added RaceHandle return to addRace so clients can identify what they are tracking

Started working on a server test that works towards starting and stopping trackers for the
same race / event, asserting that tracking structures are cleared in between
This commit is contained in:
Axel Uhl committed 2011-06-13 17:48:21 +02:00
1 parent 5354ba7e3f
commit 1e47a20edc
18 files changed
+222 -29

No files matched your search

@@ -0,0 +1,3 @@
#Fri Jun 10 21:39:55 CEST 2011
eclipse.preferences.version=1
encoding//src/com/sap/sailing/domain/test/WindTest.java=UTF-8
@@ -81,7 +81,10 @@ public class CourseUpdateTest extends AbstractTracTracLiveTest {
}
});
addListenersForStoredDataAndStartController(receivers);
race = domainFactory.getRaceDefinition(getEvent().getRaceList().iterator().next());
Race tractracRace = getEvent().getRaceList().iterator().next();
// now we expect that there is no
assertNull(domainFactory.getExistingRaceDefinitionForRace(tractracRace));
race = domainFactory.getRaceDefinition(tractracRace);
course = race.getCourse();
assertNotNull(course);
assertEquals(3, Util.size(course.getWaypoints()));
@@ -91,6 +94,11 @@ public class CourseUpdateTest extends AbstractTracTracLiveTest {
assertEquals("top", course.getLegs().get(1).getFrom().getName());
}
private void assertNull(RaceDefinition existingRaceDefinitionForRace) {
// TODO Auto-generated method stub
}
/**
* Asserts that the race course's legs have corresponding {@link TrackedLeg}s and the {@link TrackedLeg}s have
* {@link TrackedLegOfCompetitor} for each of the race's competitors.
@@ -117,6 +117,11 @@ public interface DomainFactory {
DynamicTrackedRace trackRace(TrackedEvent trackedEvent, RaceDefinition raceDefinition,
WindStore windStore, long millisecondsOverWhichToAverageWind, long millisecondsOverWhichToAverageSpeed, Event tractracEvent);
/**
* Non-blocking call that returns <code>null</code> if the {@link RaceDefinition} for the TracTrac Event
* hasn't been created yet, e.g., because the course definition hasn't been received yet or the listener
* for receiving course information hasn't been registered (yet).
*/
RaceDefinition getRace(Event tractracEvent);
JSONService parseJSONURL(URL jsonURL) throws IOException, ParseException, org.json.simple.parser.ParseException;
@@ -11,6 +11,13 @@ public interface RaceTracker {
com.sap.sailing.domain.base.Event getEvent();
/**
* Non-blocking call that returns <code>null</code> if the {@link RaceDefinition} for the TracTrac Event
* hasn't been created yet, e.g., because the course definition hasn't been received yet or the listener
* for receiving course information hasn't been registered (yet).
*/
RaceDefinition getRace();
RaceHandle getRaceHandle();
}
@@ -18,6 +18,7 @@ import com.sap.sailing.domain.tracking.TrackedRace;
import com.sap.sailing.domain.tracking.WindStore;
import com.sap.sailing.domain.tracking.impl.EmptyWindStore;
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.tractrac.clientmodule.Event;
@@ -31,10 +32,15 @@ public class RaceTrackerImpl implements Listener, RaceTracker {
private final Thread ioThread;
private final DataController controller;
private final Set<Receiver> receivers;
private final DomainFactory domainFactory;
/**
* Creates a race tracked for the specified URL/URIs and starts receiving all available existing and future push
* data from there. Receiving continues until {@link #stop()} is called.
* <p>
*
* A race tracker uses the <code>paramURL</code> for the TracTrac Java client to register for push data about one
* race. The {@link RaceDefinition} for that race, however, cannot be created until the {@link Course} has been
* race. The {@link RaceDefinition} for that race, however, isn't created until the {@link Course} has been
* received. Therefore, the {@link RaceCourseReceiver} will create the {@link RaceDefinition} and will add it to the
* {@link com.sap.sailing.domain.base.Event}.
* <p>
@@ -45,16 +51,14 @@ public class RaceTrackerImpl implements Listener, RaceTracker {
* {@link Event} as argument that is used for its tracking.
* <p>
*
* When {@link #getRace} is called on this object before the {@link RaceCourseReceiver} has created the
* {@link RaceDefinition}, the call will block until this has happened.
*
* @param windStore
* Provides the capability to obtain the {@link WindTrack}s for the different wind sources.
* A trivial implementation is {@link EmptyWindStore} which simply provides new, empty tracks.
* This is always available but loses track of the wind, e.g., during server restarts.
* Provides the capability to obtain the {@link WindTrack}s for the different wind sources. A trivial
* implementation is {@link EmptyWindStore} which simply provides new, empty tracks. This is always
* available but loses track of the wind, e.g., during server restarts.
*/
protected RaceTrackerImpl(DomainFactory domainFactory, URL paramURL, URI liveURI, URI storedURI, WindStore windStore)
throws URISyntaxException, MalformedURLException, FileNotFoundException {
this.domainFactory = domainFactory;
// Read event data from configuration file
tractracEvent = KeyValue.setup(paramURL);
@@ -81,9 +85,14 @@ public class RaceTrackerImpl implements Listener, RaceTracker {
addListenersForStoredDataAndStartController(typeControllers);
}
@Override
public RaceHandle getRaceHandle() {
return new RaceHandleImpl(domainFactory, tractracEvent);
}
@Override
public RaceDefinition getRace() {
return DomainFactory.INSTANCE.getRace(tractracEvent);
return domainFactory.getRace(tractracEvent);
}
protected void addListenersForStoredDataAndStartController(Iterable<TypeController> listenersForStoredData) {
+7
View File
@@ -0,0 +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.6"/>
<classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/>
<classpathentry kind="src" path="src"/>
<classpathentry kind="output" path="bin"/>
</classpath>
+1
View File
@@ -0,0 +1 @@
/bin
+28
View File
@@ -0,0 +1,28 @@
<?xml version="1.0" encoding="UTF-8"?>
<projectDescription>
<name>com.sap.sailing.server.test</name>
<comment></comment>
<projects>
</projects>
<buildSpec>
<buildCommand>
<name>org.eclipse.jdt.core.javabuilder</name>
<arguments>
</arguments>
</buildCommand>
<buildCommand>
<name>org.eclipse.pde.ManifestBuilder</name>
<arguments>
</arguments>
</buildCommand>
<buildCommand>
<name>org.eclipse.pde.SchemaBuilder</name>
<arguments>
</arguments>
</buildCommand>
</buildSpec>
<natures>
<nature>org.eclipse.pde.PluginNature</nature>
<nature>org.eclipse.jdt.core.javanature</nature>
</natures>
</projectDescription>
@@ -0,0 +1,8 @@
#Mon Jun 13 17:15:33 CEST 2011
eclipse.preferences.version=1
org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6
org.eclipse.jdt.core.compiler.compliance=1.6
org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
org.eclipse.jdt.core.compiler.source=1.6
@@ -0,0 +1,4 @@
#Mon Jun 13 17:15:33 CEST 2011
eclipse.preferences.version=1
pluginProject.extensions=false
resolve.requirebundle=false
+11
View File
@@ -0,0 +1,11 @@
Manifest-Version: 1.0
Bundle-ManifestVersion: 2
Bundle-Name: Test
Bundle-SymbolicName: com.sap.sailing.server.test
Bundle-Version: 1.0.0.qualifier
Bundle-Vendor: SAP
Bundle-RequiredExecutionEnvironment: JavaSE-1.6
Require-Bundle: com.sap.sailing.server,
com.sap.sailing.domain,
com.sap.sailing.domain.tractracadapter,
org.junit4
+4
View File
@@ -0,0 +1,4 @@
source.. = src/
output.. = bin/
bin.includes = META-INF/,\
.
+14
View File
@@ -0,0 +1,14 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<modelVersion>4.0.0</modelVersion>
<parent>
<artifactId>root</artifactId>
<groupId>com.sap.sailing</groupId>
<version>0.0.1-SNAPSHOT</version>
</parent>
<groupId>com.sap.sailing</groupId>
<artifactId>com.sap.sailing.server.test</artifactId>
<version>1.0.0-SNAPSHOT</version>
<packaging>eclipse-test-plugin</packaging>
</project>
@@ -0,0 +1,57 @@
package com.sap.sailing.server.test;
import static org.junit.Assert.assertNotNull;
import java.io.FileNotFoundException;
import java.net.MalformedURLException;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import org.junit.Before;
import org.junit.Test;
import com.sap.sailing.domain.base.RaceDefinition;
import com.sap.sailing.domain.tracking.impl.EmptyWindStore;
import com.sap.sailing.domain.tractracadapter.DomainFactory;
import com.sap.sailing.domain.tractracadapter.RaceHandle;
import com.sap.sailing.server.RacingEventServiceImpl;
public class RaceTrackerTest {
private final URL paramUrl;
private final URI liveUri;
private final URI storedUri;
private RacingEventServiceImpl service;
private DomainFactory domainFactory;
private RaceHandle raceHandle;
public RaceTrackerTest() throws MalformedURLException, URISyntaxException {
// for live simulation:
// paramUrl = new URL("http://sapsimulation.tracdev.dk/simulateconf/j80race12.txt");
// liveUri = new URI("tcp://sapsimulation.tracdev.dk:4420"); // or with tunneling: tcp://localhost:4420
// storedUri = new URI("tcp://sapsimulation.tracdev.dk:4421"); // or with tunneling: tcp://localhost:4421
// for stored race, non-real-time simulation:
paramUrl = new URL("http://germanmaster.traclive.dk/events/event_20110505_SailingTea/clientparams.php?event=event_20110505_SailingTea&race=bd8c778e-7c65-11e0-8236-406186cbf87c");
// tunneled:
//liveUri = new URI("tcp://localhost:4412");
//storedUri = new URI("tcp://localhost:4413");
//no tunnel:
liveUri = new URI("tcp://germanmaster.traclive.dk:4400");
storedUri = new URI("tcp://germanmaster.traclive.dk:4401");
}
@Before
public void setUp() throws MalformedURLException, FileNotFoundException, URISyntaxException {
service = new RacingEventServiceImpl();
raceHandle = service.addRace(paramUrl, liveUri, storedUri, EmptyWindStore.INSTANCE);
domainFactory = service.getDomainFactory();
}
@Test
public void testInitialization() {
RaceDefinition race = raceHandle.getRace();
assertNotNull(race);
}
}
@@ -12,11 +12,32 @@ import java.text.ParseException;
import com.sap.sailing.declination.DeclinationService;
import com.sap.sailing.domain.base.Event;
import com.sap.sailing.domain.base.RaceDefinition;
import com.sap.sailing.domain.tracking.TrackedEvent;
import com.sap.sailing.domain.tracking.TrackedRace;
import com.sap.sailing.domain.tracking.WindStore;
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.util.Util.Triple;
/**
* An OSGi service that can be used to track boat races using a TracTrac connector that pushes
* live GPS boat location, waypoint, coarse and mark passing data.<p>
*
* If a race/event is already being tracked, another {@link #addRace(URL, URI, URI, WindStore)} or
* {@link #addEvent(URL, URI, URI, WindStore)} call will have no effect, even if a different
* {@link WindStore} is requested.<p>
*
* TODO When the tracking of a race/event is {@link #stopTracking(Event, RaceDefinition) stopped}, the next
* time it's started to be tracked, a new {@link TrackedRace} at least will be constructed. This also
* means that when a {@link TrackedEvent} exists that still holds other {@link TrackedRace}s, the
* no longer tracked {@link TrackedRace} will be removed from the {@link TrackedEvent}.
* corresponding information is removed also from the {@link DomainFactory}'s caches to ensure that
* clean, fresh data is received should another tracking request be issued later.
*
* @author Axel Uhl (d043530)
*
*/
public interface RacingEventService {
Iterable<Event> getAllEvents();
@@ -25,33 +46,31 @@ public interface RacingEventService {
DomainFactory getDomainFactory();
/**
* Defines the event and for each race listed in the JSON document creates a {@link RaceTracker} that
* tracks 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 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
* JSON array named "races" which tells ID and replay URL for the race. From those replay URLs the
* paramURL for the Java client can be derived.
* @param windStore TODO
*/
void addEvent(URL jsonURL, URI liveURI, URI storedURI, WindStore windStore) throws MalformedURLException, FileNotFoundException,
Event addEvent(URL jsonURL, URI liveURI, URI storedURI, WindStore windStore) throws MalformedURLException, FileNotFoundException,
URISyntaxException, IOException, ParseException, org.json.simple.parser.ParseException;
/**
* Adds a single race tracker, 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>
* 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.
* @param windStore TODO
*/
void addRace(URL paramURL, URI liveURI, URI storedURI, WindStore windStore) throws MalformedURLException, FileNotFoundException,
RaceHandle addRace(URL paramURL, URI liveURI, URI storedURI, WindStore windStore) throws MalformedURLException, FileNotFoundException,
URISyntaxException;
/**
@@ -25,6 +25,7 @@ import com.sap.sailing.domain.tracking.DynamicTrackedRace;
import com.sap.sailing.domain.tracking.WindStore;
import com.sap.sailing.domain.tractracadapter.DomainFactory;
import com.sap.sailing.domain.tractracadapter.JSONService;
import com.sap.sailing.domain.tractracadapter.RaceHandle;
import com.sap.sailing.domain.tractracadapter.RaceRecord;
import com.sap.sailing.domain.tractracadapter.RaceTracker;
import com.sap.sailing.expeditionconnector.UDPExpeditionReceiver;
@@ -71,16 +72,18 @@ public class RacingEventServiceImpl implements RacingEventService {
}
@Override
public void addEvent(URL jsonURL, URI liveURI, URI storedURI, WindStore windStore) throws URISyntaxException, IOException, ParseException, org.json.simple.parser.ParseException {
public Event addEvent(URL jsonURL, URI liveURI, URI storedURI, WindStore windStore) throws URISyntaxException, IOException, ParseException, org.json.simple.parser.ParseException {
JSONService jsonService = getDomainFactory().parseJSONURL(jsonURL);
Event event = null;
for (RaceRecord rr : jsonService.getRaceRecords()) {
URL paramURL = rr.getParamURL();
addRace(paramURL, liveURI, storedURI, windStore);
event = addRace(paramURL, liveURI, storedURI, windStore).getEvent();
}
return event;
}
@Override
public void addRace(URL paramURL, URI liveURI, URI storedURI, WindStore windStore) throws MalformedURLException, FileNotFoundException,
public RaceHandle addRace(URL paramURL, URI liveURI, URI storedURI, WindStore windStore) throws MalformedURLException, FileNotFoundException,
URISyntaxException {
RaceTracker tracker = getDomainFactory().createRaceTracker(paramURL, liveURI, storedURI, windStore);
Set<RaceTracker> trackers = raceTrackers.get(tracker.getEvent());
@@ -98,6 +101,7 @@ public class RacingEventServiceImpl implements RacingEventService {
} else {
eventsByName.put(eventName, tracker.getEvent());
}
return tracker.getRaceHandle();
}
@Override
@@ -128,6 +132,7 @@ public class RacingEventServiceImpl implements RacingEventService {
}
}
}
// FIXME remove TrackedRace from TrackedEvent
// if the last tracked race was removed, remove the entire event
if (raceTrackers.get(event).isEmpty()) {
stopTracking(event);
+1
View File
@@ -18,6 +18,7 @@
<module>com.sap.sailing.expeditionconnector</module>
<module>com.sap.sailing.expeditionconnector.test</module>
<module>com.sap.sailing.server</module>
<module>com.sap.sailing.server.test</module>
<module>com.sap.sailing.mongodb</module>
<module>com.sap.sailing.mongodb.test</module>
<module>com.tractrac.clientmodule</module>