Merge branch 'master' into search

Conflicts:
	java/com.sap.sailing.domain.persistence/src/com/sap/sailing/domain/persistence/impl/DomainObjectFactoryImpl.java
	java/com.sap.sailing.domain.persistence/src/com/sap/sailing/domain/persistence/racelog/tracking/impl/MongoGPSFixStoreImpl.java
	java/com.sap.sailing.domain.racelogtrackingadapter/src/com/sap/sailing/domain/racelogtracking/impl/RaceLogRaceTracker.java
	java/com.sap.sailing.domain.racelogtrackingadapter/src/com/sap/sailing/domain/racelogtracking/impl/RaceLogTrackingAdapterImpl.java
	java/com.sap.sailing.domain.racelogtrackingadapter/src/com/sap/sailing/domain/racelogtracking/servlet/RecordFixesPostServlet.java
	java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/trackfiles/impl/TrackFilesImportServlet.java
This commit is contained in:
Axel Uhl
2014-06-03 01:10:25 +02:00
28 changed files with 512 additions and 281 deletions
@@ -9,7 +9,7 @@ import java.util.Iterator;
import com.sap.sailing.domain.deckmanadapter.DeckmanAdapter; import com.sap.sailing.domain.deckmanadapter.DeckmanAdapter;
import com.sap.sailing.domain.deckmanadapter.Record; import com.sap.sailing.domain.deckmanadapter.Record;
import com.sap.sailing.domain.racelog.tracking.DeviceIdentifier; import com.sap.sailing.domain.trackfiles.TrackFileImportDeviceIdentifier;
import com.sap.sailing.domain.trackfiles.TrackFileImportDeviceIdentifierImpl; import com.sap.sailing.domain.trackfiles.TrackFileImportDeviceIdentifierImpl;
import com.sap.sailing.domain.trackimport.FormatNotSupportedException; import com.sap.sailing.domain.trackimport.FormatNotSupportedException;
import com.sap.sailing.domain.trackimport.GPSFixImporter; import com.sap.sailing.domain.trackimport.GPSFixImporter;
@@ -21,7 +21,7 @@ public class DeckmanGPSFixImporter implements GPSFixImporter {
public void importFixes(InputStream inputStream, Callback callback, boolean inferSpeedAndBearing, String sourceName) public void importFixes(InputStream inputStream, Callback callback, boolean inferSpeedAndBearing, String sourceName)
throws FormatNotSupportedException, IOException { throws FormatNotSupportedException, IOException {
DeckmanAdapter deckmanAdapter = DeckmanAdapterFactoryImpl.INSTANCE.createDeckmanAdapter(); DeckmanAdapter deckmanAdapter = DeckmanAdapterFactoryImpl.INSTANCE.createDeckmanAdapter();
DeviceIdentifier device = new TrackFileImportDeviceIdentifierImpl(sourceName, getType() + "@" + new Date()); TrackFileImportDeviceIdentifier device = new TrackFileImportDeviceIdentifierImpl(sourceName, getType() + "@" + new Date());
try { try {
for (Iterator<Record> i = deckmanAdapter.parseLogFile(new InputStreamReader(inputStream)); i.hasNext();) { for (Iterator<Record> i = deckmanAdapter.parseLogFile(new InputStreamReader(inputStream)); i.hasNext();) {
Record record = i.next(); Record record = i.next();
@@ -82,4 +82,9 @@ public enum CollectionNames {
* Stores {@link GPSFix}es * Stores {@link GPSFix}es
*/ */
GPS_FIXES, GPS_FIXES,
/**
* Metadata for the GPSFixes, grouped by Device Identifier.
*/
GPS_FIXES_METADATA,
} }
@@ -71,6 +71,7 @@ import com.sap.sailing.domain.common.RegattaNameAndRaceName;
import com.sap.sailing.domain.common.ScoringSchemeType; import com.sap.sailing.domain.common.ScoringSchemeType;
import com.sap.sailing.domain.common.SpeedWithBearing; import com.sap.sailing.domain.common.SpeedWithBearing;
import com.sap.sailing.domain.common.TimePoint; import com.sap.sailing.domain.common.TimePoint;
import com.sap.sailing.domain.common.TimeRange;
import com.sap.sailing.domain.common.WindSource; import com.sap.sailing.domain.common.WindSource;
import com.sap.sailing.domain.common.WindSourceType; import com.sap.sailing.domain.common.WindSourceType;
import com.sap.sailing.domain.common.configuration.DeviceConfigurationMatcherType; import com.sap.sailing.domain.common.configuration.DeviceConfigurationMatcherType;
@@ -79,6 +80,7 @@ import com.sap.sailing.domain.common.impl.DegreePosition;
import com.sap.sailing.domain.common.impl.KnotSpeedWithBearingImpl; import com.sap.sailing.domain.common.impl.KnotSpeedWithBearingImpl;
import com.sap.sailing.domain.common.impl.MillisecondsTimePoint; import com.sap.sailing.domain.common.impl.MillisecondsTimePoint;
import com.sap.sailing.domain.common.impl.RGBColor; import com.sap.sailing.domain.common.impl.RGBColor;
import com.sap.sailing.domain.common.impl.TimeRangeImpl;
import com.sap.sailing.domain.common.impl.WindSourceImpl; import com.sap.sailing.domain.common.impl.WindSourceImpl;
import com.sap.sailing.domain.common.impl.WindSourceWithAdditionalID; import com.sap.sailing.domain.common.impl.WindSourceWithAdditionalID;
import com.sap.sailing.domain.common.racelog.Flags; import com.sap.sailing.domain.common.racelog.Flags;
@@ -164,26 +166,26 @@ public class DomainObjectFactoryImpl implements DomainObjectFactory {
private RaceLogEventRestoreFactory raceLogEventFactory; private RaceLogEventRestoreFactory raceLogEventFactory;
private final DomainFactory baseDomainFactory; private final DomainFactory baseDomainFactory;
private final TypeBasedServiceFinder<DeviceIdentifierMongoHandler> deviceIdentifierServiceFinder; private final TypeBasedServiceFinder<DeviceIdentifierMongoHandler> deviceIdentifierServiceFinder;
private final TypeBasedServiceFinderFactory serviceFinderFactory; private final TypeBasedServiceFinderFactory serviceFinderFactory;
/** /**
* Uses <code>null</code> as the {@link TypeBasedServiceFinder}, meaning that no {@link DeviceIdentifier}s can be loaded * Uses <code>null</code> as the {@link TypeBasedServiceFinder}, meaning that no {@link DeviceIdentifier}s can be loaded
* using this instance of a {@link DomainObjectFactory}. * using this instance of a {@link DomainObjectFactory}.
*/ */
public DomainObjectFactoryImpl(DB db, DomainFactory baseDomainFactory) { public DomainObjectFactoryImpl(DB db, DomainFactory baseDomainFactory) {
this(db, baseDomainFactory, /* deviceTypeServiceFinder */ null); this(db, baseDomainFactory, /* deviceTypeServiceFinder */ null);
} }
public DomainObjectFactoryImpl(DB db, DomainFactory baseDomainFactory, TypeBasedServiceFinderFactory serviceFinderFactory) { public DomainObjectFactoryImpl(DB db, DomainFactory baseDomainFactory, TypeBasedServiceFinderFactory serviceFinderFactory) {
super(); super();
this.serviceFinderFactory = serviceFinderFactory; this.serviceFinderFactory = serviceFinderFactory;
if (serviceFinderFactory != null) { if (serviceFinderFactory != null) {
this.deviceIdentifierServiceFinder = serviceFinderFactory.createServiceFinder(DeviceIdentifierMongoHandler.class); this.deviceIdentifierServiceFinder = serviceFinderFactory.createServiceFinder(DeviceIdentifierMongoHandler.class);
this.deviceIdentifierServiceFinder.setFallbackService(new PlaceHolderDeviceIdentifierMongoHandler()); this.deviceIdentifierServiceFinder.setFallbackService(new PlaceHolderDeviceIdentifierMongoHandler());
} else { } else {
this.deviceIdentifierServiceFinder = null; this.deviceIdentifierServiceFinder = null;
} }
this.baseDomainFactory = baseDomainFactory; this.baseDomainFactory = baseDomainFactory;
this.competitorDeserializer = CompetitorJsonDeserializer.create(baseDomainFactory); this.competitorDeserializer = CompetitorJsonDeserializer.create(baseDomainFactory);
this.database = db; this.database = db;
@@ -199,7 +201,7 @@ public class DomainObjectFactoryImpl implements DomainObjectFactory {
return new WindImpl(loadPosition(object), loadTimePoint(object), loadSpeedWithBearing(object)); return new WindImpl(loadPosition(object), loadTimePoint(object), loadSpeedWithBearing(object));
} }
public Position loadPosition(DBObject object) { public Position loadPosition(DBObject object) {
Number latNumber = (Number) object.get(FieldNames.LAT_DEG.name()); Number latNumber = (Number) object.get(FieldNames.LAT_DEG.name());
Double lat = latNumber == null ? null : latNumber.doubleValue(); Double lat = latNumber == null ? null : latNumber.doubleValue();
Number lngNumber = (Number) object.get(FieldNames.LNG_DEG.name()); Number lngNumber = (Number) object.get(FieldNames.LNG_DEG.name());
@@ -211,27 +213,36 @@ public class DomainObjectFactoryImpl implements DomainObjectFactory {
} }
} }
public static TimePoint loadTimePoint(DBObject object, String fieldName) { public static TimePoint loadTimePoint(DBObject object, String fieldName) {
TimePoint result = null; TimePoint result = null;
Number timePointAsNumber = (Number) object.get(fieldName); Number timePointAsNumber = (Number) object.get(fieldName);
if (timePointAsNumber != null) { if (timePointAsNumber != null) {
result = new MillisecondsTimePoint(timePointAsNumber.longValue()); result = new MillisecondsTimePoint(timePointAsNumber.longValue());
} }
return result; return result;
} }
public static TimePoint loadTimePoint(DBObject object, FieldNames field) { public static TimePoint loadTimePoint(DBObject object, FieldNames field) {
return loadTimePoint(object, field.name()); return loadTimePoint(object, field.name());
} }
public static TimeRange loadTimeRange(DBObject object, FieldNames field) {
DBObject timeRangeObj = (DBObject) object.get(field.name());
if (timeRangeObj == null) {
return null;
}
TimePoint from = loadTimePoint(timeRangeObj, FieldNames.FROM_MILLIS);
TimePoint to = loadTimePoint(timeRangeObj, FieldNames.TO_MILLIS);
return new TimeRangeImpl(from, to);
}
/** /**
* Loads a {@link TimePoint} on the given object at {@link FieldNames#TIME_AS_MILLIS}. * Loads a {@link TimePoint} on the given object at {@link FieldNames#TIME_AS_MILLIS}.
*/ */
public TimePoint loadTimePoint(DBObject object) { public TimePoint loadTimePoint(DBObject object) {
return loadTimePoint(object, FieldNames.TIME_AS_MILLIS); return loadTimePoint(object, FieldNames.TIME_AS_MILLIS);
} }
public SpeedWithBearing loadSpeedWithBearing(DBObject object) { public SpeedWithBearing loadSpeedWithBearing(DBObject object) {
return new KnotSpeedWithBearingImpl(((Number) object.get(FieldNames.KNOT_SPEED.name())).doubleValue(), return new KnotSpeedWithBearingImpl(((Number) object.get(FieldNames.KNOT_SPEED.name())).doubleValue(),
new DegreeBearingImpl(((Number) object.get(FieldNames.DEGREE_BEARING.name())).doubleValue())); new DegreeBearingImpl(((Number) object.get(FieldNames.DEGREE_BEARING.name())).doubleValue()));
} }
@@ -1058,7 +1069,7 @@ public class DomainObjectFactoryImpl implements DomainObjectFactory {
BasicDBList dbSeries = (BasicDBList) dbRegatta.get(FieldNames.REGATTA_SERIES.name()); BasicDBList dbSeries = (BasicDBList) dbRegatta.get(FieldNames.REGATTA_SERIES.name());
Iterable<Series> series = loadSeries(dbSeries, trackedRegattaRegistry); Iterable<Series> series = loadSeries(dbSeries, trackedRegattaRegistry);
RaceLogStore raceLogStore = MongoRaceLogStoreFactory.INSTANCE.getMongoRaceLogStore( RaceLogStore raceLogStore = MongoRaceLogStoreFactory.INSTANCE.getMongoRaceLogStore(
new MongoObjectFactoryImpl(database, serviceFinderFactory), new MongoObjectFactoryImpl(database, serviceFinderFactory),
this); this);
Serializable courseAreaId = (Serializable) dbRegatta.get(FieldNames.COURSE_AREA_ID.name()); Serializable courseAreaId = (Serializable) dbRegatta.get(FieldNames.COURSE_AREA_ID.name());
@@ -1221,7 +1232,7 @@ public class DomainObjectFactoryImpl implements DomainObjectFactory {
List<RaceLogEvent> eventsToMigrate = loadRaceLogEvents(result, query); List<RaceLogEvent> eventsToMigrate = loadRaceLogEvents(result, query);
if (!eventsToMigrate.isEmpty()) { if (!eventsToMigrate.isEmpty()) {
// ... migrate them... // ... migrate them...
MongoRaceLogStoreVisitor storeVisitor = new MongoRaceLogStoreVisitor(identifier, new MongoObjectFactoryImpl(database, serviceFinderFactory)); MongoRaceLogStoreVisitor storeVisitor = new MongoRaceLogStoreVisitor(identifier, new MongoObjectFactoryImpl(database, serviceFinderFactory));
for (RaceLogEvent event : eventsToMigrate) { for (RaceLogEvent event : eventsToMigrate) {
event.accept(storeVisitor); event.accept(storeVisitor);
} }
@@ -1296,22 +1307,22 @@ public class DomainObjectFactoryImpl implements DomainObjectFactory {
return loadRaceLogRaceLogProtestStartTimeEvent(createdAt, author, logicalTimePoint, id, passId, competitors, dbObject); return loadRaceLogRaceLogProtestStartTimeEvent(createdAt, author, logicalTimePoint, id, passId, competitors, dbObject);
} else if (eventClass.equals(RaceLogWindFixEvent.class.getSimpleName())) { } else if (eventClass.equals(RaceLogWindFixEvent.class.getSimpleName())) {
return loadRaceLogRaceLogWindFixEvent(createdAt, author, logicalTimePoint, id, passId, competitors, dbObject); return loadRaceLogRaceLogWindFixEvent(createdAt, author, logicalTimePoint, id, passId, competitors, dbObject);
} else if (eventClass.equals(DeviceCompetitorMappingEvent.class.getSimpleName())) { } else if (eventClass.equals(DeviceCompetitorMappingEvent.class.getSimpleName())) {
return loadRaceLogDeviceCompetitorMappingEvent(createdAt, author, logicalTimePoint, id, passId, competitors, dbObject); return loadRaceLogDeviceCompetitorMappingEvent(createdAt, author, logicalTimePoint, id, passId, competitors, dbObject);
} else if (eventClass.equals(DeviceMarkMappingEvent.class.getSimpleName())) { } else if (eventClass.equals(DeviceMarkMappingEvent.class.getSimpleName())) {
return loadRaceLogDeviceMarkMappingEvent(createdAt, author, logicalTimePoint, id, passId, competitors, dbObject); return loadRaceLogDeviceMarkMappingEvent(createdAt, author, logicalTimePoint, id, passId, competitors, dbObject);
} else if (eventClass.equals(DenoteForTrackingEvent.class.getSimpleName())) { } else if (eventClass.equals(DenoteForTrackingEvent.class.getSimpleName())) {
return loadRaceLogDenoteForTrackingEvent(createdAt, author, logicalTimePoint, id, passId, competitors, dbObject); return loadRaceLogDenoteForTrackingEvent(createdAt, author, logicalTimePoint, id, passId, competitors, dbObject);
} else if (eventClass.equals(StartTrackingEvent.class.getSimpleName())) { } else if (eventClass.equals(StartTrackingEvent.class.getSimpleName())) {
return loadRaceLogStartEvent(createdAt, author, logicalTimePoint, id, passId, competitors, dbObject); return loadRaceLogStartEvent(createdAt, author, logicalTimePoint, id, passId, competitors, dbObject);
} else if (eventClass.equals(RevokeEvent.class.getSimpleName())) { } else if (eventClass.equals(RevokeEvent.class.getSimpleName())) {
return loadRaceLogRevokeEvent(createdAt, author, logicalTimePoint, id, passId, competitors, dbObject); return loadRaceLogRevokeEvent(createdAt, author, logicalTimePoint, id, passId, competitors, dbObject);
} else if (eventClass.equals(RegisterCompetitorEvent.class.getSimpleName())) { } else if (eventClass.equals(RegisterCompetitorEvent.class.getSimpleName())) {
return loadRaceLogRegisterCompetitorEvent(createdAt, author, logicalTimePoint, id, passId, competitors, dbObject); return loadRaceLogRegisterCompetitorEvent(createdAt, author, logicalTimePoint, id, passId, competitors, dbObject);
} else if (eventClass.equals(DefineMarkEvent.class.getSimpleName())) { } else if (eventClass.equals(DefineMarkEvent.class.getSimpleName())) {
return loadRaceLogDefineMarkEvent(createdAt, author, logicalTimePoint, id, passId, competitors, dbObject); return loadRaceLogDefineMarkEvent(createdAt, author, logicalTimePoint, id, passId, competitors, dbObject);
} else if (eventClass.equals(CloseOpenEndedDeviceMappingEvent.class.getSimpleName())) { } else if (eventClass.equals(CloseOpenEndedDeviceMappingEvent.class.getSimpleName())) {
return loadRaceLogCloseOpenEndedDeviceMappingEvent(createdAt, author, logicalTimePoint, id, passId, competitors, dbObject); return loadRaceLogCloseOpenEndedDeviceMappingEvent(createdAt, author, logicalTimePoint, id, passId, competitors, dbObject);
} }
throw new IllegalStateException(String.format("Unknown RaceLogEvent type %s", eventClass)); throw new IllegalStateException(String.format("Unknown RaceLogEvent type %s", eventClass));
@@ -1323,80 +1334,80 @@ public class DomainObjectFactoryImpl implements DomainObjectFactory {
return raceLogEventFactory.createWindFixEvent(createdAt, author, logicalTimePoint, id, competitors, passId, wind); return raceLogEventFactory.createWindFixEvent(createdAt, author, logicalTimePoint, id, competitors, passId, wind);
} }
private RaceLogEvent loadRaceLogDeviceCompetitorMappingEvent(TimePoint createdAt, RaceLogEventAuthor author, TimePoint logicalTimePoint, private RaceLogEvent loadRaceLogDeviceCompetitorMappingEvent(TimePoint createdAt, RaceLogEventAuthor author, TimePoint logicalTimePoint,
Serializable id, Integer passId, List<Competitor> competitors, DBObject dbObject) { Serializable id, Integer passId, List<Competitor> competitors, DBObject dbObject) {
DeviceIdentifier device = null; DeviceIdentifier device = null;
try { try {
device = loadDeviceId(deviceIdentifierServiceFinder, device = loadDeviceId(deviceIdentifierServiceFinder,
(DBObject) dbObject.get(FieldNames.DEVICE_ID.name())); (DBObject) dbObject.get(FieldNames.DEVICE_ID.name()));
} catch (Exception e) { } catch (Exception e) {
logger.log(Level.WARNING, "Could not load deviceId for RaceLogEvent", e); logger.log(Level.WARNING, "Could not load deviceId for RaceLogEvent", e);
e.printStackTrace(); e.printStackTrace();
} }
Competitor mappedTo = baseDomainFactory.getExistingCompetitorById( Competitor mappedTo = baseDomainFactory.getExistingCompetitorById(
(Serializable) dbObject.get(FieldNames.COMPETITOR_ID.name())); (Serializable) dbObject.get(FieldNames.COMPETITOR_ID.name()));
TimePoint from = loadTimePoint(dbObject, FieldNames.RACE_LOG_FROM); TimePoint from = loadTimePoint(dbObject, FieldNames.RACE_LOG_FROM);
TimePoint to = loadTimePoint(dbObject, FieldNames.RACE_LOG_TO); TimePoint to = loadTimePoint(dbObject, FieldNames.RACE_LOG_TO);
return raceLogEventFactory.createDeviceCompetitorMappingEvent(createdAt, author, logicalTimePoint, id, device, mappedTo, passId, from, to); return raceLogEventFactory.createDeviceCompetitorMappingEvent(createdAt, author, logicalTimePoint, id, device, mappedTo, passId, from, to);
} }
private RaceLogEvent loadRaceLogDeviceMarkMappingEvent(TimePoint createdAt, RaceLogEventAuthor author, TimePoint logicalTimePoint, private RaceLogEvent loadRaceLogDeviceMarkMappingEvent(TimePoint createdAt, RaceLogEventAuthor author, TimePoint logicalTimePoint,
Serializable id, Integer passId, List<Competitor> competitors, DBObject dbObject) { Serializable id, Integer passId, List<Competitor> competitors, DBObject dbObject) {
DeviceIdentifier device = null; DeviceIdentifier device = null;
try { try {
device = loadDeviceId(deviceIdentifierServiceFinder, device = loadDeviceId(deviceIdentifierServiceFinder,
(DBObject) dbObject.get(FieldNames.DEVICE_ID.name())); (DBObject) dbObject.get(FieldNames.DEVICE_ID.name()));
} catch (Exception e) { } catch (Exception e) {
logger.log(Level.WARNING, "Could not load deviceId for RaceLogEvent", e); logger.log(Level.WARNING, "Could not load deviceId for RaceLogEvent", e);
e.printStackTrace(); e.printStackTrace();
} }
Mark mappedTo = baseDomainFactory.getOrCreateMark( Mark mappedTo = baseDomainFactory.getOrCreateMark(
(Serializable) dbObject.get(FieldNames.MARK_ID.name()), null); (Serializable) dbObject.get(FieldNames.MARK_ID.name()), null);
TimePoint from = loadTimePoint(dbObject, FieldNames.RACE_LOG_FROM); TimePoint from = loadTimePoint(dbObject, FieldNames.RACE_LOG_FROM);
TimePoint to = loadTimePoint(dbObject, FieldNames.RACE_LOG_TO); TimePoint to = loadTimePoint(dbObject, FieldNames.RACE_LOG_TO);
return raceLogEventFactory.createDeviceMarkMappingEvent(createdAt, author, logicalTimePoint, id, device, mappedTo, passId, from, to); return raceLogEventFactory.createDeviceMarkMappingEvent(createdAt, author, logicalTimePoint, id, device, mappedTo, passId, from, to);
} }
private RaceLogEvent loadRaceLogDenoteForTrackingEvent(TimePoint createdAt, RaceLogEventAuthor author, TimePoint logicalTimePoint, private RaceLogEvent loadRaceLogDenoteForTrackingEvent(TimePoint createdAt, RaceLogEventAuthor author, TimePoint logicalTimePoint,
Serializable id, Integer passId, List<Competitor> competitors, DBObject dbObject) { Serializable id, Integer passId, List<Competitor> competitors, DBObject dbObject) {
String raceName = (String) dbObject.get(FieldNames.RACE_NAME.name()); String raceName = (String) dbObject.get(FieldNames.RACE_NAME.name());
BoatClass boatClass = baseDomainFactory.getOrCreateBoatClass((String) dbObject.get(FieldNames.BOAT_CLASS_NAME.name())); BoatClass boatClass = baseDomainFactory.getOrCreateBoatClass((String) dbObject.get(FieldNames.BOAT_CLASS_NAME.name()));
Serializable raceId = (Serializable) dbObject.get(FieldNames.RACE_ID.name()); Serializable raceId = (Serializable) dbObject.get(FieldNames.RACE_ID.name());
return raceLogEventFactory.createDenoteForTrackingEvent(createdAt, author, logicalTimePoint, id, passId, raceName, boatClass, raceId); return raceLogEventFactory.createDenoteForTrackingEvent(createdAt, author, logicalTimePoint, id, passId, raceName, boatClass, raceId);
} }
private RaceLogEvent loadRaceLogStartEvent(TimePoint createdAt, RaceLogEventAuthor author, TimePoint logicalTimePoint, private RaceLogEvent loadRaceLogStartEvent(TimePoint createdAt, RaceLogEventAuthor author, TimePoint logicalTimePoint,
Serializable id, Integer passId, List<Competitor> competitors, DBObject dbObject) { Serializable id, Integer passId, List<Competitor> competitors, DBObject dbObject) {
return raceLogEventFactory.createStartTrackingEvent(createdAt, author, logicalTimePoint, id, passId); return raceLogEventFactory.createStartTrackingEvent(createdAt, author, logicalTimePoint, id, passId);
} }
private RaceLogEvent loadRaceLogRevokeEvent(TimePoint createdAt, RaceLogEventAuthor author, TimePoint logicalTimePoint, private RaceLogEvent loadRaceLogRevokeEvent(TimePoint createdAt, RaceLogEventAuthor author, TimePoint logicalTimePoint,
Serializable id, Integer passId, List<Competitor> competitors, DBObject dbObject) { Serializable id, Integer passId, List<Competitor> competitors, DBObject dbObject) {
Serializable revokedEventId = Helpers.tryUuidConversion( Serializable revokedEventId = Helpers.tryUuidConversion(
(Serializable) dbObject.get(FieldNames.RACE_LOG_REVOKED_EVENT_ID.name())); (Serializable) dbObject.get(FieldNames.RACE_LOG_REVOKED_EVENT_ID.name()));
return raceLogEventFactory.createRevokeEvent(createdAt, author, logicalTimePoint, id, passId, revokedEventId); return raceLogEventFactory.createRevokeEvent(createdAt, author, logicalTimePoint, id, passId, revokedEventId);
} }
private RaceLogEvent loadRaceLogRegisterCompetitorEvent(TimePoint createdAt, RaceLogEventAuthor author, TimePoint logicalTimePoint, private RaceLogEvent loadRaceLogRegisterCompetitorEvent(TimePoint createdAt, RaceLogEventAuthor author, TimePoint logicalTimePoint,
Serializable id, Integer passId, List<Competitor> competitors, DBObject dbObject) { Serializable id, Integer passId, List<Competitor> competitors, DBObject dbObject) {
assert competitors.size() == 1 : "Should have exactly one competitor for RegisterCompetitorEvent"; assert competitors.size() == 1 : "Should have exactly one competitor for RegisterCompetitorEvent";
return raceLogEventFactory.createRegisterCompetitorEvent(createdAt, author, logicalTimePoint, id, passId, competitors.get(0)); return raceLogEventFactory.createRegisterCompetitorEvent(createdAt, author, logicalTimePoint, id, passId, competitors.get(0));
} }
private RaceLogEvent loadRaceLogDefineMarkEvent(TimePoint createdAt, RaceLogEventAuthor author, TimePoint logicalTimePoint, private RaceLogEvent loadRaceLogDefineMarkEvent(TimePoint createdAt, RaceLogEventAuthor author, TimePoint logicalTimePoint,
Serializable id, Integer passId, List<Competitor> competitors, DBObject dbObject) { Serializable id, Integer passId, List<Competitor> competitors, DBObject dbObject) {
Mark mark = loadMark((DBObject) dbObject.get(FieldNames.RACE_LOG_MARK.name())); Mark mark = loadMark((DBObject) dbObject.get(FieldNames.RACE_LOG_MARK.name()));
return raceLogEventFactory.createDefineMarkEvent(createdAt, author, logicalTimePoint, id, passId, mark); return raceLogEventFactory.createDefineMarkEvent(createdAt, author, logicalTimePoint, id, passId, mark);
} }
private RaceLogEvent loadRaceLogCloseOpenEndedDeviceMappingEvent(TimePoint createdAt, RaceLogEventAuthor author, TimePoint logicalTimePoint, private RaceLogEvent loadRaceLogCloseOpenEndedDeviceMappingEvent(TimePoint createdAt, RaceLogEventAuthor author, TimePoint logicalTimePoint,
Serializable id, Integer passId, List<Competitor> competitors, DBObject dbObject) { Serializable id, Integer passId, List<Competitor> competitors, DBObject dbObject) {
Serializable deviceMappingEventId = Helpers.tryUuidConversion((Serializable) dbObject.get(FieldNames.RACE_LOG_DEVICE_MAPPING_EVENT_ID.name())); Serializable deviceMappingEventId = Helpers.tryUuidConversion((Serializable) dbObject.get(FieldNames.RACE_LOG_DEVICE_MAPPING_EVENT_ID.name()));
TimePoint closingTimePoint = loadTimePoint(dbObject, FieldNames.RACE_LOG_CLOSING_TIMEPOINT); TimePoint closingTimePoint = loadTimePoint(dbObject, FieldNames.RACE_LOG_CLOSING_TIMEPOINT);
return raceLogEventFactory.createCloseOpenEndedDeviceMappingEvent(createdAt, author, logicalTimePoint, id, passId, return raceLogEventFactory.createCloseOpenEndedDeviceMappingEvent(createdAt, author, logicalTimePoint, id, passId,
deviceMappingEventId, closingTimePoint); deviceMappingEventId, closingTimePoint);
} }
private RaceLogEvent loadRaceLogRaceLogProtestStartTimeEvent(TimePoint createdAt, RaceLogEventAuthor author, private RaceLogEvent loadRaceLogRaceLogProtestStartTimeEvent(TimePoint createdAt, RaceLogEventAuthor author,
TimePoint logicalTimePoint, Serializable id, Integer passId, List<Competitor> competitors, DBObject dbObject) { TimePoint logicalTimePoint, Serializable id, Integer passId, List<Competitor> competitors, DBObject dbObject) {
TimePoint protestStartTime = loadTimePoint(dbObject, FieldNames.RACE_LOG_PROTEST_START_TIME); TimePoint protestStartTime = loadTimePoint(dbObject, FieldNames.RACE_LOG_PROTEST_START_TIME);
@@ -1705,19 +1716,19 @@ public class DomainObjectFactoryImpl implements DomainObjectFactory {
} }
return configuration; return configuration;
} }
private DeviceIdentifier loadDeviceId( private DeviceIdentifier loadDeviceId(
TypeBasedServiceFinder<DeviceIdentifierMongoHandler> deviceIdentifierServiceFinder, DBObject deviceId) TypeBasedServiceFinder<DeviceIdentifierMongoHandler> deviceIdentifierServiceFinder, DBObject deviceId)
throws TransformationException, NoCorrespondingServiceRegisteredException { throws TransformationException, NoCorrespondingServiceRegisteredException {
String deviceType = (String) deviceId.get(FieldNames.DEVICE_TYPE.name()); String deviceType = (String) deviceId.get(FieldNames.DEVICE_TYPE.name());
Object deviceTypeId = deviceId.get(FieldNames.DEVICE_TYPE_SPECIFIC_ID.name()); Object deviceTypeId = deviceId.get(FieldNames.DEVICE_TYPE_SPECIFIC_ID.name());
String stringRepresentation = (String) deviceId.get(FieldNames.DEVICE_STRING_REPRESENTATION.name()); String stringRepresentation = (String) deviceId.get(FieldNames.DEVICE_STRING_REPRESENTATION.name());
try { try {
return deviceIdentifierServiceFinder.findService(deviceType).deserialize(deviceTypeId, deviceType, stringRepresentation); return deviceIdentifierServiceFinder.findService(deviceType).deserialize(deviceTypeId, deviceType, stringRepresentation);
} catch (TransformationException e) { } catch (TransformationException e) {
return new PlaceHolderDeviceIdentifierSerializationHandler().deserialize( return new PlaceHolderDeviceIdentifierSerializationHandler().deserialize(
stringRepresentation, deviceType, stringRepresentation); stringRepresentation, deviceType, stringRepresentation);
} }
} }
} }
@@ -98,4 +98,10 @@ public enum FieldNames {
// GPSFixes // GPSFixes
DEVICE_TYPE_SPECIFIC_ID, DEVICE_ID, DEVICE_TYPE, GPSFIX_TYPE, GPSFIX, DEVICE_STRING_REPRESENTATION, DEVICE_TYPE_SPECIFIC_ID, DEVICE_ID, DEVICE_TYPE, GPSFIX_TYPE, GPSFIX, DEVICE_STRING_REPRESENTATION,
// GPSFixes metadata
TIMERANGE, NUM_FIXES,
// Timespan
FROM_MILLIS, TO_MILLIS,
} }
@@ -47,6 +47,7 @@ import com.sap.sailing.domain.common.RaceIdentifier;
import com.sap.sailing.domain.common.Speed; import com.sap.sailing.domain.common.Speed;
import com.sap.sailing.domain.common.SpeedWithBearing; import com.sap.sailing.domain.common.SpeedWithBearing;
import com.sap.sailing.domain.common.TimePoint; import com.sap.sailing.domain.common.TimePoint;
import com.sap.sailing.domain.common.TimeRange;
import com.sap.sailing.domain.common.WindSource; import com.sap.sailing.domain.common.WindSource;
import com.sap.sailing.domain.common.WithID; import com.sap.sailing.domain.common.WithID;
import com.sap.sailing.domain.common.impl.MillisecondsTimePoint; import com.sap.sailing.domain.common.impl.MillisecondsTimePoint;
@@ -147,6 +148,15 @@ public class MongoObjectFactoryImpl implements MongoObjectFactory {
public static void storeTimePoint(TimePoint timePoint, DBObject result, FieldNames field) { public static void storeTimePoint(TimePoint timePoint, DBObject result, FieldNames field) {
storeTimePoint(timePoint, result, field.name()); storeTimePoint(timePoint, result, field.name());
}
public static void storeTimeRange(TimeRange timeRange, DBObject result, FieldNames field) {
if (timeRange != null) {
DBObject timeRangeObj = new BasicDBObject();
storeTimePoint(timeRange.from(), timeRangeObj, FieldNames.FROM_MILLIS);
storeTimePoint(timeRange.to(), timeRangeObj, FieldNames.TO_MILLIS);
result.put(field.name(), timeRangeObj);
}
} }
public void storeTimed(Timed timed, DBObject result) { public void storeTimed(Timed timed, DBObject result) {
@@ -192,8 +202,17 @@ public class MongoObjectFactoryImpl implements MongoObjectFactory {
DBCollection gpsFixCollection = database.getCollection(CollectionNames.GPS_FIXES.name()); DBCollection gpsFixCollection = database.getCollection(CollectionNames.GPS_FIXES.name());
DBObject index = new BasicDBObject(); DBObject index = new BasicDBObject();
index.put(FieldNames.DEVICE_ID.name(), null); index.put(FieldNames.DEVICE_ID.name(), null);
index.put(FieldNames.TIME_AS_MILLIS.name(), null); index.put(FieldNames.TIME_AS_MILLIS.name(), null);
gpsFixCollection.ensureIndex(index);
return gpsFixCollection; return gpsFixCollection;
}
public DBCollection getGPSFixMetadataCollection() {
DBCollection collection = database.getCollection(CollectionNames.GPS_FIXES_METADATA.name());
DBObject index = new BasicDBObject();
index.put(FieldNames.DEVICE_ID.name(), null);
collection.ensureIndex(index);
return collection;
} }
/** /**
@@ -8,6 +8,7 @@ import java.util.Set;
import java.util.logging.Level; import java.util.logging.Level;
import java.util.logging.Logger; import java.util.logging.Logger;
import com.mongodb.BasicDBObject;
import com.mongodb.BasicDBObjectBuilder; import com.mongodb.BasicDBObjectBuilder;
import com.mongodb.DBCollection; import com.mongodb.DBCollection;
import com.mongodb.DBCursor; import com.mongodb.DBCursor;
@@ -16,12 +17,15 @@ import com.mongodb.QueryBuilder;
import com.sap.sailing.domain.base.Competitor; import com.sap.sailing.domain.base.Competitor;
import com.sap.sailing.domain.base.Mark; import com.sap.sailing.domain.base.Mark;
import com.sap.sailing.domain.common.TimePoint; import com.sap.sailing.domain.common.TimePoint;
import com.sap.sailing.domain.common.TimeRange;
import com.sap.sailing.domain.common.impl.TimeRangeImpl;
import com.sap.sailing.domain.common.racelog.tracking.NoCorrespondingServiceRegisteredException; import com.sap.sailing.domain.common.racelog.tracking.NoCorrespondingServiceRegisteredException;
import com.sap.sailing.domain.common.racelog.tracking.TransformationException; import com.sap.sailing.domain.common.racelog.tracking.TransformationException;
import com.sap.sailing.domain.common.racelog.tracking.TypeBasedServiceFinder; import com.sap.sailing.domain.common.racelog.tracking.TypeBasedServiceFinder;
import com.sap.sailing.domain.common.racelog.tracking.TypeBasedServiceFinderFactory; import com.sap.sailing.domain.common.racelog.tracking.TypeBasedServiceFinderFactory;
import com.sap.sailing.domain.persistence.DomainObjectFactory; import com.sap.sailing.domain.persistence.DomainObjectFactory;
import com.sap.sailing.domain.persistence.MongoObjectFactory; import com.sap.sailing.domain.persistence.MongoObjectFactory;
import com.sap.sailing.domain.persistence.impl.DomainObjectFactoryImpl;
import com.sap.sailing.domain.persistence.impl.FieldNames; import com.sap.sailing.domain.persistence.impl.FieldNames;
import com.sap.sailing.domain.persistence.impl.MongoObjectFactoryImpl; import com.sap.sailing.domain.persistence.impl.MongoObjectFactoryImpl;
import com.sap.sailing.domain.persistence.racelog.tracking.DeviceIdentifierMongoHandler; import com.sap.sailing.domain.persistence.racelog.tracking.DeviceIdentifierMongoHandler;
@@ -38,11 +42,18 @@ import com.sap.sailing.domain.tracking.GPSFix;
import com.sap.sailing.domain.tracking.GPSFixMoving; import com.sap.sailing.domain.tracking.GPSFixMoving;
import com.sap.sse.common.Util; import com.sap.sse.common.Util;
/**
* At the moment, the timerange covered by the fixes for a device, and the number of
* fixes for a device are stored in a metadata collection. Should be changed, see bug 1982.
* @author Fredrik Teschke
*
*/
public class MongoGPSFixStoreImpl implements MongoGPSFixStore { public class MongoGPSFixStoreImpl implements MongoGPSFixStore {
private static final Logger logger = Logger.getLogger(MongoGPSFixStore.class.getName()); private static final Logger logger = Logger.getLogger(MongoGPSFixStore.class.getName());
private final TypeBasedServiceFinder<GPSFixMongoHandler> fixServiceFinder; private final TypeBasedServiceFinder<GPSFixMongoHandler> fixServiceFinder;
private final TypeBasedServiceFinder<DeviceIdentifierMongoHandler> deviceServiceFinder; private final TypeBasedServiceFinder<DeviceIdentifierMongoHandler> deviceServiceFinder;
private final DBCollection collection; private final DBCollection fixesCollection;
private final DBCollection metadataCollection;
private final MongoObjectFactoryImpl mongoOF; private final MongoObjectFactoryImpl mongoOF;
private final Map<DeviceIdentifier, Set<GPSFixReceivedListener>> listeners = new HashMap<>(); private final Map<DeviceIdentifier, Set<GPSFixReceivedListener>> listeners = new HashMap<>();
@@ -56,7 +67,8 @@ public class MongoGPSFixStoreImpl implements MongoGPSFixStore {
fixServiceFinder = null; fixServiceFinder = null;
deviceServiceFinder = null; deviceServiceFinder = null;
} }
collection = mongoOF.getGPSFixCollection(); fixesCollection = mongoOF.getGPSFixCollection();
metadataCollection = mongoOF.getGPSFixMetadataCollection();
} }
private GPSFix loadGPSFix(DBObject object) throws TransformationException, NoCorrespondingServiceRegisteredException { private GPSFix loadGPSFix(DBObject object) throws TransformationException, NoCorrespondingServiceRegisteredException {
@@ -66,23 +78,18 @@ public class MongoGPSFixStoreImpl implements MongoGPSFixStore {
} }
private <FixT extends GPSFix> void loadTrack(DynamicGPSFixTrack<?, FixT> track, DeviceIdentifier device, private <FixT extends GPSFix> void loadTrack(DynamicGPSFixTrack<?, FixT> track, DeviceIdentifier device,
TimePoint from, TimePoint to, boolean inclusive) throws NoCorrespondingServiceRegisteredException { TimePoint from, TimePoint to, boolean inclusive) throws NoCorrespondingServiceRegisteredException,
TransformationException {
long fromMillis = from.asMillis() - (inclusive ? 1 : 0); long fromMillis = from.asMillis() - (inclusive ? 1 : 0);
long toMillis = to.asMillis() + (inclusive ? 1 : 0); long toMillis = to.asMillis() + (inclusive ? 1 : 0);
Object dbDeviceId = null; Object dbDeviceId = MongoObjectFactoryImpl.storeDeviceId(deviceServiceFinder, device);
try {
dbDeviceId = MongoObjectFactoryImpl.storeDeviceId(deviceServiceFinder, device);
} catch (TransformationException | NoCorrespondingServiceRegisteredException e) {
logger.log(Level.WARNING, "Could not serialize Device ID for MongoDB: " + e.getMessage());
return;
}
DBObject query = QueryBuilder.start(FieldNames.DEVICE_ID.name()).is(dbDeviceId) DBObject query = QueryBuilder.start(FieldNames.DEVICE_ID.name()).is(dbDeviceId)
.and(FieldNames.TIME_AS_MILLIS.name()).greaterThan(fromMillis) .and(FieldNames.TIME_AS_MILLIS.name()).greaterThan(fromMillis)
.and(FieldNames.TIME_AS_MILLIS.name()).lessThan(toMillis).get(); .and(FieldNames.TIME_AS_MILLIS.name()).lessThan(toMillis).get();
DBCursor result = collection.find(query); DBCursor result = fixesCollection.find(query);
for (DBObject fixObject : result) { for (DBObject fixObject : result) {
try { try {
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
@@ -98,7 +105,8 @@ public class MongoGPSFixStoreImpl implements MongoGPSFixStore {
} }
@Override @Override
public void loadCompetitorTrack(DynamicGPSFixTrack<Competitor, GPSFixMoving> track, RaceLog raceLog, Competitor competitor) { public void loadCompetitorTrack(DynamicGPSFixTrack<Competitor, GPSFixMoving> track, RaceLog raceLog, Competitor competitor)
throws NoCorrespondingServiceRegisteredException, TransformationException{
List<DeviceMapping<Competitor>> mappings = new DeviceCompetitorMappingFinder(raceLog).analyze().get(competitor); List<DeviceMapping<Competitor>> mappings = new DeviceCompetitorMappingFinder(raceLog).analyze().get(competitor);
if (mappings != null) { if (mappings != null) {
@@ -109,7 +117,8 @@ public class MongoGPSFixStoreImpl implements MongoGPSFixStore {
} }
@Override @Override
public void loadMarkTrack(DynamicGPSFixTrack<Mark, GPSFix> track, RaceLog raceLog, Mark mark) { public void loadMarkTrack(DynamicGPSFixTrack<Mark, GPSFix> track, RaceLog raceLog, Mark mark)
throws NoCorrespondingServiceRegisteredException, TransformationException{
List<DeviceMapping<Mark>> mappings = new DeviceMarkMappingFinder(raceLog).analyze().get(mark); List<DeviceMapping<Mark>> mappings = new DeviceMarkMappingFinder(raceLog).analyze().get(mark);
if (mappings != null) { if (mappings != null) {
@@ -129,7 +138,28 @@ public class MongoGPSFixStoreImpl implements MongoGPSFixStore {
.add(FieldNames.GPSFIX_TYPE.name(), type).add(FieldNames.GPSFIX.name(), fixObject).get(); .add(FieldNames.GPSFIX_TYPE.name(), type).add(FieldNames.GPSFIX.name(), fixObject).get();
mongoOF.storeTimed(fix, entry); mongoOF.storeTimed(fix, entry);
collection.insert(entry); fixesCollection.insert(entry);
TimeRange oldTimeRange = getTimeRangeCoveredByFixes(device);
long oldNumFixes = getNumberOfFixes(device);
DBObject newMetadata = new BasicDBObject();
newMetadata.put(FieldNames.DEVICE_ID.name(), MongoObjectFactoryImpl.storeDeviceId(deviceServiceFinder, device));
newMetadata.put(FieldNames.NUM_FIXES.name(), oldNumFixes + 1);
TimePoint newFrom = fix.getTimePoint();
TimePoint newTo = fix.getTimePoint();
if (oldTimeRange != null) {
if (oldTimeRange.from().before(newFrom)) {
newFrom = oldTimeRange.from();
}
if (oldTimeRange.to().after(newTo)) {
newTo = oldTimeRange.to();
}
}
MongoObjectFactoryImpl.storeTimeRange(new TimeRangeImpl(newFrom, newTo), newMetadata, FieldNames.TIMERANGE);
metadataCollection.update(getDeviceQuery(device), newMetadata, /*create if not existent*/ true,
/*update multiple*/ false);
} catch (TransformationException e) { } catch (TransformationException e) {
logger.log(Level.WARNING, "Could not store fix in MongoDB"); logger.log(Level.WARNING, "Could not store fix in MongoDB");
e.printStackTrace(); e.printStackTrace();
@@ -156,12 +186,47 @@ public class MongoGPSFixStoreImpl implements MongoGPSFixStore {
} }
@Override @Override
public void loadCompetitorTrack(DynamicGPSFixTrack<Competitor, GPSFixMoving> track, DeviceMapping<Competitor> mapping) { public void loadCompetitorTrack(DynamicGPSFixTrack<Competitor, GPSFixMoving> track, DeviceMapping<Competitor> mapping)
throws TransformationException, NoCorrespondingServiceRegisteredException {
loadTrack(track, mapping.getDevice(), mapping.getTimeRange().from(), mapping.getTimeRange().to(), true /*inclusive*/); loadTrack(track, mapping.getDevice(), mapping.getTimeRange().from(), mapping.getTimeRange().to(), true /*inclusive*/);
} }
@Override @Override
public void loadMarkTrack(DynamicGPSFixTrack<Mark, GPSFix> track, DeviceMapping<Mark> mapping) { public void loadMarkTrack(DynamicGPSFixTrack<Mark, GPSFix> track, DeviceMapping<Mark> mapping)
throws TransformationException, NoCorrespondingServiceRegisteredException {
loadTrack(track, mapping.getDevice(), mapping.getTimeRange().from(), mapping.getTimeRange().to(), true /*inclusive*/); loadTrack(track, mapping.getDevice(), mapping.getTimeRange().from(), mapping.getTimeRange().to(), true /*inclusive*/);
} }
private DBObject getDeviceQuery(DeviceIdentifier device)
throws TransformationException, NoCorrespondingServiceRegisteredException {
Object dbDeviceId = MongoObjectFactoryImpl.storeDeviceId(deviceServiceFinder, device);
DBObject query = QueryBuilder.start(FieldNames.DEVICE_ID.name()).is(dbDeviceId).get();
return query;
}
private DBObject findMetadataObject(DeviceIdentifier device)
throws TransformationException, NoCorrespondingServiceRegisteredException {
DBObject query = getDeviceQuery(device);
DBObject result = metadataCollection.findOne(query);
return result;
}
@Override
public TimeRange getTimeRangeCoveredByFixes(DeviceIdentifier device)
throws TransformationException, NoCorrespondingServiceRegisteredException {
DBObject result = findMetadataObject(device);
if (result == null) {
return null;
}
return DomainObjectFactoryImpl.loadTimeRange(result, FieldNames.TIMERANGE);
}
@Override
public long getNumberOfFixes(DeviceIdentifier device) throws TransformationException, NoCorrespondingServiceRegisteredException {
DBObject result = findMetadataObject(device);
if (result == null) {
return 0;
}
return ((Number) result.get(FieldNames.NUM_FIXES.name())).longValue();
}
} }
@@ -62,6 +62,7 @@ public class AbstractGPSFixStoreTest {
public void after() { public void after() {
MongoObjectFactoryImpl mongoOF = (MongoObjectFactoryImpl) service.getMongoObjectFactory(); MongoObjectFactoryImpl mongoOF = (MongoObjectFactoryImpl) service.getMongoObjectFactory();
mongoOF.getGPSFixCollection().drop(); mongoOF.getGPSFixCollection().drop();
mongoOF.getGPSFixMetadataCollection().drop();
} }
protected void map(Competitor comp, DeviceIdentifier device, long from, long to) { protected void map(Competitor comp, DeviceIdentifier device, long from, long to) {
@@ -1,5 +1,7 @@
package com.sap.sailing.domain.racelogtracking.test.impl; package com.sap.sailing.domain.racelogtracking.test.impl;
import static junit.framework.Assert.assertEquals;
import java.util.Arrays; import java.util.Arrays;
import java.util.Collections; import java.util.Collections;
@@ -18,6 +20,7 @@ import com.sap.sailing.domain.base.impl.CourseImpl;
import com.sap.sailing.domain.base.impl.RaceDefinitionImpl; import com.sap.sailing.domain.base.impl.RaceDefinitionImpl;
import com.sap.sailing.domain.base.impl.RegattaImpl; import com.sap.sailing.domain.base.impl.RegattaImpl;
import com.sap.sailing.domain.base.impl.WaypointImpl; import com.sap.sailing.domain.base.impl.WaypointImpl;
import com.sap.sailing.domain.common.impl.TimeRangeImpl;
import com.sap.sailing.domain.common.racelog.tracking.NoCorrespondingServiceRegisteredException; import com.sap.sailing.domain.common.racelog.tracking.NoCorrespondingServiceRegisteredException;
import com.sap.sailing.domain.common.racelog.tracking.TransformationException; import com.sap.sailing.domain.common.racelog.tracking.TransformationException;
import com.sap.sailing.domain.racelog.impl.EmptyRaceLogStore; import com.sap.sailing.domain.racelog.impl.EmptyRaceLogStore;
@@ -29,7 +32,7 @@ import com.sap.sailing.domain.tracking.impl.DynamicTrackedRaceImpl;
import com.sap.sailing.domain.tracking.impl.EmptyWindStore; import com.sap.sailing.domain.tracking.impl.EmptyWindStore;
import com.sap.sailing.domain.tracking.impl.TrackedRegattaImpl; import com.sap.sailing.domain.tracking.impl.TrackedRegattaImpl;
public class TrackedRaceLoadsFixesTest extends AbstractGPSFixStoreTest { public class TrackedRaceLoadsFixesTest extends AbstractGPSFixStoreTest {
@Test @Test
@Ignore @Ignore
public void areFixesStoredInDb() throws TransformationException, NoCorrespondingServiceRegisteredException, InterruptedException { public void areFixesStoredInDb() throws TransformationException, NoCorrespondingServiceRegisteredException, InterruptedException {
@@ -65,4 +68,18 @@ public class TrackedRaceLoadsFixesTest extends AbstractGPSFixStoreTest {
testLength(trackedRace.getOrCreateTrack(mark), 1); testLength(trackedRace.getOrCreateTrack(mark), 1);
testLength(trackedRace.getOrCreateTrack(mark2), 1); testLength(trackedRace.getOrCreateTrack(mark2), 1);
} }
@Test
public void metadataStoredInDb() throws TransformationException, NoCorrespondingServiceRegisteredException {
assertEquals(0, store.getNumberOfFixes(device));
assertEquals(null, store.getTimeRangeCoveredByFixes(device));
map(comp, device, 0, 600);
store.storeFix(device, createFix(100, 10, 20, 30, 40));
store.storeFix(device, createFix(200, 10, 20, 30, 40));
assertEquals(2, store.getNumberOfFixes(device));
assertEquals(TimeRangeImpl.create(100, 200), store.getTimeRangeCoveredByFixes(device));
}
} }
@@ -31,9 +31,11 @@ import com.sap.sailing.domain.common.TimePoint;
import com.sap.sailing.domain.common.TrackedRaceStatusEnum; import com.sap.sailing.domain.common.TrackedRaceStatusEnum;
import com.sap.sailing.domain.common.WithID; import com.sap.sailing.domain.common.WithID;
import com.sap.sailing.domain.common.impl.MillisecondsTimePoint; import com.sap.sailing.domain.common.impl.MillisecondsTimePoint;
import com.sap.sailing.domain.common.racelog.tracking.NoCorrespondingServiceRegisteredException;
import com.sap.sailing.domain.common.racelog.tracking.NotRevokableException; import com.sap.sailing.domain.common.racelog.tracking.NotRevokableException;
import com.sap.sailing.domain.common.racelog.tracking.RaceLogTrackingState; import com.sap.sailing.domain.common.racelog.tracking.RaceLogTrackingState;
import com.sap.sailing.domain.common.racelog.tracking.RaceNotCreatedException; import com.sap.sailing.domain.common.racelog.tracking.RaceNotCreatedException;
import com.sap.sailing.domain.common.racelog.tracking.TransformationException;
import com.sap.sailing.domain.markpassingcalculation.MarkPassingCalculator; import com.sap.sailing.domain.markpassingcalculation.MarkPassingCalculator;
import com.sap.sailing.domain.racelog.RaceLog; import com.sap.sailing.domain.racelog.RaceLog;
import com.sap.sailing.domain.racelog.RaceLogCourseDesignChangedEvent; import com.sap.sailing.domain.racelog.RaceLogCourseDesignChangedEvent;
@@ -258,7 +260,11 @@ public class RaceLogRaceTracker extends BaseRaceLogEventVisitor implements RaceT
if (oldMappings != null) { if (oldMappings != null) {
for (DeviceMapping<Mark> newMapping : newMappings.get(mark)) { for (DeviceMapping<Mark> newMapping : newMappings.get(mark)) {
if (!hasMappingAlreadyBeenLoaded(newMapping, oldMappings)) { if (!hasMappingAlreadyBeenLoaded(newMapping, oldMappings)) {
gpsFixStore.loadMarkTrack(track, newMapping); try {
gpsFixStore.loadMarkTrack(track, newMapping);
} catch (TransformationException | NoCorrespondingServiceRegisteredException e) {
logger.log(Level.WARNING, "Could not load mark track " + newMapping.getMappedTo());
}
} }
} }
} }
@@ -297,7 +303,11 @@ public class RaceLogRaceTracker extends BaseRaceLogEventVisitor implements RaceT
for (DeviceMapping<Competitor> newMapping : newMappings.get(competitor)) { for (DeviceMapping<Competitor> newMapping : newMappings.get(competitor)) {
if (!hasMappingAlreadyBeenLoaded(newMapping, oldMappings)) { if (!hasMappingAlreadyBeenLoaded(newMapping, oldMappings)) {
gpsFixStore.loadCompetitorTrack(track, newMapping); try {
gpsFixStore.loadCompetitorTrack(track, newMapping);
} catch (TransformationException | NoCorrespondingServiceRegisteredException e) {
logger.log(Level.WARNING, "Could not load competitor track " + newMapping.getMappedTo());
}
} }
} }
} }
@@ -25,11 +25,13 @@ import com.sap.sailing.domain.common.PassingInstruction;
import com.sap.sailing.domain.common.RegattaIdentifier; import com.sap.sailing.domain.common.RegattaIdentifier;
import com.sap.sailing.domain.common.TimePoint; import com.sap.sailing.domain.common.TimePoint;
import com.sap.sailing.domain.common.impl.MillisecondsTimePoint; import com.sap.sailing.domain.common.impl.MillisecondsTimePoint;
import com.sap.sailing.domain.common.racelog.tracking.NoCorrespondingServiceRegisteredException;
import com.sap.sailing.domain.common.racelog.tracking.NotDenotableForRaceLogTrackingException; import com.sap.sailing.domain.common.racelog.tracking.NotDenotableForRaceLogTrackingException;
import com.sap.sailing.domain.common.racelog.tracking.NotDenotedForRaceLogTrackingException; import com.sap.sailing.domain.common.racelog.tracking.NotDenotedForRaceLogTrackingException;
import com.sap.sailing.domain.common.racelog.tracking.NotRevokableException; import com.sap.sailing.domain.common.racelog.tracking.NotRevokableException;
import com.sap.sailing.domain.common.racelog.tracking.RaceLogRaceTrackerExistsException; import com.sap.sailing.domain.common.racelog.tracking.RaceLogRaceTrackerExistsException;
import com.sap.sailing.domain.common.racelog.tracking.RaceLogTrackingState; import com.sap.sailing.domain.common.racelog.tracking.RaceLogTrackingState;
import com.sap.sailing.domain.common.racelog.tracking.TransformationException;
import com.sap.sailing.domain.leaderboard.FlexibleLeaderboard; import com.sap.sailing.domain.leaderboard.FlexibleLeaderboard;
import com.sap.sailing.domain.leaderboard.Leaderboard; import com.sap.sailing.domain.leaderboard.Leaderboard;
import com.sap.sailing.domain.leaderboard.RegattaLeaderboard; import com.sap.sailing.domain.leaderboard.RegattaLeaderboard;
@@ -250,7 +252,11 @@ public class RaceLogTrackingAdapterImpl implements RaceLogTrackingAdapter {
RaceLogEvent mapping = RaceLogEventFactory.INSTANCE.createDeviceMarkMappingEvent(time, RaceLogEvent mapping = RaceLogEventFactory.INSTANCE.createDeviceMarkMappingEvent(time,
service.getServerAuthor(), device, mark, raceLog.getCurrentPassId(), time, time); service.getServerAuthor(), device, mark, raceLog.getCurrentPassId(), time, time);
raceLog.add(mapping); raceLog.add(mapping);
service.getGPSFixStore().storeFix(device, gpsFix); try {
service.getGPSFixStore().storeFix(device, gpsFix);
} catch (TransformationException | NoCorrespondingServiceRegisteredException e) {
logger.log(Level.WARNING, "Could not pint mark " + mark);
}
} }
@Override @Override
@@ -3,10 +3,13 @@ package com.sap.sailing.domain.racelogtracking.servlet;
import java.io.Serializable; import java.io.Serializable;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.logging.Level;
import javax.servlet.ServletConfig; import javax.servlet.ServletConfig;
import javax.servlet.ServletException; import javax.servlet.ServletException;
import com.sap.sailing.domain.common.racelog.tracking.NoCorrespondingServiceRegisteredException;
import com.sap.sailing.domain.common.racelog.tracking.TransformationException;
import com.sap.sailing.domain.common.racelog.tracking.TypeBasedServiceFinder; import com.sap.sailing.domain.common.racelog.tracking.TypeBasedServiceFinder;
import com.sap.sailing.domain.racelog.tracking.DeviceIdentifier; import com.sap.sailing.domain.racelog.tracking.DeviceIdentifier;
import com.sap.sailing.domain.tracking.GPSFix; import com.sap.sailing.domain.tracking.GPSFix;
@@ -55,7 +58,11 @@ public class RecordFixesPostServlet extends
List<GPSFix> fixes = domainObject.getC(); List<GPSFix> fixes = domainObject.getC();
for (GPSFix fix : fixes) { for (GPSFix fix : fixes) {
getService().getGPSFixStore().storeFix(device, fix); try {
getService().getGPSFixStore().storeFix(device, fix);
} catch (TransformationException | NoCorrespondingServiceRegisteredException e) {
logger.log(Level.WARNING, "Could not load store fix from device " + device);
}
} }
return null; return null;
@@ -2,6 +2,7 @@ package com.sap.sailing.domain.racelog.tracking;
import com.sap.sailing.domain.base.Competitor; import com.sap.sailing.domain.base.Competitor;
import com.sap.sailing.domain.base.Mark; import com.sap.sailing.domain.base.Mark;
import com.sap.sailing.domain.common.TimeRange;
import com.sap.sailing.domain.racelog.RaceLog; import com.sap.sailing.domain.racelog.RaceLog;
import com.sap.sailing.domain.tracking.DynamicGPSFixTrack; import com.sap.sailing.domain.tracking.DynamicGPSFixTrack;
import com.sap.sailing.domain.tracking.GPSFix; import com.sap.sailing.domain.tracking.GPSFix;
@@ -44,4 +45,14 @@ public enum EmptyGPSFixStore implements GPSFixStore {
DeviceMapping<Mark> mapping) { DeviceMapping<Mark> mapping) {
} }
@Override
public TimeRange getTimeRangeCoveredByFixes(DeviceIdentifier device) {
return null;
}
@Override
public long getNumberOfFixes(DeviceIdentifier device) {
return 0;
}
} }
@@ -2,6 +2,9 @@ package com.sap.sailing.domain.racelog.tracking;
import com.sap.sailing.domain.base.Competitor; import com.sap.sailing.domain.base.Competitor;
import com.sap.sailing.domain.base.Mark; import com.sap.sailing.domain.base.Mark;
import com.sap.sailing.domain.common.TimeRange;
import com.sap.sailing.domain.common.racelog.tracking.NoCorrespondingServiceRegisteredException;
import com.sap.sailing.domain.common.racelog.tracking.TransformationException;
import com.sap.sailing.domain.racelog.RaceLog; import com.sap.sailing.domain.racelog.RaceLog;
import com.sap.sailing.domain.tracking.DynamicGPSFixTrack; import com.sap.sailing.domain.tracking.DynamicGPSFixTrack;
import com.sap.sailing.domain.tracking.GPSFix; import com.sap.sailing.domain.tracking.GPSFix;
@@ -13,24 +16,27 @@ public interface GPSFixStore {
* Load all fixes that correspond to the {@link DeviceCompetitorMappingEvent}s found in the {@code raceLog}. * Load all fixes that correspond to the {@link DeviceCompetitorMappingEvent}s found in the {@code raceLog}.
*/ */
void loadCompetitorTrack(DynamicGPSFixTrack<Competitor, GPSFixMoving> track, RaceLog raceLog, void loadCompetitorTrack(DynamicGPSFixTrack<Competitor, GPSFixMoving> track, RaceLog raceLog,
Competitor competitor); Competitor competitor) throws TransformationException;
/** /**
* Load all fixes that correspond to the {@link DeviceMarkMappingEvent}s found in the {@code raceLog}. * Load all fixes that correspond to the {@link DeviceMarkMappingEvent}s found in the {@code raceLog}.
*/ */
void loadMarkTrack(DynamicGPSFixTrack<Mark, GPSFix> track, RaceLog raceLog, Mark mark); void loadMarkTrack(DynamicGPSFixTrack<Mark, GPSFix> track, RaceLog raceLog, Mark mark) throws TransformationException,
NoCorrespondingServiceRegisteredException;
/** /**
* Load all fixes that correspond to the {@code mapping}. * Load all fixes that correspond to the {@code mapping}.
*/ */
void loadCompetitorTrack(DynamicGPSFixTrack<Competitor, GPSFixMoving> track, DeviceMapping<Competitor> mapping); void loadCompetitorTrack(DynamicGPSFixTrack<Competitor, GPSFixMoving> track, DeviceMapping<Competitor> mapping)
throws TransformationException, NoCorrespondingServiceRegisteredException;
/** /**
* Load all fixes that correspond to the {@code mapping}. * Load all fixes that correspond to the {@code mapping}.
*/ */
void loadMarkTrack(DynamicGPSFixTrack<Mark, GPSFix> track, DeviceMapping<Mark> mapping); void loadMarkTrack(DynamicGPSFixTrack<Mark, GPSFix> track, DeviceMapping<Mark> mapping) throws TransformationException,
NoCorrespondingServiceRegisteredException;
void storeFix(DeviceIdentifier device, GPSFix fix); void storeFix(DeviceIdentifier device, GPSFix fix) throws TransformationException, NoCorrespondingServiceRegisteredException;
/** /**
* Listeners are notified, whenever a {@link GPSFix} submitted by the {@code device} * Listeners are notified, whenever a {@link GPSFix} submitted by the {@code device}
@@ -42,4 +48,9 @@ public interface GPSFixStore {
* Remove the registrations of the listener for all devices. * Remove the registrations of the listener for all devices.
*/ */
void removeListener(GPSFixReceivedListener listener); void removeListener(GPSFixReceivedListener listener);
TimeRange getTimeRangeCoveredByFixes(DeviceIdentifier device) throws TransformationException,
NoCorrespondingServiceRegisteredException;
long getNumberOfFixes(DeviceIdentifier device) throws TransformationException, NoCorrespondingServiceRegisteredException;
} }
@@ -5,6 +5,7 @@ import java.io.InputStream;
import java.util.Map; import java.util.Map;
import com.sap.sailing.domain.racelog.tracking.DeviceIdentifier; import com.sap.sailing.domain.racelog.tracking.DeviceIdentifier;
import com.sap.sailing.domain.trackfiles.TrackFileImportDeviceIdentifier;
import com.sap.sailing.domain.tracking.GPSFix; import com.sap.sailing.domain.tracking.GPSFix;
/** /**
@@ -38,7 +39,7 @@ public interface GPSFixImporter {
* *
*/ */
interface Callback { interface Callback {
void addFix(GPSFix fix, DeviceIdentifier device); void addFix(GPSFix fix, TrackFileImportDeviceIdentifier device);
} }
/** /**
@@ -72,6 +72,8 @@ import com.sap.sailing.domain.common.impl.KnotSpeedWithBearingImpl;
import com.sap.sailing.domain.common.impl.MillisecondsTimePoint; import com.sap.sailing.domain.common.impl.MillisecondsTimePoint;
import com.sap.sailing.domain.common.impl.NauticalMileDistance; import com.sap.sailing.domain.common.impl.NauticalMileDistance;
import com.sap.sailing.domain.common.impl.WindSourceImpl; import com.sap.sailing.domain.common.impl.WindSourceImpl;
import com.sap.sailing.domain.common.racelog.tracking.NoCorrespondingServiceRegisteredException;
import com.sap.sailing.domain.common.racelog.tracking.TransformationException;
import com.sap.sailing.domain.confidence.ConfidenceBasedWindAverager; import com.sap.sailing.domain.confidence.ConfidenceBasedWindAverager;
import com.sap.sailing.domain.confidence.ConfidenceFactory; import com.sap.sailing.domain.confidence.ConfidenceFactory;
import com.sap.sailing.domain.confidence.HasConfidence; import com.sap.sailing.domain.confidence.HasConfidence;
@@ -2473,15 +2475,23 @@ public abstract class TrackedRaceImpl extends TrackedRaceWithWindEssentials impl
try { try {
logger.info("Started loading competitor tracks for " + getRace().getName()); logger.info("Started loading competitor tracks for " + getRace().getName());
for (Competitor competitor : race.getCompetitors()) { for (Competitor competitor : race.getCompetitors()) {
gpsFixStore.loadCompetitorTrack( try {
(DynamicGPSFixTrack<Competitor, GPSFixMoving>) tracks.get(competitor), raceLog, gpsFixStore.loadCompetitorTrack(
competitor); (DynamicGPSFixTrack<Competitor, GPSFixMoving>) tracks.get(competitor), raceLog,
competitor);
} catch (TransformationException | NoCorrespondingServiceRegisteredException e) {
logger.log(Level.WARNING, "Could not load track for " + competitor);
}
} }
logger.info("Finished loading competitor tracks for " + getRace().getName()); logger.info("Finished loading competitor tracks for " + getRace().getName());
logger.info("Started loading mark tracks for " + getRace().getName()); logger.info("Started loading mark tracks for " + getRace().getName());
for (Mark mark : getMarks()) { for (Mark mark : getMarks()) {
gpsFixStore.loadMarkTrack((DynamicGPSFixTrack<Mark, GPSFix>) markTracks.get(mark), raceLog, try {
mark); gpsFixStore.loadMarkTrack((DynamicGPSFixTrack<Mark, GPSFix>) markTracks.get(mark), raceLog,
mark);
} catch (TransformationException | NoCorrespondingServiceRegisteredException e) {
logger.log(Level.WARNING, "Could not load track for " + mark);
}
} }
logger.info("Finished loading mark tracks for " + getRace().getName()); logger.info("Finished loading mark tracks for " + getRace().getName());
@@ -15,13 +15,13 @@ import com.google.gwt.user.client.ui.Widget;
import com.google.gwt.view.client.SelectionChangeEvent; import com.google.gwt.view.client.SelectionChangeEvent;
import com.google.gwt.view.client.SingleSelectionModel; import com.google.gwt.view.client.SingleSelectionModel;
import com.sap.sailing.domain.common.dto.CompetitorDTO; import com.sap.sailing.domain.common.dto.CompetitorDTO;
import com.sap.sailing.gwt.ui.adminconsole.TrackFileImportDeviceIdentifierTableWrapper.TrackFileImportDeviceIdentifier;
import com.sap.sailing.gwt.ui.client.ErrorReporter; import com.sap.sailing.gwt.ui.client.ErrorReporter;
import com.sap.sailing.gwt.ui.client.SailingServiceAsync; import com.sap.sailing.gwt.ui.client.SailingServiceAsync;
import com.sap.sailing.gwt.ui.client.StringMessages; import com.sap.sailing.gwt.ui.client.StringMessages;
import com.sap.sailing.gwt.ui.shared.DeviceIdentifierDTO; import com.sap.sailing.gwt.ui.shared.DeviceIdentifierDTO;
import com.sap.sailing.gwt.ui.shared.DeviceMappingDTO; import com.sap.sailing.gwt.ui.shared.DeviceMappingDTO;
import com.sap.sailing.gwt.ui.shared.MarkDTO; import com.sap.sailing.gwt.ui.shared.MarkDTO;
import com.sap.sailing.gwt.ui.shared.TrackFileImportDeviceIdentifierDTO;
import com.sap.sse.gwt.client.dialog.DataEntryDialog; import com.sap.sse.gwt.client.dialog.DataEntryDialog;
public class ImportFixesAndAddMappingsDialog extends DataEntryDialog<Collection<DeviceMappingDTO>> { public class ImportFixesAndAddMappingsDialog extends DataEntryDialog<Collection<DeviceMappingDTO>> {
@@ -31,9 +31,9 @@ public class ImportFixesAndAddMappingsDialog extends DataEntryDialog<Collection<
private final MarkTableWrapper<SingleSelectionModel<MarkDTO>> markTable; private final MarkTableWrapper<SingleSelectionModel<MarkDTO>> markTable;
private final StringMessages stringMessages; private final StringMessages stringMessages;
private final Map<TrackFileImportDeviceIdentifier, Serializable> mappings = new HashMap<>(); private final Map<TrackFileImportDeviceIdentifierDTO, Serializable> mappings = new HashMap<>();
private TrackFileImportDeviceIdentifier deviceToSelect; private TrackFileImportDeviceIdentifierDTO deviceToSelect;
private CompetitorDTO compToSelect; private CompetitorDTO compToSelect;
private MarkDTO markToSelect; private MarkDTO markToSelect;
private boolean inInstableTransitionState = false; private boolean inInstableTransitionState = false;
@@ -132,7 +132,7 @@ public class ImportFixesAndAddMappingsDialog extends DataEntryDialog<Collection<
private void mappedToSelectionChanged(Serializable mappedTo) { private void mappedToSelectionChanged(Serializable mappedTo) {
if (! inInstableTransitionState) { if (! inInstableTransitionState) {
TrackFileImportDeviceIdentifier device = deviceIdTable.getSelectionModel().getSelectedObject(); TrackFileImportDeviceIdentifierDTO device = deviceIdTable.getSelectionModel().getSelectedObject();
if (device != null) { if (device != null) {
mappings.put(device, mappedTo); mappings.put(device, mappedTo);
} }
@@ -148,7 +148,7 @@ public class ImportFixesAndAddMappingsDialog extends DataEntryDialog<Collection<
select(); select();
} }
private void deviceSelectionChanged(TrackFileImportDeviceIdentifier deviceId) { private void deviceSelectionChanged(TrackFileImportDeviceIdentifierDTO deviceId) {
if (! inInstableTransitionState) { if (! inInstableTransitionState) {
deviceToSelect = deviceId; deviceToSelect = deviceId;
compToSelect = null; compToSelect = null;
@@ -190,8 +190,8 @@ public class ImportFixesAndAddMappingsDialog extends DataEntryDialog<Collection<
@Override @Override
protected Collection<DeviceMappingDTO> getResult() { protected Collection<DeviceMappingDTO> getResult() {
List<DeviceMappingDTO> result = new ArrayList<>(); List<DeviceMappingDTO> result = new ArrayList<>();
for (TrackFileImportDeviceIdentifier device : mappings.keySet()) { for (TrackFileImportDeviceIdentifierDTO device : mappings.keySet()) {
DeviceIdentifierDTO deviceIdDto = new DeviceIdentifierDTO("FILE", device.uuid); DeviceIdentifierDTO deviceIdDto = new DeviceIdentifierDTO("FILE", device.uuidAsString);
Serializable mappedTo = mappings.get(device); Serializable mappedTo = mappings.get(device);
DeviceMappingDTO mapping = new DeviceMappingDTO(deviceIdDto, device.from, device.to, DeviceMappingDTO mapping = new DeviceMappingDTO(deviceIdDto, device.from, device.to,
mappedTo, null); mappedTo, null);
@@ -1,77 +1,68 @@
package com.sap.sailing.gwt.ui.adminconsole; package com.sap.sailing.gwt.ui.adminconsole;
import java.util.Date;
import com.google.gwt.user.cellview.client.TextColumn; import com.google.gwt.user.cellview.client.TextColumn;
import com.google.gwt.view.client.SingleSelectionModel; import com.google.gwt.view.client.SingleSelectionModel;
import com.sap.sailing.gwt.ui.adminconsole.TrackFileImportDeviceIdentifierTableWrapper.TrackFileImportDeviceIdentifier;
import com.sap.sailing.gwt.ui.client.ErrorReporter; import com.sap.sailing.gwt.ui.client.ErrorReporter;
import com.sap.sailing.gwt.ui.client.SailingServiceAsync; import com.sap.sailing.gwt.ui.client.SailingServiceAsync;
import com.sap.sailing.gwt.ui.client.StringMessages; import com.sap.sailing.gwt.ui.client.StringMessages;
import com.sap.sailing.gwt.ui.common.client.DateAndTimeFormatterUtil;
import com.sap.sailing.gwt.ui.shared.TrackFileImportDeviceIdentifierDTO;
public class TrackFileImportDeviceIdentifierTableWrapper extends TableWrapper<TrackFileImportDeviceIdentifier, SingleSelectionModel<TrackFileImportDeviceIdentifier>> { public class TrackFileImportDeviceIdentifierTableWrapper extends TableWrapper<TrackFileImportDeviceIdentifierDTO,
public static class TrackFileImportDeviceIdentifier { SingleSelectionModel<TrackFileImportDeviceIdentifierDTO>> {
public String uuid;
public String fileName;
public String trackName;
public Date from;
public Date to;
public long numberOfFixes;
public TrackFileImportDeviceIdentifier(String uuid, String fileName, String trackName, Date from, Date to, long numberOfFixes) {
this.fileName = fileName;
this.trackName = trackName;
this.from = from;
this.to = to;
this.numberOfFixes = numberOfFixes;
this.uuid = uuid;
}
}
public TrackFileImportDeviceIdentifierTableWrapper(SailingServiceAsync sailingService, StringMessages stringMessages, public TrackFileImportDeviceIdentifierTableWrapper(SailingServiceAsync sailingService, StringMessages stringMessages,
ErrorReporter errorReporter) { ErrorReporter errorReporter) {
super(sailingService, stringMessages, errorReporter, new SingleSelectionModel<TrackFileImportDeviceIdentifier>()); super(sailingService, stringMessages, errorReporter, new SingleSelectionModel<TrackFileImportDeviceIdentifierDTO>());
TextColumn<TrackFileImportDeviceIdentifier> fileNameColumn = new TextColumn<TrackFileImportDeviceIdentifier>() { TextColumn<TrackFileImportDeviceIdentifierDTO> uuidColumn = new TextColumn<TrackFileImportDeviceIdentifierDTO>() {
@Override @Override
public String getValue(TrackFileImportDeviceIdentifier object) { public String getValue(TrackFileImportDeviceIdentifierDTO object) {
return object.uuidAsString;
}
};
TextColumn<TrackFileImportDeviceIdentifierDTO> fileNameColumn = new TextColumn<TrackFileImportDeviceIdentifierDTO>() {
@Override
public String getValue(TrackFileImportDeviceIdentifierDTO object) {
return object.fileName; return object.fileName;
} }
}; };
TextColumn<TrackFileImportDeviceIdentifier> trackNameColumn = new TextColumn<TrackFileImportDeviceIdentifier>() { TextColumn<TrackFileImportDeviceIdentifierDTO> trackNameColumn = new TextColumn<TrackFileImportDeviceIdentifierDTO>() {
@Override @Override
public String getValue(TrackFileImportDeviceIdentifier object) { public String getValue(TrackFileImportDeviceIdentifierDTO object) {
return object.trackName; return object.trackName;
} }
}; };
// TextColumn<TrackFileImportDeviceIdentifier> fromColumn = new TextColumn<TrackFileImportDeviceIdentifier>() { TextColumn<TrackFileImportDeviceIdentifierDTO> fromColumn = new TextColumn<TrackFileImportDeviceIdentifierDTO>() {
// @Override @Override
// public String getValue(TrackFileImportDeviceIdentifier object) { public String getValue(TrackFileImportDeviceIdentifierDTO object) {
// return DateAndTimeFormatterUtil.formatDateAndTime(object.from); return DateAndTimeFormatterUtil.formatDateAndTime(object.from);
// } }
// }; };
//
// TextColumn<TrackFileImportDeviceIdentifier> toColumn = new TextColumn<TrackFileImportDeviceIdentifier>() {
// @Override
// public String getValue(TrackFileImportDeviceIdentifier object) {
// return DateAndTimeFormatterUtil.formatDateAndTime(object.to);
// }
// };
//
// TextColumn<TrackFileImportDeviceIdentifier> numberOfFixesColumn = new TextColumn<TrackFileImportDeviceIdentifier>() {
// @Override
// public String getValue(TrackFileImportDeviceIdentifier object) {
// return "" + object.numberOfFixes;
// }
// };
TextColumn<TrackFileImportDeviceIdentifierDTO> toColumn = new TextColumn<TrackFileImportDeviceIdentifierDTO>() {
@Override
public String getValue(TrackFileImportDeviceIdentifierDTO object) {
return DateAndTimeFormatterUtil.formatDateAndTime(object.to);
}
};
TextColumn<TrackFileImportDeviceIdentifierDTO> numberOfFixesColumn = new TextColumn<TrackFileImportDeviceIdentifierDTO>() {
@Override
public String getValue(TrackFileImportDeviceIdentifierDTO object) {
return "" + object.numFixes;
}
};
table.addColumn(uuidColumn, "UUID");
table.addColumn(fileNameColumn, "Filename"); table.addColumn(fileNameColumn, "Filename");
table.addColumn(trackNameColumn, "Trackname"); table.addColumn(trackNameColumn, "Trackname");
// table.addColumn(fromColumn, stringMessages.from()); table.addColumn(fromColumn, stringMessages.from());
// table.addColumn(toColumn, stringMessages.to()); table.addColumn(toColumn, stringMessages.to());
// table.addColumn(numberOfFixesColumn, "# fixes"); table.addColumn(numberOfFixesColumn, "# fixes");
} }
} }
@@ -1,13 +1,11 @@
package com.sap.sailing.gwt.ui.adminconsole; package com.sap.sailing.gwt.ui.adminconsole;
import java.util.Arrays;
import java.util.Collection; import java.util.Collection;
import java.util.Date; import java.util.List;
import com.google.gwt.event.dom.client.ClickEvent; import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler; import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.json.client.JSONArray;
import com.google.gwt.json.client.JSONObject;
import com.google.gwt.json.client.JSONParser;
import com.google.gwt.user.client.rpc.AsyncCallback; import com.google.gwt.user.client.rpc.AsyncCallback;
import com.google.gwt.user.client.ui.Button; import com.google.gwt.user.client.ui.Button;
import com.google.gwt.user.client.ui.FileUpload; import com.google.gwt.user.client.ui.FileUpload;
@@ -20,33 +18,36 @@ import com.google.gwt.user.client.ui.ListBox;
import com.google.gwt.user.client.ui.Panel; import com.google.gwt.user.client.ui.Panel;
import com.google.gwt.user.client.ui.VerticalPanel; import com.google.gwt.user.client.ui.VerticalPanel;
import com.google.gwt.user.client.ui.Widget; import com.google.gwt.user.client.ui.Widget;
import com.sap.sailing.gwt.ui.adminconsole.TrackFileImportDeviceIdentifierTableWrapper.TrackFileImportDeviceIdentifier;
import com.sap.sailing.gwt.ui.client.ErrorReporter; import com.sap.sailing.gwt.ui.client.ErrorReporter;
import com.sap.sailing.gwt.ui.client.SailingServiceAsync; import com.sap.sailing.gwt.ui.client.SailingServiceAsync;
import com.sap.sailing.gwt.ui.client.StringMessages; import com.sap.sailing.gwt.ui.client.StringMessages;
import com.sap.sailing.gwt.ui.shared.TrackFileImportDeviceIdentifierDTO;
public class TrackFileImportWidget implements IsWidget { public class TrackFileImportWidget implements IsWidget {
private final Panel mainPanel = new VerticalPanel(); private final Panel mainPanel = new VerticalPanel();
public TrackFileImportWidget(final TrackFileImportDeviceIdentifierTableWrapper table, StringMessages stringMessages, public TrackFileImportWidget(final TrackFileImportDeviceIdentifierTableWrapper table, StringMessages stringMessages,
SailingServiceAsync sailingService, ErrorReporter errorReporter) { final SailingServiceAsync sailingService, final ErrorReporter errorReporter) {
this(new SubmitCompleteHandler() { this(new SubmitCompleteHandler() {
@Override @Override
public void onSubmitComplete(SubmitCompleteEvent event) { public void onSubmitComplete(SubmitCompleteEvent event) {
JSONArray json = JSONParser.parseLenient(event.getResults()).isArray();
table.getDataProvider().getList().clear(); table.getDataProvider().getList().clear();
for (int i=0; i<json.size(); i++) {
JSONObject obj = json.get(i).isObject(); String[] uuids = event.getResults().split("\\n");
JSONObject deviceIdJson = obj.get("id").isObject(); sailingService.getTrackFileImportDeviceIds(Arrays.asList(uuids),
String uuid = deviceIdJson.get("UUID").isString().stringValue(); new AsyncCallback<List<TrackFileImportDeviceIdentifierDTO>>() {
String fileName = deviceIdJson.get("FILE_NAME").isString().stringValue();
String trackName = deviceIdJson.get("TRACK_NAME").isString().stringValue(); @Override
long fromMillis = (long) obj.get("FROM_MILLIS").isNumber().doubleValue(); public void onSuccess(List<TrackFileImportDeviceIdentifierDTO> result) {
long toMillis = (long) obj.get("TO_MILLIS").isNumber().doubleValue(); table.getDataProvider().getList().addAll(result);
TrackFileImportDeviceIdentifier deviceId = new TrackFileImportDeviceIdentifier(uuid, fileName, }
trackName, new Date(fromMillis), new Date(toMillis), /* number of fixes */ 0);
table.getDataProvider().getList().add(deviceId); @Override
} public void onFailure(Throwable caught) {
errorReporter.reportError("Could not load TrackFileImportDeviceIds: " + caught.getMessage());
}
});
} }
}, stringMessages, sailingService, errorReporter); }, stringMessages, sailingService, errorReporter);
} }
@@ -77,6 +77,7 @@ import com.sap.sailing.gwt.ui.shared.SwissTimingRaceRecordDTO;
import com.sap.sailing.gwt.ui.shared.SwissTimingReplayRaceDTO; import com.sap.sailing.gwt.ui.shared.SwissTimingReplayRaceDTO;
import com.sap.sailing.gwt.ui.shared.TracTracConfigurationDTO; import com.sap.sailing.gwt.ui.shared.TracTracConfigurationDTO;
import com.sap.sailing.gwt.ui.shared.TracTracRaceRecordDTO; import com.sap.sailing.gwt.ui.shared.TracTracRaceRecordDTO;
import com.sap.sailing.gwt.ui.shared.TrackFileImportDeviceIdentifierDTO;
import com.sap.sailing.gwt.ui.shared.VenueDTO; import com.sap.sailing.gwt.ui.shared.VenueDTO;
import com.sap.sailing.gwt.ui.shared.WindDTO; import com.sap.sailing.gwt.ui.shared.WindDTO;
import com.sap.sailing.gwt.ui.shared.WindInfoForRaceDTO; import com.sap.sailing.gwt.ui.shared.WindInfoForRaceDTO;
@@ -476,5 +477,8 @@ public interface SailingService extends RemoteService {
void revokeRaceLogEvents(String leaderboardName, String raceColumnName, String fleetName, List<Serializable> eventIds) void revokeRaceLogEvents(String leaderboardName, String raceColumnName, String fleetName, List<Serializable> eventIds)
throws NotRevokableException; throws NotRevokableException;
Collection<String> getGPSFixImporterTypes(); Collection<String> getGPSFixImporterTypes();
List<TrackFileImportDeviceIdentifierDTO> getTrackFileImportDeviceIds(List<String> uuids)
throws NoCorrespondingServiceRegisteredException, TransformationException;
} }
@@ -68,6 +68,7 @@ import com.sap.sailing.gwt.ui.shared.SwissTimingRaceRecordDTO;
import com.sap.sailing.gwt.ui.shared.SwissTimingReplayRaceDTO; import com.sap.sailing.gwt.ui.shared.SwissTimingReplayRaceDTO;
import com.sap.sailing.gwt.ui.shared.TracTracConfigurationDTO; import com.sap.sailing.gwt.ui.shared.TracTracConfigurationDTO;
import com.sap.sailing.gwt.ui.shared.TracTracRaceRecordDTO; import com.sap.sailing.gwt.ui.shared.TracTracRaceRecordDTO;
import com.sap.sailing.gwt.ui.shared.TrackFileImportDeviceIdentifierDTO;
import com.sap.sailing.gwt.ui.shared.VenueDTO; import com.sap.sailing.gwt.ui.shared.VenueDTO;
import com.sap.sailing.gwt.ui.shared.WindDTO; import com.sap.sailing.gwt.ui.shared.WindDTO;
import com.sap.sailing.gwt.ui.shared.WindInfoForRaceDTO; import com.sap.sailing.gwt.ui.shared.WindInfoForRaceDTO;
@@ -595,4 +596,6 @@ public interface SailingServiceAsync {
Set<Util.Triple<String, String, String>> raceLogsTo, AsyncCallback<Void> callback); Set<Util.Triple<String, String, String>> raceLogsTo, AsyncCallback<Void> callback);
void getGPSFixImporterTypes(AsyncCallback<Collection<String>> callback); void getGPSFixImporterTypes(AsyncCallback<Collection<String>> callback);
void getTrackFileImportDeviceIds(List<String> uuids, AsyncCallback<List<TrackFileImportDeviceIdentifierDTO>> callback);
} }
@@ -222,6 +222,8 @@ import com.sap.sailing.domain.swisstimingadapter.persistence.SwissTimingAdapterP
import com.sap.sailing.domain.swisstimingreplayadapter.SwissTimingReplayRace; import com.sap.sailing.domain.swisstimingreplayadapter.SwissTimingReplayRace;
import com.sap.sailing.domain.swisstimingreplayadapter.SwissTimingReplayService; import com.sap.sailing.domain.swisstimingreplayadapter.SwissTimingReplayService;
import com.sap.sailing.domain.swisstimingreplayadapter.SwissTimingReplayServiceFactory; import com.sap.sailing.domain.swisstimingreplayadapter.SwissTimingReplayServiceFactory;
import com.sap.sailing.domain.trackfiles.TrackFileImportDeviceIdentifier;
import com.sap.sailing.domain.trackfiles.TrackFileImportDeviceIdentifierImpl;
import com.sap.sailing.domain.trackimport.GPSFixImporter; import com.sap.sailing.domain.trackimport.GPSFixImporter;
import com.sap.sailing.domain.tracking.DynamicTrackedRace; import com.sap.sailing.domain.tracking.DynamicTrackedRace;
import com.sap.sailing.domain.tracking.DynamicTrackedRegatta; import com.sap.sailing.domain.tracking.DynamicTrackedRegatta;
@@ -306,6 +308,7 @@ import com.sap.sailing.gwt.ui.shared.SwissTimingRaceRecordDTO;
import com.sap.sailing.gwt.ui.shared.SwissTimingReplayRaceDTO; import com.sap.sailing.gwt.ui.shared.SwissTimingReplayRaceDTO;
import com.sap.sailing.gwt.ui.shared.TracTracConfigurationDTO; import com.sap.sailing.gwt.ui.shared.TracTracConfigurationDTO;
import com.sap.sailing.gwt.ui.shared.TracTracRaceRecordDTO; import com.sap.sailing.gwt.ui.shared.TracTracRaceRecordDTO;
import com.sap.sailing.gwt.ui.shared.TrackFileImportDeviceIdentifierDTO;
import com.sap.sailing.gwt.ui.shared.VenueDTO; import com.sap.sailing.gwt.ui.shared.VenueDTO;
import com.sap.sailing.gwt.ui.shared.WaypointDTO; import com.sap.sailing.gwt.ui.shared.WaypointDTO;
import com.sap.sailing.gwt.ui.shared.WindDTO; import com.sap.sailing.gwt.ui.shared.WindDTO;
@@ -4321,7 +4324,11 @@ public class SailingServiceImpl extends ProxiedRemoteServiceServlet implements S
DynamicGPSFixTrackImpl<Mark> track = new DynamicGPSFixTrackImpl<Mark>(mark, 0); DynamicGPSFixTrackImpl<Mark> track = new DynamicGPSFixTrackImpl<Mark>(mark, 0);
DeviceMappingEvent<Mark> lastPingMappingEvent = new LastPingMappingEventFinder<Mark>(raceLog, mark).analyze(); DeviceMappingEvent<Mark> lastPingMappingEvent = new LastPingMappingEventFinder<Mark>(raceLog, mark).analyze();
if (lastPingMappingEvent != null) { if (lastPingMappingEvent != null) {
getService().getGPSFixStore().loadMarkTrack(track, DeviceMappingImpl.convertToDeviceMapping(lastPingMappingEvent)); try {
getService().getGPSFixStore().loadMarkTrack(track, DeviceMappingImpl.convertToDeviceMapping(lastPingMappingEvent));
} catch (TransformationException | NoCorrespondingServiceRegisteredException e) {
logger.log(Level.WARNING, "Could not convert to Mark DTO: " + mark);
}
} }
Position lastPos = track.getLastRawFix() == null ? null : track.getLastRawFix().getPosition(); Position lastPos = track.getLastRawFix() == null ? null : track.getLastRawFix().getPosition();
dtos.add(convertToMarkDTO(mark, lastPos)); dtos.add(convertToMarkDTO(mark, lastPos));
@@ -4601,4 +4608,21 @@ public class SailingServiceImpl extends ProxiedRemoteServiceServlet implements S
} }
return result; return result;
} }
@Override
public List<TrackFileImportDeviceIdentifierDTO> getTrackFileImportDeviceIds(List<String> uuids)
throws NoCorrespondingServiceRegisteredException, TransformationException {
List<TrackFileImportDeviceIdentifierDTO> result = new ArrayList<>();
for (String uuidAsString : uuids) {
UUID uuid = UUID.fromString(uuidAsString);
TrackFileImportDeviceIdentifier device = TrackFileImportDeviceIdentifierImpl.getOrCreate(uuid);
long numFixes = getService().getGPSFixStore().getNumberOfFixes(device);
TimeRange timeRange = getService().getGPSFixStore().getTimeRangeCoveredByFixes(device);
Date from = timeRange == null ? null : timeRange.from().asDate();
Date to = timeRange == null ? null : timeRange.to().asDate();
result.add(new TrackFileImportDeviceIdentifierDTO(uuidAsString, device.getFileName(), device.getTrackName(),
numFixes, from, to));
}
return result;
}
} }
@@ -0,0 +1,28 @@
package com.sap.sailing.gwt.ui.shared;
import java.util.Date;
import com.sap.sailing.domain.trackfiles.TrackFileImportDeviceIdentifier;
public class TrackFileImportDeviceIdentifierDTO extends DeviceIdentifierDTO {
private static final long serialVersionUID = 5409142940941055516L;
public String uuidAsString;
public String fileName;
public String trackName;
public long numFixes;
public Date from;
public Date to;
protected TrackFileImportDeviceIdentifierDTO() {}
public TrackFileImportDeviceIdentifierDTO(String uuidAsString, String fileName, String trackName,
long numFixes, Date from, Date to) {
super(TrackFileImportDeviceIdentifier.TYPE, uuidAsString);
this.uuidAsString = uuidAsString;
this.fileName = fileName;
this.trackName = trackName;
this.numFixes = numFixes;
this.from = from;
this.to = to;
}
}
@@ -24,30 +24,25 @@ import org.apache.commons.fileupload.FileItemFactory;
import org.apache.commons.fileupload.FileUploadException; import org.apache.commons.fileupload.FileUploadException;
import org.apache.commons.fileupload.disk.DiskFileItemFactory; import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.fileupload.servlet.ServletFileUpload; import org.apache.commons.fileupload.servlet.ServletFileUpload;
import org.json.simple.JSONArray;
import org.osgi.framework.Filter; import org.osgi.framework.Filter;
import org.osgi.framework.InvalidSyntaxException; import org.osgi.framework.InvalidSyntaxException;
import org.osgi.framework.ServiceReference; import org.osgi.framework.ServiceReference;
import com.sap.sailing.domain.common.TimePoint; import com.sap.sailing.domain.common.TimePoint;
import com.sap.sailing.domain.common.impl.TimeRangeImpl; import com.sap.sailing.domain.common.racelog.tracking.NoCorrespondingServiceRegisteredException;
import com.sap.sailing.domain.common.racelog.tracking.TypeBasedServiceFinder; import com.sap.sailing.domain.common.racelog.tracking.TransformationException;
import com.sap.sailing.domain.racelog.tracking.DeviceIdentifier; import com.sap.sailing.domain.racelog.tracking.DeviceIdentifier;
import com.sap.sailing.domain.racelog.tracking.DeviceWithTimeRange; import com.sap.sailing.domain.trackfiles.TrackFileImportDeviceIdentifier;
import com.sap.sailing.domain.trackimport.FormatNotSupportedException; import com.sap.sailing.domain.trackimport.FormatNotSupportedException;
import com.sap.sailing.domain.trackimport.GPSFixImporter; import com.sap.sailing.domain.trackimport.GPSFixImporter;
import com.sap.sailing.domain.trackimport.GPSFixImporter.Callback; import com.sap.sailing.domain.trackimport.GPSFixImporter.Callback;
import com.sap.sailing.domain.tracking.GPSFix; import com.sap.sailing.domain.tracking.GPSFix;
import com.sap.sailing.server.gateway.AbstractJsonHttpServlet; import com.sap.sailing.server.gateway.AbstractJsonHttpServlet;
import com.sap.sailing.server.gateway.serialization.JsonSerializer;
import com.sap.sailing.server.gateway.serialization.impl.DeviceIdentifierJsonSerializer;
import com.sap.sailing.server.gateway.serialization.impl.DeviceWithTimeRangeJsonSerializer;
import com.sap.sailing.server.gateway.serialization.racelog.tracking.DeviceIdentifierJsonHandler;
import com.sap.sse.common.Util; import com.sap.sse.common.Util;
/** /**
* Servlet that processes uploaded track files by adding their fixes to the GPSFixStore. * Servlet that processes uploaded track files by adding their fixes to the GPSFixStore.
* Returns a JSON array of generated device identifiers.<p> * Returns a newline-separated list of the device identifiers genearted by the import.<p>
* *
* The available importers are tried one by one in the following order, until the first * The available importers are tried one by one in the following order, until the first
* one is found that does not fail with an {@link FormatNotSupportedException}: * one is found that does not fail with an {@link FormatNotSupportedException}:
@@ -68,7 +63,11 @@ public class TrackFilesImportServlet extends AbstractJsonHttpServlet {
private static final int READ_BUFFER_SIZE = 1024 * 1024 * 1024; private static final int READ_BUFFER_SIZE = 1024 * 1024 * 1024;
public void storeFix(GPSFix fix, DeviceIdentifier deviceIdentifier) { public void storeFix(GPSFix fix, DeviceIdentifier deviceIdentifier) {
getService().getGPSFixStore().storeFix(deviceIdentifier, fix); try {
getService().getGPSFixStore().storeFix(deviceIdentifier, fix);
} catch (TransformationException | NoCorrespondingServiceRegisteredException e) {
logger.log(Level.WARNING, "Could not store fix for " + deviceIdentifier);
}
} }
public Collection<GPSFixImporter> getGPSFixImporters(String fileExtension) { public Collection<GPSFixImporter> getGPSFixImporters(String fileExtension) {
@@ -90,9 +89,9 @@ public class TrackFilesImportServlet extends AbstractJsonHttpServlet {
return result; return result;
} }
public Iterable<DeviceWithTimeRange> importFiles(Iterable<Util.Pair<String, InputStream>> files, GPSFixImporter preferredImporter) public Iterable<TrackFileImportDeviceIdentifier> importFiles(Iterable<Pair<String, InputStream>> files, GPSFixImporter preferredImporter)
throws IOException { throws IOException {
final Set<DeviceIdentifier> deviceIds = new HashSet<>(); final Set<TrackFileImportDeviceIdentifier> deviceIds = new HashSet<>();
final Map<DeviceIdentifier, TimePoint> from = new HashMap<>(); final Map<DeviceIdentifier, TimePoint> from = new HashMap<>();
final Map<DeviceIdentifier, TimePoint> to = new HashMap<>(); final Map<DeviceIdentifier, TimePoint> to = new HashMap<>();
@@ -134,7 +133,7 @@ public class TrackFilesImportServlet extends AbstractJsonHttpServlet {
try { try {
importer.importFixes(in, new Callback() { importer.importFixes(in, new Callback() {
@Override @Override
public void addFix(GPSFix fix, DeviceIdentifier device) { public void addFix(GPSFix fix, TrackFileImportDeviceIdentifier device) {
deviceIds.add(device); deviceIds.add(device);
storeFix(fix, device); storeFix(fix, device);
@@ -160,11 +159,7 @@ public class TrackFilesImportServlet extends AbstractJsonHttpServlet {
} }
} }
} }
List<DeviceWithTimeRange> result = new ArrayList<>(); return deviceIds;
for (DeviceIdentifier deviceId : deviceIds) {
result.add(new DeviceWithTimeRangeImpl(deviceId, new TimeRangeImpl(from.get(deviceId), to.get(deviceId))));
}
return result;
} }
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
@@ -201,20 +196,16 @@ public class TrackFilesImportServlet extends AbstractJsonHttpServlet {
findService(prefImporterType); findService(prefImporterType);
} }
final Iterable<DeviceWithTimeRange> mappingList = importFiles(files, preferredImporter); final Iterable<TrackFileImportDeviceIdentifier> mappingList = importFiles(files, preferredImporter);
//setJsonResponseHeader(resp); //setJsonResponseHeader(resp);
//DO NOT set a JSON response header. This causes the browser to wrap the response in a //DO NOT set a JSON response header. This causes the browser to wrap the response in a
//<pre> tag when uploading from GWT, as this is an AJAX-request inside an iFrame. //<pre> tag when uploading from GWT, as this is an AJAX-request inside an iFrame.
resp.setContentType("text/html"); resp.setContentType("text/html");
TypeBasedServiceFinder<DeviceIdentifierJsonHandler> serviceFinder = for (TrackFileImportDeviceIdentifier mapping : mappingList) {
getServiceFinderFactory().createServiceFinder(DeviceIdentifierJsonHandler.class); String stringRep = mapping.getId().toString();
JsonSerializer<DeviceWithTimeRange> serializer = new DeviceWithTimeRangeJsonSerializer(new DeviceIdentifierJsonSerializer(serviceFinder)); resp.getWriter().println(stringRep);
JSONArray array = new JSONArray();
for (DeviceWithTimeRange mapping : mappingList) {
array.add(serializer.serialize(mapping));
} }
array.writeJSONString(resp.getWriter());
} }
} }
@@ -16,7 +16,7 @@ import org.w3c.dom.Element;
import slash.navigation.base.BaseNavigationPosition; import slash.navigation.base.BaseNavigationPosition;
import slash.navigation.gpx.binding11.WptType; import slash.navigation.gpx.binding11.WptType;
import com.sap.sailing.domain.racelog.tracking.DeviceIdentifier; import com.sap.sailing.domain.trackfiles.TrackFileImportDeviceIdentifier;
import com.sap.sailing.domain.tracking.GPSFix; import com.sap.sailing.domain.tracking.GPSFix;
import com.sap.sailing.server.trackfiles.impl.BaseRouteConverterGPSFixImporterImpl; import com.sap.sailing.server.trackfiles.impl.BaseRouteConverterGPSFixImporterImpl;
import com.sap.sailing.server.trackfiles.impl.RouteConverterGPSFixImporterImpl; import com.sap.sailing.server.trackfiles.impl.RouteConverterGPSFixImporterImpl;
@@ -49,7 +49,7 @@ public class RouteConverterGpx11ExtensionsTest {
importer.importFixes(in, new com.sap.sailing.domain.trackimport.GPSFixImporter.Callback() { importer.importFixes(in, new com.sap.sailing.domain.trackimport.GPSFixImporter.Callback() {
@Override @Override
public void addFix(GPSFix fix, DeviceIdentifier device) { public void addFix(GPSFix fix, TrackFileImportDeviceIdentifier device) {
} }
}, false, "source"); }, false, "source");
@@ -8,7 +8,7 @@ import java.io.InputStream;
import org.junit.Before; import org.junit.Before;
import org.junit.Test; import org.junit.Test;
import com.sap.sailing.domain.racelog.tracking.DeviceIdentifier; import com.sap.sailing.domain.trackfiles.TrackFileImportDeviceIdentifier;
import com.sap.sailing.domain.trackimport.FormatNotSupportedException; import com.sap.sailing.domain.trackimport.FormatNotSupportedException;
import com.sap.sailing.domain.trackimport.GPSFixImporter.Callback; import com.sap.sailing.domain.trackimport.GPSFixImporter.Callback;
import com.sap.sailing.domain.tracking.GPSFix; import com.sap.sailing.domain.tracking.GPSFix;
@@ -28,7 +28,7 @@ public class TrackFileImportTest {
InputStream in = getClass().getResourceAsStream("/Cardiff Race17 - COMPETITORS.gpx"); InputStream in = getClass().getResourceAsStream("/Cardiff Race17 - COMPETITORS.gpx");
new RouteConverterGPSFixImporterImpl().importFixes(in, new Callback() { new RouteConverterGPSFixImporterImpl().importFixes(in, new Callback() {
@Override @Override
public void addFix(GPSFix fix, DeviceIdentifier device) { public void addFix(GPSFix fix, TrackFileImportDeviceIdentifier device) {
if (fix instanceof GPSFixMoving) { if (fix instanceof GPSFixMoving) {
callbackCalled = true; callbackCalled = true;
} }
@@ -42,7 +42,7 @@ public class TrackFileImportTest {
InputStream in = getClass().getResourceAsStream("/sam002903 - COMPETITORS.kml"); InputStream in = getClass().getResourceAsStream("/sam002903 - COMPETITORS.kml");
new RouteConverterGPSFixImporterImpl().importFixes(in, new Callback() { new RouteConverterGPSFixImporterImpl().importFixes(in, new Callback() {
@Override @Override
public void addFix(GPSFix fix, DeviceIdentifier device) { public void addFix(GPSFix fix, TrackFileImportDeviceIdentifier device) {
if (fix instanceof GPSFix) { if (fix instanceof GPSFix) {
callbackCalled = true; callbackCalled = true;
} }
@@ -1,7 +1,7 @@
package com.sap.sailing.server.trackfiles.common; package com.sap.sailing.server.trackfiles.common;
import com.sap.sailing.domain.common.SpeedWithBearing; import com.sap.sailing.domain.common.SpeedWithBearing;
import com.sap.sailing.domain.racelog.tracking.DeviceIdentifier; import com.sap.sailing.domain.trackfiles.TrackFileImportDeviceIdentifier;
import com.sap.sailing.domain.trackimport.GPSFixImporter; import com.sap.sailing.domain.trackimport.GPSFixImporter;
import com.sap.sailing.domain.tracking.GPSFix; import com.sap.sailing.domain.tracking.GPSFix;
import com.sap.sailing.domain.tracking.GPSFixMoving; import com.sap.sailing.domain.tracking.GPSFixMoving;
@@ -24,10 +24,12 @@ import com.sap.sailing.domain.tracking.impl.GPSFixMovingImpl;
public abstract class BaseGPSFixImporterImpl implements GPSFixImporter { public abstract class BaseGPSFixImporterImpl implements GPSFixImporter {
private GPSFix previousFix; private GPSFix previousFix;
protected void addFixAndInfer(Callback callback, boolean inferSpeedAndBearing, GPSFix fix, DeviceIdentifier device) { protected void addFixAndInfer(Callback callback, boolean inferSpeedAndBearing, GPSFix fix,
TrackFileImportDeviceIdentifier device) {
if (inferSpeedAndBearing && ! (fix instanceof GPSFixMoving)) { if (inferSpeedAndBearing && ! (fix instanceof GPSFixMoving)) {
if (previousFix == null) { if (previousFix == null) {
//have to infer speed and bearing, but this is the first fix -> drop it //have to infer speed and bearing, but this is the first fix -> drop it
previousFix = fix;
return; return;
} }
SpeedWithBearing speedWithBearing = previousFix.getSpeedAndBearingRequiredToReach(fix); SpeedWithBearing speedWithBearing = previousFix.getSpeedAndBearingRequiredToReach(fix);
@@ -13,7 +13,7 @@ import slash.navigation.base.NavigationFormat;
import slash.navigation.base.NavigationFormatParser; import slash.navigation.base.NavigationFormatParser;
import slash.navigation.base.ParserResult; import slash.navigation.base.ParserResult;
import com.sap.sailing.domain.racelog.tracking.DeviceIdentifier; import com.sap.sailing.domain.trackfiles.TrackFileImportDeviceIdentifier;
import com.sap.sailing.domain.trackfiles.TrackFileImportDeviceIdentifierImpl; import com.sap.sailing.domain.trackfiles.TrackFileImportDeviceIdentifierImpl;
import com.sap.sailing.domain.trackimport.FormatNotSupportedException; import com.sap.sailing.domain.trackimport.FormatNotSupportedException;
import com.sap.sailing.domain.tracking.GPSFix; import com.sap.sailing.domain.tracking.GPSFix;
@@ -74,7 +74,7 @@ public abstract class BaseRouteConverterGPSFixImporterImpl extends BaseGPSFixImp
for (BaseRoute route : routes) { for (BaseRoute route : routes) {
List<? extends BaseNavigationPosition> positions = (List<? extends BaseNavigationPosition>) route.getPositions(); List<? extends BaseNavigationPosition> positions = (List<? extends BaseNavigationPosition>) route.getPositions();
String routeName = route.getName(); String routeName = route.getName();
DeviceIdentifier device = new TrackFileImportDeviceIdentifierImpl(sourceName, routeName); TrackFileImportDeviceIdentifier device = new TrackFileImportDeviceIdentifierImpl(sourceName, routeName);
for (BaseNavigationPosition p : positions) { for (BaseNavigationPosition p : positions) {
try { try {
addFixAndInfer(callback, inferSpeedAndBearing, convertToGPSFix(p), device); addFixAndInfer(callback, inferSpeedAndBearing, convertToGPSFix(p), device);
@@ -4,6 +4,7 @@ import java.util.Arrays;
import java.util.Date; import java.util.Date;
import java.util.List; import java.util.List;
import slash.common.type.CompactCalendar;
import slash.navigation.base.BaseNavigationPosition; import slash.navigation.base.BaseNavigationPosition;
import slash.navigation.base.NavigationFormat; import slash.navigation.base.NavigationFormat;
import slash.navigation.base.NavigationFormats; import slash.navigation.base.NavigationFormats;
@@ -190,7 +191,13 @@ public class RouteConverterGPSFixImporterImpl extends BaseRouteConverterGPSFixIm
} }
public GPSFix convertToGPSFix(BaseNavigationPosition position) throws Exception { public GPSFix convertToGPSFix(BaseNavigationPosition position) throws Exception {
Date t = position.getTime().getTime(); final CompactCalendar time = position.getTime();
final Date t;
if (time == null) {
t = new Date(); // use "now" as the time for the fix which otherwise would be lacking a time stamp
} else {
t = time.getTime();
}
Double heading = null; Double heading = null;
if (position instanceof Wgs84Position) { if (position instanceof Wgs84Position) {
heading = ((Wgs84Position) position).getHeading(); heading = ((Wgs84Position) position).getHeading();