factored out the metadata parsing logic into MetadataParser[Impl]

This commit is contained in:
Axel Uhl committed 2013-07-12 11:49:59 +02:00
1 parent 90200e2760
commit c1ec12b4e3
6 files changed
+261 -114

No files matched your search

@@ -264,4 +264,6 @@ public interface DomainFactory {
JSONService parseJSONURLForOneRaceRecord(URL jsonURL, String raceId, boolean loadClientParams) throws IOException, ParseException, org.json.simple.parser.ParseException, URISyntaxException;
MetadataParser getMetadataParser();
}
@@ -0,0 +1,44 @@
package com.sap.sailing.domain.tractracadapter;
import java.io.Serializable;
import java.util.List;
import java.util.Map;
import com.sap.sailing.domain.common.MarkType;
import com.sap.sailing.domain.common.Named;
import com.sap.sailing.domain.common.NauticalSide;
import com.sap.sailing.domain.tractracadapter.impl.ClientParamsPHP;
import com.sap.sailing.domain.tractracadapter.impl.RaceCourseReceiver;
/**
* TracTrac objects can be augmented by what TracTrac calls a "DataSheet." These optional data sheets can provide
* meta data about the object to which they belong. For example, a course's meta data can provide the passing
* sides for each waypoint in the list. The race can provide a definition of side lines in its meta data. And a
* control point can define its shape and color.<p>
*
* This class encapsulates the patterns and procedures by which the additional data is extracted from the
* respective TracTrac data. It can be used for both, clientparams.php or TTCM based data.
*
* @see ClientParamsPHP
* @see RaceCourseReceiver
*
* @author Axel Uhl (d043530)
*
*/
public interface MetadataParser {
public interface ControlPointMetaData extends Named {
MarkType getType();
String getColor();
String getShape();
String getPattern();
Serializable getId();
}
Map<Integer, NauticalSide> parsePassingSideData(String routeMetadataString, List<? extends TracTracControlPoint> controlPoints);
/**
* Returns as many metadata objects as there are marks in the control point (two for a gate, one otherwise)
*/
Iterable<ControlPointMetaData> parseControlPointMetadata(TracTracControlPoint controlPoint);
}
@@ -3,7 +3,6 @@ package com.sap.sailing.domain.tractracadapter.impl;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.Serializable;
import java.io.StringReader;
import java.net.MalformedURLException;
import java.net.URI;
import java.net.URISyntaxException;
@@ -11,12 +10,10 @@ import java.net.URL;
import java.text.ParseException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.UUID;
import java.util.logging.Level;
import java.util.logging.Logger;
@@ -43,7 +40,6 @@ import com.sap.sailing.domain.base.impl.RaceDefinitionImpl;
import com.sap.sailing.domain.base.impl.RegattaImpl;
import com.sap.sailing.domain.base.impl.SidelineImpl;
import com.sap.sailing.domain.base.impl.TeamImpl;
import com.sap.sailing.domain.common.MarkType;
import com.sap.sailing.domain.common.NauticalSide;
import com.sap.sailing.domain.common.Position;
import com.sap.sailing.domain.common.ScoringSchemeType;
@@ -67,6 +63,8 @@ import com.sap.sailing.domain.tracking.WindTrack;
import com.sap.sailing.domain.tracking.impl.GPSFixMovingImpl;
import com.sap.sailing.domain.tractracadapter.DomainFactory;
import com.sap.sailing.domain.tractracadapter.JSONService;
import com.sap.sailing.domain.tractracadapter.MetadataParser;
import com.sap.sailing.domain.tractracadapter.MetadataParser.ControlPointMetaData;
import com.sap.sailing.domain.tractracadapter.Receiver;
import com.sap.sailing.domain.tractracadapter.ReceiverType;
import com.sap.sailing.domain.tractracadapter.TracTracConfiguration;
@@ -107,11 +105,19 @@ 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>();
private final MetadataParser metadataParser;
public DomainFactoryImpl(com.sap.sailing.domain.base.DomainFactory baseDomainFactory) {
this.baseDomainFactory = baseDomainFactory;
this.metadataParser = new MetadataParserImpl();
}
@Override
public MetadataParser getMetadataParser() {
return metadataParser;
}
@Override
public com.sap.sailing.domain.base.DomainFactory getBaseDomainFactory() {
return baseDomainFactory;
@@ -149,39 +155,22 @@ public class DomainFactoryImpl implements DomainFactory {
synchronized (controlPointCache) {
com.sap.sailing.domain.base.ControlPoint domainControlPoint = controlPointCache.get(controlPoint);
if (domainControlPoint == null) {
String controlPointName = controlPoint.getName();
final String controlPointMetadataString = controlPoint.getMetadata();
Map<String, String> controlPointMetadata;
if (controlPointMetadataString == null) {
controlPointMetadata = Collections.emptyMap();
} else {
controlPointMetadata = parseControlPointMetadata(controlPointMetadataString);
final Iterable<MetadataParser.ControlPointMetaData> controlPointMetadata = getMetadataParser().parseControlPointMetadata(controlPoint);
List<Mark> marks = new ArrayList<Mark>();
for (ControlPointMetaData markMetadata : controlPointMetadata) {
Mark mark = baseDomainFactory.getOrCreateMark(markMetadata.getId(), markMetadata.getName(),
markMetadata.getType(), markMetadata.getColor(), markMetadata.getShape(),
markMetadata.getPattern());
marks.add(mark);
}
if (controlPoint.getHasTwoPoints()) {
// it's a gate
MarkType type1 = resolveMarkTypeFromMetadata(controlPointMetadata, "P1.Type");
MarkType type2 = resolveMarkTypeFromMetadata(controlPointMetadata, "P2.Type");
String color1 = controlPointMetadata.get("P1.Color");
String color2 = controlPointMetadata.get("P2.Color");
String shape1 = controlPointMetadata.get("P1.Shape");
String shape2 = controlPointMetadata.get("P2.Shape");
String pattern1 = controlPointMetadata.get("P1.Pattern");
String pattern2 = controlPointMetadata.get("P2.Pattern");
String mark1UUID = controlPointMetadata.get("P1.UUID");
String mark2UUID = controlPointMetadata.get("P2.UUID");
final String name1 = controlPointName + " (1)";
final Serializable id1 = mark1UUID == null ? name1 : UUID.fromString(mark1UUID);
Mark mark1 = baseDomainFactory.getOrCreateMark(id1, name1, type1, color1, shape1, pattern1);
final String name2 = controlPointName + " (2)";
final Serializable id2 = mark2UUID == null ? name2 : UUID.fromString(mark2UUID);
Mark mark2 = baseDomainFactory.getOrCreateMark(id2, name2, type2, color2, shape2, pattern2);
domainControlPoint = baseDomainFactory.createGate(controlPoint.getId(), mark1, mark2, controlPointName);
Iterator<Mark> markIter = marks.iterator();
Mark mark1 = markIter.next();
Mark mark2 = markIter.next();
domainControlPoint = baseDomainFactory.createGate(controlPoint.getId(), mark1, mark2, controlPoint.getName());
} else {
MarkType type = resolveMarkTypeFromMetadata(controlPointMetadata, "Type");
String color = controlPointMetadata.get("Color");
String shape = controlPointMetadata.get("Shape");
String pattern = controlPointMetadata.get("Pattern");
Mark mark = baseDomainFactory.getOrCreateMark(controlPoint.getId(), controlPointName, type, color, shape, pattern);
Mark mark = marks.iterator().next();
domainControlPoint = mark;
}
controlPointCache.put(controlPoint, domainControlPoint);
@@ -190,33 +179,6 @@ public class DomainFactoryImpl implements DomainFactory {
}
}
private MarkType resolveMarkTypeFromMetadata(Map<String, String> controlPointMetadata, String typePropertyName) {
MarkType result = MarkType.BUOY;
String markType = controlPointMetadata.get(typePropertyName);
if(markType != null && !markType.isEmpty()) {
for(MarkType m: MarkType.values()) {
if(m.name().equalsIgnoreCase(markType)) {
result = m;
break;
}
}
}
return result;
}
@SuppressWarnings({ "rawtypes", "unchecked" })
private Map<String, String> parseControlPointMetadata(String controlPointMetadata) {
Map<String, String> metadataMap = new HashMap<String, String>();
try {
Properties p = new Properties();
p.load(new StringReader(controlPointMetadata));
metadataMap = new HashMap<String, String>((Map) p);
} catch (IOException e) {
// do nothing
}
return metadataMap;
}
@Override
public Course createCourse(String name, Iterable<Pair<TracTracControlPoint, NauticalSide>> controlPoints) {
List<Waypoint> waypointList = new ArrayList<Waypoint>();
@@ -0,0 +1,176 @@
package com.sap.sailing.domain.tractracadapter.impl;
import java.io.IOException;
import java.io.Serializable;
import java.io.StringReader;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.UUID;
import com.sap.sailing.domain.common.MarkType;
import com.sap.sailing.domain.common.NauticalSide;
import com.sap.sailing.domain.common.impl.NamedImpl;
import com.sap.sailing.domain.tractracadapter.MetadataParser;
import com.sap.sailing.domain.tractracadapter.TracTracControlPoint;
/**
* TracTrac objects can be augmented by what TracTrac calls a "DataSheet." These optional data sheets can provide
* meta data about the object to which they belong. For example, a course's meta data can provide the passing
* sides for each waypoint in the list. The race can provide a definition of side lines in its meta data. And a
* control point can define its shape and color.<p>
*
* This class encapsulates the patterns and procedures by which the additional data is extracted from the
* respective TracTrac data. It can be used for both, clientparams.php or TTCM based data.
*
* @see ClientParamsPHP
* @see RaceCourseReceiver
*
* @author Axel Uhl (d043530)
*
*/
public class MetadataParserImpl implements MetadataParser {
private class ControlPointMetaDataImpl extends NamedImpl implements ControlPointMetaData {
private static final long serialVersionUID = 1L;
private final MarkType type;
private final String color;
private final String shape;
private final String pattern;
private final Serializable id;
public ControlPointMetaDataImpl(String name, MarkType type, String color, String shape, String pattern, Serializable id) {
super(name);
this.type = type;
this.color = color;
this.shape = shape;
this.pattern = pattern;
this.id = id;
}
@Override
public MarkType getType() {
return type;
}
@Override
public String getColor() {
return color;
}
@Override
public String getShape() {
return shape;
}
@Override
public String getPattern() {
return pattern;
}
@Override
public Serializable getId() {
return id;
}
}
/**
* Parses the route metadata for additional course information
* The 'passing side' for each course waypoint is encoded like this...
* Seq.1=GATE
* Seq.2=PORT
* Seq.3=GATE
* Seq.4=STARBOARD
*/
@Override
public Map<Integer, NauticalSide> parsePassingSideData(String routeMetadataString, List<? extends TracTracControlPoint> controlPoints) {
Map<Integer, NauticalSide> result = new HashMap<Integer, NauticalSide>();
int controlPointsCount = controlPoints.size();
if(routeMetadataString != null) {
Map<String, String> routeMetadata = parseMetadata(routeMetadataString);
for(int i = 1; i <= controlPointsCount; i++) {
String seqValue = routeMetadata.get("Seq." + i);
TracTracControlPoint controlPoint = controlPoints.get(i-1);
if(!controlPoint.getHasTwoPoints() && seqValue != null) {
if("PORT".equalsIgnoreCase(seqValue)) {
result.put(i, NauticalSide.PORT);
} else if("STARBOARD".equalsIgnoreCase(seqValue)) {
result.put(i, NauticalSide.STARBOARD);
}
}
}
}
return result;
}
@SuppressWarnings({ "rawtypes", "unchecked" })
private Map<String, String> parseMetadata(String metadata) {
Map<String, String> metadataMap = new HashMap<String, String>();
try {
Properties p = new Properties();
p.load(new StringReader(metadata));
metadataMap = new HashMap<String, String>((Map) p);
} catch (IOException e) {
// do nothing
}
return metadataMap;
}
@Override
public Iterable<ControlPointMetaData> parseControlPointMetadata(TracTracControlPoint controlPoint) {
final Iterable<ControlPointMetaData> result;
final String controlPointMetadataString = controlPoint.getMetadata();
final String controlPointName = controlPoint.getName();
final Map<String, String> controlPointMetadata;
if (controlPointMetadataString == null) {
controlPointMetadata = Collections.emptyMap();
} else {
controlPointMetadata = parseMetadata(controlPointMetadataString);
}
if (controlPoint.getHasTwoPoints()) {
// it's a gate
MarkType type1 = resolveMarkTypeFromMetadata(controlPointMetadata, "P1.Type");
MarkType type2 = resolveMarkTypeFromMetadata(controlPointMetadata, "P2.Type");
String color1 = controlPointMetadata.get("P1.Color");
String color2 = controlPointMetadata.get("P2.Color");
String shape1 = controlPointMetadata.get("P1.Shape");
String shape2 = controlPointMetadata.get("P2.Shape");
String pattern1 = controlPointMetadata.get("P1.Pattern");
String pattern2 = controlPointMetadata.get("P2.Pattern");
String mark1UUID = controlPointMetadata.get("P1.UUID");
String mark2UUID = controlPointMetadata.get("P2.UUID");
final String name1 = controlPointName + " (1)";
final Serializable id1 = mark1UUID == null ? name1 : UUID.fromString(mark1UUID);
ControlPointMetaData mark1Metadata = new ControlPointMetaDataImpl(name1, type1, color1, shape1, pattern1, id1);
final String name2 = controlPointName + " (2)";
final Serializable id2 = mark2UUID == null ? name2 : UUID.fromString(mark2UUID);
ControlPointMetaData mark2Metadata = new ControlPointMetaDataImpl(name2, type2, color2, shape2, pattern2, id2);
result = Arrays.asList(new ControlPointMetaData[] { mark1Metadata, mark2Metadata });
} else {
MarkType type = resolveMarkTypeFromMetadata(controlPointMetadata, "Type");
String color = controlPointMetadata.get("Color");
String shape = controlPointMetadata.get("Shape");
String pattern = controlPointMetadata.get("Pattern");
ControlPointMetaData markMetadata = new ControlPointMetaDataImpl(controlPointName, type, color, shape, pattern, controlPoint.getId());
result = Collections.singleton(markMetadata);
}
return result;
}
private MarkType resolveMarkTypeFromMetadata(Map<String, String> controlPointMetadata, String typePropertyName) {
MarkType result = MarkType.BUOY;
String markType = controlPointMetadata.get(typePropertyName);
if(markType != null && !markType.isEmpty()) {
for(MarkType m: MarkType.values()) {
if(m.name().equalsIgnoreCase(markType)) {
result = m;
break;
}
}
}
return result;
}
}
@@ -6,6 +6,8 @@ import java.net.URI;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
@@ -101,12 +103,16 @@ public class RaceCourseReceiver extends AbstractReceiverWithQueue<Route, RouteDa
System.out.print("R");
final Route route = event.getA();
final String routeMetadataString = route.getMetadata() != null ? route.getMetadata().getText() : null;
Map<Integer, NauticalSide> courseWaypointPassingSides = parseAdditionalCourseDataFromMetadata(route, event.getB().getPoints(), routeMetadataString);
final LinkedHashMap<com.tractrac.clientmodule.ControlPoint, TracTracControlPoint> ttControlPointsForOriginalControlPoints = new LinkedHashMap<>();
for (com.tractrac.clientmodule.ControlPoint cp : event.getB().getPoints()) {
ttControlPointsForOriginalControlPoints.put(cp, new ControlPointAdapter(cp));
}
Map<Integer, NauticalSide> courseWaypointPassingSides = parseAdditionalCourseDataFromMetadata(ttControlPointsForOriginalControlPoints.values(), routeMetadataString);
List<Util.Pair<TracTracControlPoint, NauticalSide>> ttControlPoints = new ArrayList<>();
int i = 1;
for (com.tractrac.clientmodule.ControlPoint cp : event.getB().getPoints()) {
NauticalSide nauticalSide = courseWaypointPassingSides.containsKey(i) ? courseWaypointPassingSides.get(i) : null;
ttControlPoints.add(new Pair<TracTracControlPoint, NauticalSide>(new ControlPointAdapter(cp), nauticalSide));
ttControlPoints.add(new Pair<TracTracControlPoint, NauticalSide>(ttControlPointsForOriginalControlPoints.get(cp), nauticalSide));
i++;
}
Course course = getDomainFactory().createCourse(route.getName(), ttControlPoints);
@@ -156,17 +162,17 @@ public class RaceCourseReceiver extends AbstractReceiverWithQueue<Route, RouteDa
* Seq.3=GATE
* Seq.4=STARBOARD
* </pre>
* @param routeMetadataString TODO
*/
private Map<Integer, NauticalSide> parseAdditionalCourseDataFromMetadata(Route route,
List<com.tractrac.clientmodule.ControlPoint> controlPoints, String routeMetadataString) {
private Map<Integer, NauticalSide> parseAdditionalCourseDataFromMetadata(Iterable<TracTracControlPoint> controlPoints,
String routeMetadataString) {
Map<Integer, NauticalSide> result = new HashMap<Integer, NauticalSide>();
int controlPointsCount = controlPoints.size();
if (routeMetadataString != null) {
Map<String, String> routeMetadata = parseMetadata(routeMetadataString);
for (int i = 1; i <= controlPointsCount; i++) {
Iterator<TracTracControlPoint> iter = controlPoints.iterator();
int i=1;
while (iter.hasNext()) {
String seqValue = routeMetadata.get("Seq." + i);
com.tractrac.clientmodule.ControlPoint controlPoint = controlPoints.get(i - 1);
TracTracControlPoint controlPoint = iter.next();
if (!controlPoint.getHasTwoPoints() && seqValue != null) {
if ("PORT".equalsIgnoreCase(seqValue)) {
result.put(i, NauticalSide.PORT);
@@ -174,6 +180,7 @@ public class RaceCourseReceiver extends AbstractReceiverWithQueue<Route, RouteDa
result.put(i, NauticalSide.STARBOARD);
}
}
i++;
}
}
return result;
@@ -4,18 +4,15 @@ import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.Serializable;
import java.io.StringReader;
import java.net.MalformedURLException;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
@@ -277,7 +274,8 @@ public class TracTracRaceTrackerImpl extends AbstractRaceTrackerImpl implements
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();
Map<Integer, NauticalSide> passingSideData = parsePassingSideData(clientParams.getRace().getDefaultRoute(), newTracTracControlPoints);
Map<Integer, NauticalSide> passingSideData = domainFactory.getMetadataParser().parsePassingSideData(
clientParams.getRace().getDefaultRoute().getMetadata(), newTracTracControlPoints);
int i = 1;
for (TracTracControlPoint newTracTracControlPoint : newTracTracControlPoints) {
NauticalSide nauticalSide = passingSideData.containsKey(i) ? passingSideData.get(i) : null;
@@ -329,48 +327,6 @@ public class TracTracRaceTrackerImpl extends AbstractRaceTrackerImpl implements
}
}
/**
* Parses the route metadata for additional course information
* The 'passing side' for each course waypoint is encoded like this...
* Seq.1=GATE
* Seq.2=PORT
* Seq.3=GATE
* Seq.4=STARBOARD
*/
private Map<Integer, NauticalSide> parsePassingSideData(ClientParamsPHP.Route route, List<? extends TracTracControlPoint> controlPoints) {
Map<Integer, NauticalSide> result = new HashMap<Integer, NauticalSide>();
int controlPointsCount = controlPoints.size();
String routeMetadataString = route.getMetadata();
if(routeMetadataString != null) {
Map<String, String> routeMetadata = parseMetadata(routeMetadataString);
for(int i = 1; i <= controlPointsCount; i++) {
String seqValue = routeMetadata.get("Seq." + i);
TracTracControlPoint controlPoint = controlPoints.get(i-1);
if(!controlPoint.getHasTwoPoints() && seqValue != null) {
if("PORT".equalsIgnoreCase(seqValue)) {
result.put(i, NauticalSide.PORT);
} else if("STARBOARD".equalsIgnoreCase(seqValue)) {
result.put(i, NauticalSide.STARBOARD);
}
}
}
}
return result;
}
@SuppressWarnings({ "rawtypes", "unchecked" })
private Map<String, String> parseMetadata(String metadata) {
Map<String, String> metadataMap = new HashMap<String, String>();
try {
Properties p = new Properties();
p.load(new StringReader(metadata));
metadataMap = new HashMap<String, String>((Map) p);
} catch (IOException e) {
// do nothing
}
return metadataMap;
}
private void updateStartStopTimesAndLiveDelay(ClientParamsPHP clientParams, Simulator simulator) {
RaceDefinition currentRace = null;
long delayInMillis = clientParams.getLiveDelayInMillis();