added support for fetching competitors from clientparams.php

This commit is contained in:
Axel Uhl committed 2013-07-12 14:53:41 +02:00
1 parent fb5124da61
commit 5a0375e69f
16 files changed
+123 -73

No files matched your search

@@ -92,8 +92,8 @@ public class CourseUpdateTest extends AbstractTracTracLiveTest {
addListenersForStoredDataAndStartController(receivers);
Race tractracRace = getTracTracEvent().getRaceList().iterator().next();
// now we expect that there is no
assertNull(domainFactory.getExistingRaceDefinitionForRace(tractracRace));
race = domainFactory.getAndWaitForRaceDefinition(tractracRace);
assertNull(domainFactory.getExistingRaceDefinitionForRace(tractracRace.getId()));
race = domainFactory.getAndWaitForRaceDefinition(tractracRace.getId());
course = race.getCourse();
assertNotNull(course);
assertEquals(3, Util.size(course.getWaypoints()));
@@ -105,8 +105,8 @@ public abstract class OnlineTracTracBasedTest extends AbstractTracTracLiveTest {
addListenersForStoredDataAndStartController(receivers);
Race tractracRace = getTracTracEvent().getRaceList().iterator().next();
// now we expect that there is no RaceDefinition for the TracTrac race yet:
assertNull(domainFactory.getExistingRaceDefinitionForRace(tractracRace));
race = getDomainFactory().getAndWaitForRaceDefinition(tractracRace);
assertNull(domainFactory.getExistingRaceDefinitionForRace(tractracRace.getId()));
race = getDomainFactory().getAndWaitForRaceDefinition(tractracRace.getId());
assertNotNull(race);
logger.info("Waiting for stored data to be loaded for " + race.getName());
synchronized (getSemaphor()) {
@@ -105,7 +105,7 @@ public class ReceiveMarkPassingDataTest extends AbstractTracTracLiveTest {
receivers.add(r);
}
addListenersForStoredDataAndStartController(receivers);
raceDefinition = DomainFactory.INSTANCE.getAndWaitForRaceDefinition(race);
raceDefinition = DomainFactory.INSTANCE.getAndWaitForRaceDefinition(race.getId());
synchronized (semaphor) {
while (firstData[0] == null) {
try {
@@ -9,6 +9,7 @@ import org.junit.Before;
import org.junit.Test;
import com.sap.sailing.domain.common.impl.Util;
import com.sap.sailing.domain.tractracadapter.impl.ClientParamsPHP.Competitor;
import com.sap.sailing.domain.tractracadapter.impl.ClientParamsPHP.Event;
import com.sap.sailing.domain.tractracadapter.impl.ClientParamsPHP.Race;
import com.sap.sailing.domain.tractracadapter.impl.ClientParamsPHP.Route;
@@ -54,4 +55,11 @@ public class ClientParamsPHP49erFX2013Test extends AbstractClientParamsPHPTest {
assertEquals("49er European Championship 2013", event.getName());
assertEquals("event_20130703_erEuropean", event.getDB());
}
@Test
public void testCompetitors() {
Iterable<Competitor> competitors = clientParams.getCompetitors();
assertEquals(9, Util.size(competitors));
assertEquals("Nielsen", competitors.iterator().next().getName());
}
}
@@ -12,6 +12,9 @@ import java.util.List;
import java.util.UUID;
import com.maptrack.client.io.TypeController;
import com.sap.sailing.domain.base.BoatClass;
import com.sap.sailing.domain.base.Course;
@@ -88,8 +91,9 @@ public interface DomainFactory {
* Fetch a race definition previously created by a call to {@link #getOrCreateRaceDefinitionAndTrackedRace}. If no such
* race definition was created so far, the call blocks until such a definition is provided by a call to
* {@link #getOrCreateRaceDefinitionAndTrackedRace}.
* @param raceId TODO
*/
RaceDefinition getAndWaitForRaceDefinition(Race race);
RaceDefinition getAndWaitForRaceDefinition(UUID raceId);
/**
* Creates an {@link com.sap.sailing.domain.base.Regatta event} from a
@@ -179,21 +183,23 @@ public interface DomainFactory {
* resulting {@link RaceDefinition} is added to the {@link com.sap.sailing.domain.base.Regatta} to which
* <code>trackedRegatta</code> belongs (see {@link TrackedRegatta#getRegatta()}). It is added to the internal race cache.
* The corresponding {@link TrackedRace} object is also created, and the notification of threads waiting on the race
* cache such as a blocking {@link #getAndWaitForRaceDefinition(Race)} happens only <em>after</em> the tracked race
* cache such as a blocking {@link #getAndWaitForRaceDefinition(UUID)} happens only <em>after</em> the tracked race
* has been created and the {@link RaceDefinition} was
* {@link com.sap.sailing.domain.base.Regatta#addRace(RaceDefinition) added} to the domain event. This ensures that
* waiters for the {@link RaceDefinition} are guaranteed to obtain a valid, non- <code>null</code> tracked race
* already immediately after the notification was sent, and that the {@link RaceDefinition} is already
* {@link com.sap.sailing.domain.base.Regatta#getAllRaces() known} by its containing
* {@link com.sap.sailing.domain.base.Regatta}.
*
* @param raceName TODO
* @param competitors TODO
* @param boatClass TODO
* @param raceDefinitionSetToUpdate
* if not <code>null</code>, after creating the {@link TrackedRace}, the {@link RaceDefinition} is
* {@link DynamicRaceDefinitionSet#addRaceDefinition(RaceDefinition, DynamicTrackedRace) added} to that object.
*/
DynamicTrackedRace getOrCreateRaceDefinitionAndTrackedRace(TrackedRegatta trackedRegatta, Race race,
Course course, Iterable<Sideline> sidelines, WindStore windStore, long delayToLiveInMillis, long millisecondsOverWhichToAverageWind,
DynamicRaceDefinitionSet raceDefinitionSetToUpdate, URI courseDesignUpdateURI, UUID tracTracEventUuid, String tracTracUsername, String tracTracPassword);
DynamicTrackedRace getOrCreateRaceDefinitionAndTrackedRace(TrackedRegatta trackedRegatta, UUID raceId,
String raceName, Iterable<com.sap.sailing.domain.base.Competitor> competitors, BoatClass boatClass, Course course, Iterable<Sideline> sidelines,
WindStore windStore, long delayToLiveInMillis, long millisecondsOverWhichToAverageWind, DynamicRaceDefinitionSet raceDefinitionSetToUpdate, URI courseDesignUpdateURI, UUID tracTracEventUuid, String tracTracUsername, String tracTracPassword);
/**
* The record may be for a single mark or a gate. If for a gate, the
@@ -216,7 +222,7 @@ public interface DomainFactory {
/**
* Returns a {@link RaceDefinition} for the race if it already exists, <code>null</code> otherwise.
*/
RaceDefinition getExistingRaceDefinitionForRace(Race race);
RaceDefinition getExistingRaceDefinitionForRace(UUID raceId);
/**
* When a course is changed dynamically, we receive an updated list of control points that now define
@@ -234,12 +240,12 @@ public interface DomainFactory {
* <code>timeoutInMilliseconds</code> milliseconds have passed and the race definition is found not to have shown up
* until then, <code>null</code> is returned. The unblocking may be deferred even beyond
* <code>timeoutInMilliseconds</code> in case no modifications happen on the set of races cached by this factory.
*
* @param raceId TODO
* @param timeoutInMilliseconds
* passing -1 means an infinite timeout; 0 means return immediately with <code>null</code> as result if no
* race definition is found for <code>race</code>.
*/
RaceDefinition getAndWaitForRaceDefinition(Race race, long timeoutInMilliseconds);
RaceDefinition getAndWaitForRaceDefinition(UUID raceId, long timeoutInMilliseconds);
Pair<List<com.sap.sailing.domain.base.Competitor>, BoatClass> getCompetitorsAndDominantBoatClass(Race race);
@@ -40,6 +40,18 @@ public interface MetadataParser {
*/
Iterable<ControlPointMetaData> parseControlPointMetadata(TracTracControlPoint controlPoint);
Map<String, Iterable<TracTracControlPoint>> parseSidelinesFromRaceMetadata(String raceMetadataString, Iterable<? extends TracTracControlPoint> controlPoints);
/**
* Parses the race metadata for sideline information
* The sidelines of a race (course) are encoded like this:
* <pre>
* SIDELINE1=(TR-A) 3
* SIDELINE2=(TR-A) Start
* </pre>
* Each sideline is defined right now through a simple gate, but this might change in the future.
*
* @return keys are the sideline names, such as "SIDELINE1", values are the control points that form the sideline
*/
Map<String, Iterable<TracTracControlPoint>> parseSidelinesFromRaceMetadata(String raceMetadataString,
Iterable<? extends TracTracControlPoint> controlPoints);
}
@@ -156,7 +156,7 @@ public abstract class AbstractReceiverWithQueue<A, B, C> implements Runnable, Re
*/
protected DynamicTrackedRace getTrackedRace(Race race) {
DynamicTrackedRace result = null;
RaceDefinition raceDefinition = getDomainFactory().getAndWaitForRaceDefinition(race,
RaceDefinition raceDefinition = getDomainFactory().getAndWaitForRaceDefinition(race.getId(),
RaceTracker.TIMEOUT_FOR_RECEIVING_RACE_DEFINITION_IN_MILLISECONDS);
if (raceDefinition != null) {
com.sap.sailing.domain.base.Regatta domainRegatta = trackedRegatta.getRegatta();
@@ -11,6 +11,7 @@ import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;
@@ -59,7 +60,7 @@ import com.sap.sailing.domain.tractracadapter.TracTracControlPoint;
public class ClientParamsPHP {
private static final Logger logger = Logger.getLogger(ClientParamsPHP.class.getName());
private final Map<String, String> properties;
private final LinkedHashMap<String, String> properties;
/**
* Keys are UUIDs, values are property names for which this UUID was set. The values of this map can be used as
@@ -171,13 +172,6 @@ public class ClientParamsPHP {
return getProperty("Name");
}
/**
* @return the event UUID
*/
public UUID getID() {
return UUID.fromString(getProperty("ID"));
}
public TimePoint getStartTime() throws ParseException {
return getTimePoint("StartTime");
}
@@ -202,13 +196,6 @@ public class ClientParamsPHP {
return getProperty("Name");
}
/**
* @return the race UUID
*/
public UUID getID() {
return UUID.fromString(getProperty("ID"));
}
public TimePoint getStartTime() throws ParseException {
return getTimePoint("StartTime");
}
@@ -279,10 +266,40 @@ public class ClientParamsPHP {
}
}
public class BoatClass extends ObjectWithUUID {
public BoatClass(UUID uuid) {
super(uuid);
}
public String getName() {
return getProperty("Name");
}
}
public class Competitor extends ObjectWithUUID {
public Competitor(UUID uuid) {
super(uuid);
}
public String getName() {
return getProperty("Name");
}
public String getShorName() {
return getProperty("NameShort");
}
public String getColor() {
return getProperty("Color");
}
public String getNationality() {
return getProperty("Nationality");
}
public BoatClass getBoatClass() {
return new BoatClass(UUID.fromString(getProperty("ClassUUID")));
}
}
public static class Mark {
@@ -380,7 +397,7 @@ public class ClientParamsPHP {
public ClientParamsPHP(Reader r) throws IOException {
BufferedReader br = new BufferedReader(r);
properties = new HashMap<>();
properties = new LinkedHashMap<>();
propertiesByID = new HashMap<>();
String line;
while ((line = br.readLine()) != null) {
@@ -428,6 +445,16 @@ public class ClientParamsPHP {
}
return result;
}
public Iterable<Competitor> getCompetitors() {
List<Competitor> result = new ArrayList<>();
for (Map.Entry<String, String> e : properties.entrySet()) {
if (e.getKey().matches("Comp[0-9][0-9]*UUID")) {
result.add(new Competitor(UUID.fromString(e.getValue())));
}
}
return result;
}
public Race getRace() {
return new Race(UUID.fromString(properties.get("RaceID")));
@@ -104,7 +104,11 @@ public class DomainFactoryImpl implements DomainFactory {
*/
private final WeakIdentityHashMap<com.tractrac.clientmodule.Event, Regatta> weakRegattaCache = new WeakIdentityHashMap<>();
private final Map<Race, RaceDefinition> raceCache = new HashMap<Race, RaceDefinition>();
/**
* Maps from the TracTrac race UUIDs to the domain model's {@link RaceDefinition} objects that represent the race
* identified by that UUID
*/
private final Map<UUID, RaceDefinition> raceCache = new HashMap<>();
private final MetadataParser metadataParser;
@@ -263,20 +267,20 @@ public class DomainFactoryImpl implements DomainFactory {
}
@Override
public RaceDefinition getExistingRaceDefinitionForRace(Race race) {
return raceCache.get(race);
public RaceDefinition getExistingRaceDefinitionForRace(UUID raceId) {
return raceCache.get(raceId);
}
@Override
public RaceDefinition getAndWaitForRaceDefinition(Race race) {
return getAndWaitForRaceDefinition(race, -1);
public RaceDefinition getAndWaitForRaceDefinition(UUID raceId) {
return getAndWaitForRaceDefinition(raceId, -1);
}
@Override
public RaceDefinition getAndWaitForRaceDefinition(Race race, long timeoutInMilliseconds) {
public RaceDefinition getAndWaitForRaceDefinition(UUID raceId, long timeoutInMilliseconds) {
long start = System.currentTimeMillis();
synchronized (raceCache) {
RaceDefinition result = raceCache.get(race);
RaceDefinition result = raceCache.get(raceId);
boolean interrupted = false;
while ((timeoutInMilliseconds == -1 || System.currentTimeMillis()-start < timeoutInMilliseconds) && !interrupted && result == null) {
try {
@@ -288,7 +292,7 @@ public class DomainFactoryImpl implements DomainFactory {
raceCache.wait(timeToWait);
}
}
result = raceCache.get(race);
result = raceCache.get(raceId);
} catch (InterruptedException e) {
interrupted = true;
}
@@ -396,9 +400,9 @@ public class DomainFactoryImpl implements DomainFactory {
public void removeRace(com.tractrac.clientmodule.Event tractracEvent, Race tractracRace, TrackedRegattaRegistry trackedRegattaRegistry) {
RaceDefinition raceDefinition;
synchronized (raceCache) {
raceDefinition = getExistingRaceDefinitionForRace(tractracRace);
raceDefinition = getExistingRaceDefinitionForRace(tractracRace.getId());
if (raceDefinition != null) { // otherwise, this domain factory doesn't seem to know about the race
raceCache.remove(tractracRace);
raceCache.remove(tractracRace.getId());
logger.info("Removed race "+raceDefinition.getName()+" from TracTrac DomainFactoryImpl");
}
}
@@ -439,16 +443,16 @@ public class DomainFactoryImpl implements DomainFactory {
}
@Override
public DynamicTrackedRace getOrCreateRaceDefinitionAndTrackedRace(TrackedRegatta trackedRegatta,
Race race, Course course, Iterable<Sideline> sidelines, WindStore windStore, long delayToLiveInMillis, long millisecondsOverWhichToAverageWind,
DynamicRaceDefinitionSet raceDefinitionSetToUpdate, URI courseDesignUpdateURI, UUID tracTracEventUuid, String tracTracUsername, String tracTracPassword) {
public DynamicTrackedRace getOrCreateRaceDefinitionAndTrackedRace(TrackedRegatta trackedRegatta, UUID raceId,
String raceName, Iterable<Competitor> competitors, BoatClass boatClass, Course course,
Iterable<Sideline> sidelines, WindStore windStore, long delayToLiveInMillis,
long millisecondsOverWhichToAverageWind, DynamicRaceDefinitionSet raceDefinitionSetToUpdate,
URI courseDesignUpdateURI, UUID tracTracEventUuid, String tracTracUsername, String tracTracPassword) {
synchronized (raceCache) {
RaceDefinition raceDefinition = raceCache.get(race);
RaceDefinition raceDefinition = raceCache.get(raceId);
if (raceDefinition == null) {
Pair<List<Competitor>, BoatClass> competitorsAndDominantBoatClass = getCompetitorsAndDominantBoatClass(race);
logger.info("Creating RaceDefinitionImpl for race "+race.getName());
raceDefinition = new RaceDefinitionImpl(race.getName(), course, competitorsAndDominantBoatClass.getB(),
competitorsAndDominantBoatClass.getA(), getRaceID(race));
logger.info("Creating RaceDefinitionImpl for race "+raceName);
raceDefinition = new RaceDefinitionImpl(raceName, course, boatClass, competitors, raceId);
// add to existing regatta only if boat class matches
if (raceDefinition.getBoatClass() == trackedRegatta.getRegatta().getBoatClass()) {
trackedRegatta.getRegatta().addRace(raceDefinition);
@@ -462,7 +466,7 @@ public class DomainFactoryImpl implements DomainFactory {
trackedRace.addCourseDesignChangedListener(courseDesignHandler);
synchronized (raceCache) {
raceCache.put(race, raceDefinition);
raceCache.put(raceId, raceDefinition);
raceCache.notifyAll();
}
return trackedRace;
@@ -473,7 +477,7 @@ public class DomainFactoryImpl implements DomainFactory {
return null;
}
} else {
throw new RuntimeException("Race "+race.getName()+" already exists");
throw new RuntimeException("Race "+raceName+" already exists");
}
}
}
@@ -177,15 +177,6 @@ public class MetadataParserImpl implements MetadataParser {
return result;
}
/**
* Parses the race metadata for sideline information
* The sidelines of a race (course) are encoded like this...
* <pre>
* SIDELINE1=(TR-A) 3
* SIDELINE2=(TR-A) Start
* </pre>
* Each sideline is defined right now through a simple gate, but this might change in the future
*/
@Override
public Map<String, Iterable<TracTracControlPoint>> parseSidelinesFromRaceMetadata(String raceMetadataString,
Iterable<? extends TracTracControlPoint> controlPoints) {
@@ -10,6 +10,8 @@ import java.util.logging.Level;
import java.util.logging.Logger;
import com.maptrack.client.io.TypeController;
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;
import com.sap.sailing.domain.base.RaceDefinition;
@@ -124,7 +126,7 @@ public class RaceCourseReceiver extends AbstractReceiverWithQueue<Route, RouteDa
}
}
RaceDefinition existingRaceDefinitionForRace = getDomainFactory().getExistingRaceDefinitionForRace(event.getC());
RaceDefinition existingRaceDefinitionForRace = getDomainFactory().getExistingRaceDefinitionForRace(event.getC().getId());
if (existingRaceDefinitionForRace != null) {
logger.log(Level.INFO, "Received course update for existing race "+event.getC().getName()+": "+
event.getB().getPoints());
@@ -142,9 +144,11 @@ public class RaceCourseReceiver extends AbstractReceiverWithQueue<Route, RouteDa
} else {
logger.log(Level.INFO, "Received course for non-existing race "+event.getC().getName()+". Creating RaceDefinition.");
// create race definition and add to event
Pair<List<Competitor>, BoatClass> competitorsAndDominantBoatClass = getDomainFactory().getCompetitorsAndDominantBoatClass(race);
DynamicTrackedRace trackedRace = getDomainFactory().getOrCreateRaceDefinitionAndTrackedRace(
getTrackedRegatta(), event.getC(), course, sidelines, windStore, delayToLiveInMillis,
millisecondsOverWhichToAverageWind, raceDefinitionSetToUpdate, courseDesignUpdateURI,
getTrackedRegatta(), event.getC().getId(), race.getName(), competitorsAndDominantBoatClass.getA(),
competitorsAndDominantBoatClass.getB(), course, sidelines, windStore, delayToLiveInMillis,
millisecondsOverWhichToAverageWind, raceDefinitionSetToUpdate, courseDesignUpdateURI,
getTracTracEvent().getId(), tracTracUsername, tracTracPassword);
if (getSimulator() != null) {
getSimulator().setTrackedRace(trackedRace);
@@ -33,7 +33,7 @@ public class RaceHandleImpl implements RacesHandle {
public Set<RaceDefinition> getRaces() {
Set<RaceDefinition> result = new HashSet<RaceDefinition>();
for (Race r : tractracEvent.getRaceList()) {
result.add(domainFactory.getAndWaitForRaceDefinition(r));
result.add(domainFactory.getAndWaitForRaceDefinition(r.getId()));
}
return result;
}
@@ -51,8 +51,8 @@ public class RaceHandleImpl implements RacesHandle {
@Override
public Set<RaceDefinition> getRaces(long timeoutInMilliseconds) {
Set<RaceDefinition> result = new HashSet<RaceDefinition>();
for (Race r : tractracEvent.getRaceList()) {
result.add(domainFactory.getAndWaitForRaceDefinition(r, timeoutInMilliseconds));
for (Race race : tractracEvent.getRaceList()) {
result.add(domainFactory.getAndWaitForRaceDefinition(race.getId(), timeoutInMilliseconds));
}
return result;
}
@@ -272,8 +272,8 @@ public class TracTracRaceTrackerImpl extends AbstractRaceTrackerImpl implements
try {
clientParams = new ClientParamsPHP(new InputStreamReader(paramURL.openStream()));
List<com.sap.sailing.domain.base.ControlPoint> newCourseControlPoints = new ArrayList<>();
List<Pair<com.sap.sailing.domain.base.ControlPoint, NauticalSide>> newCourseControlPointsWithPassingSide = new ArrayList<>();
final List<? extends TracTracControlPoint> newTracTracControlPoints = clientParams.getRace().getDefaultRoute().getControlPoints();
List<Pair<com.sap.sailing.domain.base.ControlPoint, NauticalSide>> newCourseControlPointsWithPassingSide = new ArrayList<>();
Map<Integer, NauticalSide> passingSideData = domainFactory.getMetadataParser().parsePassingSideData(
clientParams.getRace().getDefaultRoute().getMetadata(), newTracTracControlPoints);
int i = 1;
@@ -1,9 +1,7 @@
package com.sap.sailing.domain.base;
import java.util.List;
import java.util.concurrent.locks.ReentrantReadWriteLock;
import com.sap.sailing.domain.common.NauticalSide;
import com.sap.sailing.domain.common.impl.Util.Pair;
@@ -42,5 +40,5 @@ public interface Course extends CourseBase {
* to the registered {@link CourseListener}s as if {@link #addWaypoint(int, Waypoint)} and {@link #removeWaypoint(int)}
* had been used.
*/
void update(List<Pair<ControlPoint, NauticalSide>> newControlPoints, DomainFactory baseDomainFactory) throws PatchFailedException;
void update(Iterable<Pair<ControlPoint, NauticalSide>> newControlPoints, DomainFactory baseDomainFactory) throws PatchFailedException;
}
@@ -380,7 +380,7 @@ public class CourseImpl extends NamedImpl implements Course {
}
@Override
public void update(List<Pair<ControlPoint, NauticalSide>> newControlPoints, DomainFactory baseDomainFactory) throws PatchFailedException {
public void update(Iterable<Pair<ControlPoint, NauticalSide>> newControlPoints, DomainFactory baseDomainFactory) throws PatchFailedException {
Patch<Waypoint> patch = null;
synchronized (updateMonitor) {
lockForRead();
@@ -85,7 +85,7 @@ public class TestStoringAndRetrievingWindTracksTest extends AbstractTracTracLive
}
}, /* trackedRegattaRegistry */ null, /*courseDesignUpdateURI*/ null, /*tracTracUsername*/ null, /*tracTracPassword*/ null, ReceiverType.RACECOURSE);
addListenersForStoredDataAndStartController(typeControllers);
RaceDefinition race = domainFactory.getAndWaitForRaceDefinition(getTracTracEvent().getRaceList().iterator().next());
RaceDefinition race = domainFactory.getAndWaitForRaceDefinition(getTracTracEvent().getRaceList().iterator().next().getId());
DynamicTrackedRace trackedRace = trackedRegatta.createTrackedRace(race, Collections.<Sideline> emptyList(), EmptyWindStore.INSTANCE,
/* delayToLiveInMillis */ 0l, /* millisecondsOverWhichToAverageWind */ 30000, /* millisecondsOverWhichToAverageSpeed */ 10000, new DynamicRaceDefinitionSet() {
@Override