Merge branch 'master' into design2015

Conflicts:
	java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages.java
	java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages.properties
	java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages_de.properties
	java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages_ru.properties
	java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages_zh.properties
This commit is contained in:
Steffen Schaefer
2016-01-26 08:13:21 +01:00
200 changed files with 5955 additions and 5982 deletions
@@ -0,0 +1,15 @@
package com.sap.sailing.domain.common;
import java.io.Serializable;
public class NotFoundException extends Exception implements Serializable {
private static final long serialVersionUID = 1690510580423647161L;
public NotFoundException() {
}
public NotFoundException(String message) {
super(message);
}
}
@@ -0,0 +1,13 @@
package com.sap.sailing.domain.common;
import java.io.Serializable;
public class UnableToCloseDeviceMappingException extends Exception implements Serializable{
private static final long serialVersionUID = 4595827888350748956L;
public UnableToCloseDeviceMappingException() {}
public UnableToCloseDeviceMappingException(String message) {
super(message);
}
}
@@ -0,0 +1,15 @@
package com.sap.sailing.domain.common.racelog.tracking;
import java.io.Serializable;
public class CompetitorRegistrationOnRaceLogDisabledException extends Exception implements Serializable {
private static final long serialVersionUID = 963948633131929332L;
public CompetitorRegistrationOnRaceLogDisabledException() {
super("Competitor registration not allowed on race");
}
public CompetitorRegistrationOnRaceLogDisabledException(String message) {
super(message);
}
}
@@ -63,6 +63,7 @@ public class CompactGPSFixMovingImpl extends CompactGPSFixImpl implements GPSFix
public String toString() {
return super.toString()+" to "+getBearing().getDegrees()+"°";
}
@Override
public int hashCode() {
return super.hashCode() ^ getBearing().hashCode();
@@ -57,6 +57,7 @@ import com.sap.sailing.domain.abstractlog.race.RaceLogStartTimeEvent;
import com.sap.sailing.domain.abstractlog.race.RaceLogSuppressedMarkPassingsEvent;
import com.sap.sailing.domain.abstractlog.race.RaceLogWindFixEvent;
import com.sap.sailing.domain.abstractlog.race.SimpleRaceLogIdentifier;
import com.sap.sailing.domain.abstractlog.race.impl.CompetitorResultImpl;
import com.sap.sailing.domain.abstractlog.race.impl.CompetitorResultsImpl;
import com.sap.sailing.domain.abstractlog.race.impl.RaceLogCourseAreaChangeEventImpl;
import com.sap.sailing.domain.abstractlog.race.impl.RaceLogCourseDesignChangedEventImpl;
@@ -82,23 +83,18 @@ import com.sap.sailing.domain.abstractlog.race.impl.SimpleRaceLogIdentifierImpl;
import com.sap.sailing.domain.abstractlog.race.scoring.AdditionalScoringInformationType;
import com.sap.sailing.domain.abstractlog.race.scoring.RaceLogAdditionalScoringInformationEvent;
import com.sap.sailing.domain.abstractlog.race.scoring.impl.RaceLogAdditionalScoringInformationEventImpl;
import com.sap.sailing.domain.abstractlog.race.tracking.RaceLogCloseOpenEndedDeviceMappingEvent;
import com.sap.sailing.domain.abstractlog.race.tracking.RaceLogDefineMarkEvent;
import com.sap.sailing.domain.abstractlog.race.tracking.RaceLogDenoteForTrackingEvent;
import com.sap.sailing.domain.abstractlog.race.tracking.RaceLogDeviceCompetitorMappingEvent;
import com.sap.sailing.domain.abstractlog.race.tracking.RaceLogDeviceMarkMappingEvent;
import com.sap.sailing.domain.abstractlog.race.tracking.RaceLogRegisterCompetitorEvent;
import com.sap.sailing.domain.abstractlog.race.tracking.RaceLogStartTrackingEvent;
import com.sap.sailing.domain.abstractlog.race.tracking.impl.RaceLogCloseOpenEndedDeviceMappingEventImpl;
import com.sap.sailing.domain.abstractlog.race.tracking.impl.RaceLogDefineMarkEventImpl;
import com.sap.sailing.domain.abstractlog.race.tracking.RaceLogUseCompetitorsFromRaceLogEvent;
import com.sap.sailing.domain.abstractlog.race.tracking.impl.RaceLogDenoteForTrackingEventImpl;
import com.sap.sailing.domain.abstractlog.race.tracking.impl.RaceLogDeviceCompetitorMappingEventImpl;
import com.sap.sailing.domain.abstractlog.race.tracking.impl.RaceLogDeviceMarkMappingEventImpl;
import com.sap.sailing.domain.abstractlog.race.tracking.impl.RaceLogRegisterCompetitorEventImpl;
import com.sap.sailing.domain.abstractlog.race.tracking.impl.RaceLogStartTrackingEventImpl;
import com.sap.sailing.domain.abstractlog.race.tracking.impl.RaceLogUseCompetitorsFromRaceLogEventImpl;
import com.sap.sailing.domain.abstractlog.regatta.RegattaLog;
import com.sap.sailing.domain.abstractlog.regatta.RegattaLogEvent;
import com.sap.sailing.domain.abstractlog.regatta.events.RegattaLogCloseOpenEndedDeviceMappingEvent;
import com.sap.sailing.domain.abstractlog.regatta.events.RegattaLogDefineMarkEvent;
import com.sap.sailing.domain.abstractlog.regatta.events.RegattaLogDeviceCompetitorMappingEvent;
import com.sap.sailing.domain.abstractlog.regatta.events.RegattaLogDeviceMarkMappingEvent;
import com.sap.sailing.domain.abstractlog.regatta.events.RegattaLogRegisterCompetitorEvent;
@@ -106,6 +102,7 @@ import com.sap.sailing.domain.abstractlog.regatta.events.RegattaLogRevokeEvent;
import com.sap.sailing.domain.abstractlog.regatta.events.RegattaLogSetCompetitorTimeOnDistanceAllowancePerNauticalMileEvent;
import com.sap.sailing.domain.abstractlog.regatta.events.RegattaLogSetCompetitorTimeOnTimeFactorEvent;
import com.sap.sailing.domain.abstractlog.regatta.events.impl.RegattaLogCloseOpenEndedDeviceMappingEventImpl;
import com.sap.sailing.domain.abstractlog.regatta.events.impl.RegattaLogDefineMarkEventImpl;
import com.sap.sailing.domain.abstractlog.regatta.events.impl.RegattaLogDeviceCompetitorMappingEventImpl;
import com.sap.sailing.domain.abstractlog.regatta.events.impl.RegattaLogDeviceMarkMappingEventImpl;
import com.sap.sailing.domain.abstractlog.regatta.events.impl.RegattaLogRegisterCompetitorEventImpl;
@@ -1313,7 +1310,7 @@ public class DomainObjectFactoryImpl implements DomainObjectFactory {
}
return result;
}
public RaceLogEvent loadRaceLogEvent(DBObject dbObject) {
TimePoint logicalTimePoint = loadTimePoint(dbObject);
TimePoint createdAt = loadTimePoint(dbObject, FieldNames.RACE_LOG_EVENT_CREATED_AT);
@@ -1363,10 +1360,6 @@ public class DomainObjectFactoryImpl implements DomainObjectFactory {
return loadRaceLogProtestStartTimeEvent(createdAt, author, logicalTimePoint, id, passId, competitors, dbObject);
} else if (eventClass.equals(RaceLogWindFixEvent.class.getSimpleName())) {
return loadRaceLogWindFixEvent(createdAt, author, logicalTimePoint, id, passId, competitors, dbObject);
} else if (eventClass.equals(RaceLogDeviceCompetitorMappingEvent.class.getSimpleName())) {
return loadRaceLogDeviceCompetitorMappingEvent(createdAt, author, logicalTimePoint, id, passId, competitors, dbObject);
} else if (eventClass.equals(RaceLogDeviceMarkMappingEvent.class.getSimpleName())) {
return loadRaceLogDeviceMarkMappingEvent(createdAt, author, logicalTimePoint, id, passId, competitors, dbObject);
} else if (eventClass.equals(RaceLogDenoteForTrackingEvent.class.getSimpleName())) {
return loadRaceLogDenoteForTrackingEvent(createdAt, author, logicalTimePoint, id, passId, competitors, dbObject);
} else if (eventClass.equals(RaceLogStartTrackingEvent.class.getSimpleName())) {
@@ -1375,21 +1368,24 @@ public class DomainObjectFactoryImpl implements DomainObjectFactory {
return loadRaceLogRevokeEvent(createdAt, author, logicalTimePoint, id, passId, competitors, dbObject);
} else if (eventClass.equals(RaceLogRegisterCompetitorEvent.class.getSimpleName())) {
return loadRaceLogRegisterCompetitorEvent(createdAt, author, logicalTimePoint, id, passId, competitors, dbObject);
} else if (eventClass.equals(RaceLogDefineMarkEvent.class.getSimpleName())) {
return loadRaceLogDefineMarkEvent(createdAt, author, logicalTimePoint, id, passId, competitors, dbObject);
} else if (eventClass.equals(RaceLogCloseOpenEndedDeviceMappingEvent.class.getSimpleName())) {
return loadRaceLogCloseOpenEndedDeviceMappingEvent(createdAt, author, logicalTimePoint, id, passId, competitors, dbObject);
} else if (eventClass.equals(RaceLogAdditionalScoringInformationEvent.class.getSimpleName())) {
return loadRaceLogAdditionalScoringInformationEvent(createdAt, author, logicalTimePoint, id, passId, competitors, dbObject);
} else if (eventClass.equals(RaceLogFixedMarkPassingEvent.class.getSimpleName())){
return loadRaceLogFixedMarkPassingEvent(createdAt, author, logicalTimePoint, id, passId, competitors, dbObject);
} else if (eventClass.equals(RaceLogSuppressedMarkPassingsEvent.class.getSimpleName())){
return loadRaceLogSuppressedMarkPassingsEvent(createdAt, author, logicalTimePoint, id, passId, competitors, dbObject);
} else if (eventClass.equals(RaceLogUseCompetitorsFromRaceLogEvent.class.getSimpleName())){
return loadRaceLogUseCompetitorsFromRaceLogEvent(createdAt, author, logicalTimePoint, id, passId, competitors, dbObject);
}
throw new IllegalStateException(String.format("Unknown RaceLogEvent type %s", eventClass));
}
private RaceLogEvent loadRaceLogUseCompetitorsFromRaceLogEvent(TimePoint createdAt, AbstractLogEventAuthor author,
TimePoint logicalTimePoint, Serializable id, Integer passId, List<Competitor> competitors, DBObject dbObject) {
return new RaceLogUseCompetitorsFromRaceLogEventImpl(createdAt, author, logicalTimePoint, id, passId);
}
private RaceLogEvent loadRaceLogWindFixEvent(TimePoint createdAt, AbstractLogEventAuthor author, TimePoint logicalTimePoint,
Serializable id, Integer passId, List<Competitor> competitors, DBObject dbObject) {
Wind wind = loadWind((DBObject) dbObject.get(FieldNames.WIND.name()));
@@ -1397,40 +1393,6 @@ public class DomainObjectFactoryImpl implements DomainObjectFactory {
return new RaceLogWindFixEventImpl(createdAt, logicalTimePoint, author, id, passId, wind, isMagnetic == null ? true : isMagnetic);
}
private RaceLogEvent loadRaceLogDeviceCompetitorMappingEvent(TimePoint createdAt, AbstractLogEventAuthor author, TimePoint logicalTimePoint,
Serializable id, Integer passId, List<Competitor> competitors, DBObject dbObject) {
DeviceIdentifier device = null;
try {
device = loadDeviceId(deviceIdentifierServiceFinder,
(DBObject) dbObject.get(FieldNames.DEVICE_ID.name()));
} catch (Exception e) {
logger.log(Level.WARNING, "Could not load deviceId for RaceLogEvent", e);
e.printStackTrace();
}
Competitor mappedTo = baseDomainFactory.getExistingCompetitorById(
(Serializable) dbObject.get(FieldNames.COMPETITOR_ID.name()));
TimePoint from = loadTimePoint(dbObject, FieldNames.RACE_LOG_FROM);
TimePoint to = loadTimePoint(dbObject, FieldNames.RACE_LOG_TO);
return new RaceLogDeviceCompetitorMappingEventImpl(createdAt, logicalTimePoint, author, id, passId, mappedTo, device, from, to);
}
private RaceLogEvent loadRaceLogDeviceMarkMappingEvent(TimePoint createdAt, AbstractLogEventAuthor author, TimePoint logicalTimePoint,
Serializable id, Integer passId, List<Competitor> competitors, DBObject dbObject) {
DeviceIdentifier device = null;
try {
device = loadDeviceId(deviceIdentifierServiceFinder,
(DBObject) dbObject.get(FieldNames.DEVICE_ID.name()));
} catch (Exception e) {
logger.log(Level.WARNING, "Could not load deviceId for RaceLogEvent", e);
e.printStackTrace();
}
//have to load complete mark, as no order is guaranteed for loading of racelog events
Mark mappedTo = loadMark((DBObject) dbObject.get(FieldNames.MARK.name()));
TimePoint from = loadTimePoint(dbObject, FieldNames.RACE_LOG_FROM);
TimePoint to = loadTimePoint(dbObject, FieldNames.RACE_LOG_TO);
return new RaceLogDeviceMarkMappingEventImpl(createdAt, logicalTimePoint, author, id, passId, mappedTo, device, from, to);
}
private RaceLogEvent loadRaceLogDenoteForTrackingEvent(TimePoint createdAt, AbstractLogEventAuthor author, TimePoint logicalTimePoint,
Serializable id, Integer passId, List<Competitor> competitors, DBObject dbObject) {
String raceName = (String) dbObject.get(FieldNames.RACE_NAME.name());
@@ -1462,20 +1424,6 @@ public class DomainObjectFactoryImpl implements DomainObjectFactory {
return new RaceLogRegisterCompetitorEventImpl(createdAt, logicalTimePoint, author, id, passId, comp);
}
private RaceLogEvent loadRaceLogDefineMarkEvent(TimePoint createdAt, AbstractLogEventAuthor author, TimePoint logicalTimePoint,
Serializable id, Integer passId, List<Competitor> competitors, DBObject dbObject) {
Mark mark = loadMark((DBObject) dbObject.get(FieldNames.RACE_LOG_MARK.name()));
return new RaceLogDefineMarkEventImpl(createdAt, logicalTimePoint, author, id, passId, mark);
}
private RaceLogEvent loadRaceLogCloseOpenEndedDeviceMappingEvent(TimePoint createdAt, AbstractLogEventAuthor author, TimePoint logicalTimePoint,
Serializable id, Integer passId, List<Competitor> competitors, DBObject dbObject) {
Serializable deviceMappingEventId = Helpers.tryUuidConversion((Serializable) dbObject.get(FieldNames.RACE_LOG_DEVICE_MAPPING_EVENT_ID.name()));
TimePoint closingTimePoint = loadTimePoint(dbObject, FieldNames.RACE_LOG_CLOSING_TIMEPOINT);
return new RaceLogCloseOpenEndedDeviceMappingEventImpl(createdAt, logicalTimePoint, author, id, passId,
deviceMappingEventId, closingTimePoint);
}
private RaceLogEvent loadRaceLogAdditionalScoringInformationEvent(TimePoint createdAt, AbstractLogEventAuthor author, TimePoint logicalTimePoint,
Serializable id, Integer passId, List<Competitor> competitors, DBObject dbObject) {
Object additionalScoringInformationTypeInfo = dbObject.get(FieldNames.RACE_LOG_ADDITIONAL_SCORING_INFORMATION_TYPE.name());
@@ -1568,27 +1516,30 @@ public class DomainObjectFactoryImpl implements DomainObjectFactory {
}
private CompetitorResults loadPositionedCompetitors(BasicDBList dbPositionedCompetitorList) {
CompetitorResults positionedCompetitors = new CompetitorResultsImpl();
CompetitorResultsImpl positionedCompetitors = new CompetitorResultsImpl();
int rankCounter = 1;
for (Object object : dbPositionedCompetitorList) {
DBObject dbObject = (DBObject) object;
Serializable competitorId = (Serializable) dbObject.get(FieldNames.COMPETITOR_ID.name());
String competitorName = (String) dbObject.get(FieldNames.COMPETITOR_DISPLAY_NAME.name());
final Serializable competitorId = (Serializable) dbObject.get(FieldNames.COMPETITOR_ID.name());
String competitorDisplayName = (String) dbObject.get(FieldNames.COMPETITOR_DISPLAY_NAME.name());
//The Competitor name is a new field in the list. Therefore the name might be null for existing events. In this case a standard name is set.
if (competitorName == null) {
competitorName = "loaded competitor";
if (competitorDisplayName == null) {
competitorDisplayName = "loaded competitor";
}
//At this point we do not retrieve the competitor object since at any point in time, especially after a server restart, the DomainFactory and its competitor
//cache might be empty. But at this time the race log is loaded from database, so the competitor would be null.
//By not using the Competitor object retrieved from the DomainFactory we get completely independent from server restarts and the timepoint of loading
//competitors by tracking providers.
MaxPointsReason maxPointsReason = MaxPointsReason.valueOf((String) dbObject.get(FieldNames.LEADERBOARD_SCORE_CORRECTION_MAX_POINTS_REASON.name()));
Util.Triple<Serializable, String, MaxPointsReason> positionedCompetitor = new Util.Triple<Serializable, String, MaxPointsReason>(competitorId, competitorName, maxPointsReason);
final Integer rank = (Integer) dbObject.get(FieldNames.LEADERBOARD_RANK.name());
final MaxPointsReason maxPointsReason = MaxPointsReason.valueOf((String) dbObject.get(FieldNames.LEADERBOARD_SCORE_CORRECTION_MAX_POINTS_REASON.name()));
final Double score = (Double) dbObject.get(FieldNames.LEADERBOARD_CORRECTED_SCORE.name());
final Long finishingTimePointAsMillis = (Long) dbObject.get(FieldNames.RACE_LOG_FINISHING_TIME_AS_MILLIS.name());
final TimePoint finishingTime = finishingTimePointAsMillis == null ? null : new MillisecondsTimePoint(finishingTimePointAsMillis);
final String comment = (String) dbObject.get(FieldNames.LEADERBOARD_SCORE_CORRECTION_COMMENT.name());
CompetitorResultImpl positionedCompetitor = new CompetitorResultImpl(
competitorId, competitorDisplayName, rank == null ? rankCounter : rank, maxPointsReason, score, finishingTime, comment);
positionedCompetitors.add(positionedCompetitor);
rankCounter++;
}
return positionedCompetitors;
}
@@ -1703,12 +1654,14 @@ public class DomainObjectFactoryImpl implements DomainObjectFactory {
return loadRegattaLogSetCompetitorTimeOnTimeFactorEvent(createdAt, author, logicalTimePoint, id, dbObject);
} else if (eventClass.equals(RegattaLogSetCompetitorTimeOnDistanceAllowancePerNauticalMileEvent.class.getSimpleName())) {
return loadRegattaLogSetCompetitorTimeOnDistanceAllowancePerNauticalMileEvent(createdAt, author, logicalTimePoint, id, dbObject);
} else if (eventClass.equals(RegattaLogDefineMarkEvent.class.getSimpleName())) {
return loadRegattaLogDefineMarkEvent(createdAt, author, logicalTimePoint, id, dbObject);
} else if (eventClass.equals(RegattaLogRevokeEvent.class.getSimpleName())) {
return loadRegattaLogRevokeEvent(createdAt, author, logicalTimePoint, id, dbObject);
}
throw new IllegalStateException(String.format("Unknown RegattaLogEvent type %s", eventClass));
}
private Competitor getCompetitorByID(DBObject dbObject) {
Serializable competitorId = (Serializable) dbObject.get(FieldNames.REGATTA_LOG_COMPETITOR_ID.name());
Competitor comp = baseDomainFactory.getCompetitorStore().getExistingCompetitorById(competitorId);
@@ -1741,6 +1694,12 @@ public class DomainObjectFactoryImpl implements DomainObjectFactory {
return new RegattaLogRevokeEventImpl(createdAt, logicalTimePoint, author, id,
revokedEventId, revokedEventType, revokedEventShortInfo, reason);
}
private RegattaLogEvent loadRegattaLogDefineMarkEvent(TimePoint createdAt, AbstractLogEventAuthor author,
TimePoint logicalTimePoint, Serializable id, DBObject dbObject) {
Mark mark = loadMark((DBObject) dbObject.get(FieldNames.REGATTA_LOG_MARK.name()));
return new RegattaLogDefineMarkEventImpl(createdAt, author, logicalTimePoint, id, mark);
}
private RegattaLogRegisterCompetitorEvent loadRegattaLogRegisterCompetitorEvent(TimePoint createdAt, AbstractLogEventAuthor author,
TimePoint logicalTimePoint, Serializable id, DBObject dbObject) {
@@ -1769,7 +1728,11 @@ public class DomainObjectFactoryImpl implements DomainObjectFactory {
}
//have to load complete mark, as no order is guaranteed for loading of racelog events
Mark mappedTo = loadMark((DBObject) dbObject.get(FieldNames.MARK.name()));
Triple<TimePoint, TimePoint, Boolean> times = loadFromToTimePoint(dbObject, FieldNames.REGATTA_LOG_FROM, FieldNames.RACE_LOG_FROM, FieldNames.REGATTA_LOG_TO, FieldNames.RACE_LOG_TO);
@SuppressWarnings("deprecation") // used only for auto-migration; may be removed in future releases
final FieldNames deprecatedFromFieldName = FieldNames.RACE_LOG_FROM;
@SuppressWarnings("deprecation") // used only for auto-migration; may be removed in future releases
final FieldNames deprecatedToFieldName = FieldNames.RACE_LOG_TO;
Triple<TimePoint, TimePoint, Boolean> times = loadFromToTimePoint(dbObject, FieldNames.REGATTA_LOG_FROM, deprecatedFromFieldName, FieldNames.REGATTA_LOG_TO, deprecatedToFieldName);
final TimePoint from = times.getA();
final TimePoint to = times.getB();
final RegattaLogDeviceMarkMappingEventImpl result = new RegattaLogDeviceMarkMappingEventImpl(createdAt, logicalTimePoint, author, id, mappedTo, device, from, to);
@@ -1830,7 +1793,11 @@ public class DomainObjectFactoryImpl implements DomainObjectFactory {
}
Competitor mappedTo = baseDomainFactory.getExistingCompetitorById(
(Serializable) dbObject.get(FieldNames.COMPETITOR_ID.name()));
Triple<TimePoint, TimePoint, Boolean> times = loadFromToTimePoint(dbObject, FieldNames.REGATTA_LOG_FROM, FieldNames.RACE_LOG_FROM, FieldNames.REGATTA_LOG_TO, FieldNames.RACE_LOG_TO);
@SuppressWarnings("deprecation") // used only for auto-migration; may be removed in future releases
final FieldNames deprecatedFromFieldName = FieldNames.RACE_LOG_FROM;
@SuppressWarnings("deprecation") // used only for auto-migration; may be removed in future releases
final FieldNames deprecatedToFieldName = FieldNames.RACE_LOG_TO;
Triple<TimePoint, TimePoint, Boolean> times = loadFromToTimePoint(dbObject, FieldNames.REGATTA_LOG_FROM, deprecatedFromFieldName, FieldNames.REGATTA_LOG_TO, deprecatedToFieldName);
final TimePoint from = times.getA();
final TimePoint to = times.getB();
final boolean needsMigration = times.getC();
@@ -74,7 +74,7 @@ public enum FieldNames {
LEADERBOARD_IS_MEDAL_RACE_COLUMN, LEADERBOARD_CARRIED_POINTS, LEADERBOARD_CARRIED_POINTS_BY_ID,
LEADERBOARD_SCORE_CORRECTIONS, LEADERBOARD_DISCARDING_THRESHOLDS,
LEADERBOARD_SCORE_CORRECTION_MAX_POINTS_REASON, LEADERBOARD_CORRECTED_SCORE, LEADERBOARD_SCORE_CORRECTION_TIMESTAMP,
LEADERBOARD_SCORE_CORRECTION_COMMENT, LEADERBOARD_COLUMN_FACTORS,
LEADERBOARD_RANK, LEADERBOARD_SCORE_CORRECTION_COMMENT, LEADERBOARD_COLUMN_FACTORS,
// leaderboard group
LEADERBOARD_GROUP_UUID, LEADERBOARD_GROUP_NAME, LEADERBOARD_GROUP_DESCRIPTION,
@@ -92,10 +92,13 @@ public enum FieldNames {
CONTROLPOINT_VALUE, CONTROLPOINTWITHTWOMARKS_ID, CONTROLPOINTWITHTWOMARKS_NAME, CONTROLPOINTWITHTWOMARKS_LEFT, CONTROLPOINTWITHTWOMARKS_RIGHT,
RACE_LOG_POSITIONED_COMPETITORS, RACE_LOG_PATHFINDER_ID, RACE_LOG_GATE_LINE_OPENING_TIME, RACE_LOG_GOLF_DOWN_TIME, RACE_LOG_START_PROCEDURE_TYPE,
RACE_LOG_PROTEST_START_TIME, RACE_LOG_COURSE_DESIGN_NAME, RACE_LOG_REVOKED_EVENT_ID, RACE_LOG_REVOKED_EVENT_TYPE, RACE_LOG_REVOKED_EVENT_SHORT_INFO,
RACE_LOG_REVOKED_REASON, RACE_LOG_FROM, RACE_LOG_TO, RACE_LOG_MARK, RACE_LOG_DEVICE_MAPPING_EVENT_ID,
RACE_LOG_REVOKED_REASON, RACE_LOG_DEVICE_MAPPING_EVENT_ID,
RACE_LOG_CLOSING_TIMEPOINT, TIMEPOINT_OF_FIXED_MARKPASSING, INDEX_OF_PASSED_WAYPOINT,INDEX_OF_FIRST_SUPPRESSED_WAYPOINT, MARK, RACE_LOG_COMPETITOR_ID,
RACE_LOG_DEPDENDENT_ON_FLEET, RACE_LOG_DEPDENDENT_ON_RACECOLUMN, RACE_LOG_DEPDENDENT_ON_REGATTALIKE,
RACE_LOG_START_TIME_DIFFERENCE_IN_MS,
RACE_LOG_START_TIME_DIFFERENCE_IN_MS, RACE_LOG_FINISHING_TIME_AS_MILLIS,
/** @deprecated Replaced by {@link #REGATTA_LOG_FROM}; auto-migration from race log device mappings to regatta log is implemented */ @Deprecated RACE_LOG_FROM,
/** @deprecated Replaced by {@link #REGATTA_LOG_TO}; auto-migration from race log device mappings to regatta log is implemented */ @Deprecated RACE_LOG_TO,
/** @deprecated Replaced by a regatta log entry with type {@link #REGATTA_LOG_MARK} */ @Deprecated RACE_LOG_MARK,
/** @deprecated Replaced by WAYPOINT_PASSINGINSTRUCTIONS, still used to migrate old races*/ @Deprecated WAYPOINT_PASSINGSIDE,
/** @deprecated Replaced by CONTROLPOINTWITHTWOMARKS_ID, still used to migrate old races*/ @Deprecated GATE_ID,
/** @deprecated Replaced by CONTROLPOINTWITHTWOMARKS_NAME, still used to migrate old races*/ @Deprecated GATE_NAME,
@@ -107,7 +110,7 @@ public enum FieldNames {
REGATTA_LOG_IDENTIFIER_TYPE, REGATTA_LOG_IDENTIFIER_NAME, REGATTA_LOG_EVENT_ID, REGATTA_LOG_EVENT_CREATED_AT, REGATTA_LOG_EVENT_AUTHOR_NAME,
REGATTA_LOG_EVENT_AUTHOR_PRIORITY, REGATTA_LOG_EVENT_CLASS, REGATTA_LOG_REVOKED_EVENT_ID, REGATTA_LOG_REVOKED_EVENT_TYPE, REGATTA_LOG_REVOKED_EVENT_SHORT_INFO,
REGATTA_LOG_REVOKED_REASON, REGATTA_LOG_COMPETITOR_ID, REGATTA_LOG_DEVICE_MAPPING_EVENT_ID, REGATTA_LOG_CLOSING_TIMEPOINT,
REGATTA_LOG_FROM, REGATTA_LOG_TO, REGATTA_LOG_EVENT,
REGATTA_LOG_FROM, REGATTA_LOG_TO, REGATTA_LOG_EVENT, REGATTA_LOG_MARK,
// remote server reference fields
SERVER_NAME,
@@ -3,14 +3,14 @@ package com.sap.sailing.domain.persistence.impl;
import java.util.logging.Logger;
import com.mongodb.DBObject;
import com.sap.sailing.domain.abstractlog.race.RaceLogEndOfTrackingEvent;
import com.sap.sailing.domain.abstractlog.race.RaceLogFixedMarkPassingEvent;
import com.sap.sailing.domain.abstractlog.race.RaceLogCourseAreaChangedEvent;
import com.sap.sailing.domain.abstractlog.race.RaceLogCourseDesignChangedEvent;
import com.sap.sailing.domain.abstractlog.race.RaceLogDependentStartTimeEvent;
import com.sap.sailing.domain.abstractlog.race.RaceLogEndOfTrackingEvent;
import com.sap.sailing.domain.abstractlog.race.RaceLogEventVisitor;
import com.sap.sailing.domain.abstractlog.race.RaceLogFinishPositioningConfirmedEvent;
import com.sap.sailing.domain.abstractlog.race.RaceLogFinishPositioningListChangedEvent;
import com.sap.sailing.domain.abstractlog.race.RaceLogFixedMarkPassingEvent;
import com.sap.sailing.domain.abstractlog.race.RaceLogFlagEvent;
import com.sap.sailing.domain.abstractlog.race.RaceLogGateLineOpeningTimeEvent;
import com.sap.sailing.domain.abstractlog.race.RaceLogPassChangeEvent;
@@ -21,16 +21,13 @@ import com.sap.sailing.domain.abstractlog.race.RaceLogRevokeEvent;
import com.sap.sailing.domain.abstractlog.race.RaceLogStartOfTrackingEvent;
import com.sap.sailing.domain.abstractlog.race.RaceLogStartProcedureChangedEvent;
import com.sap.sailing.domain.abstractlog.race.RaceLogStartTimeEvent;
import com.sap.sailing.domain.abstractlog.race.RaceLogWindFixEvent;
import com.sap.sailing.domain.abstractlog.race.RaceLogSuppressedMarkPassingsEvent;
import com.sap.sailing.domain.abstractlog.race.RaceLogWindFixEvent;
import com.sap.sailing.domain.abstractlog.race.scoring.RaceLogAdditionalScoringInformationEvent;
import com.sap.sailing.domain.abstractlog.race.tracking.RaceLogCloseOpenEndedDeviceMappingEvent;
import com.sap.sailing.domain.abstractlog.race.tracking.RaceLogDefineMarkEvent;
import com.sap.sailing.domain.abstractlog.race.tracking.RaceLogDenoteForTrackingEvent;
import com.sap.sailing.domain.abstractlog.race.tracking.RaceLogDeviceCompetitorMappingEvent;
import com.sap.sailing.domain.abstractlog.race.tracking.RaceLogDeviceMarkMappingEvent;
import com.sap.sailing.domain.abstractlog.race.tracking.RaceLogRegisterCompetitorEvent;
import com.sap.sailing.domain.abstractlog.race.tracking.RaceLogStartTrackingEvent;
import com.sap.sailing.domain.abstractlog.race.tracking.RaceLogUseCompetitorsFromRaceLogEvent;
import com.sap.sailing.domain.persistence.MongoObjectFactory;
import com.sap.sailing.domain.racelog.RaceLogIdentifier;
@@ -125,18 +122,6 @@ public class MongoRaceLogStoreVisitor implements RaceLogEventVisitor {
mongoObjectFactory.storeRaceLogEventEvent(object);
}
@Override
public void visit(RaceLogDeviceCompetitorMappingEvent event) {
DBObject object = mongoObjectFactory.storeRaceLogEntry(raceLogIdentifier, event);
mongoObjectFactory.storeRaceLogEventEvent(object);
}
@Override
public void visit(RaceLogDeviceMarkMappingEvent event) {
DBObject object = mongoObjectFactory.storeRaceLogEntry(raceLogIdentifier, event);
mongoObjectFactory.storeRaceLogEventEvent(object);
}
@Override
public void visit(RaceLogDenoteForTrackingEvent event) {
DBObject object = mongoObjectFactory.storeRaceLogEntry(raceLogIdentifier, event);
@@ -161,18 +146,6 @@ public class MongoRaceLogStoreVisitor implements RaceLogEventVisitor {
mongoObjectFactory.storeRaceLogEventEvent(object);
}
@Override
public void visit(RaceLogDefineMarkEvent event) {
DBObject object = mongoObjectFactory.storeRaceLogEntry(raceLogIdentifier, event);
mongoObjectFactory.storeRaceLogEventEvent(object);
}
@Override
public void visit(RaceLogCloseOpenEndedDeviceMappingEvent event) {
DBObject object = mongoObjectFactory.storeRaceLogEntry(raceLogIdentifier, event);
mongoObjectFactory.storeRaceLogEventEvent(object);
}
@Override
public void visit(RaceLogAdditionalScoringInformationEvent event) {
DBObject object = mongoObjectFactory.storeRaceLogEntry(raceLogIdentifier, event);
@@ -208,4 +181,10 @@ public class MongoRaceLogStoreVisitor implements RaceLogEventVisitor {
DBObject object = mongoObjectFactory.storeRaceLogEntry(raceLogIdentifier, event);
mongoObjectFactory.storeRaceLogEventEvent(object);
}
@Override
public void visit(RaceLogUseCompetitorsFromRaceLogEvent event) {
DBObject object = mongoObjectFactory.storeRaceLogEntry(raceLogIdentifier, event);
mongoObjectFactory.storeRaceLogEventEvent(object);
}
}
@@ -4,6 +4,7 @@ import java.util.logging.Logger;
import com.sap.sailing.domain.abstractlog.regatta.RegattaLogEventVisitor;
import com.sap.sailing.domain.abstractlog.regatta.events.RegattaLogCloseOpenEndedDeviceMappingEvent;
import com.sap.sailing.domain.abstractlog.regatta.events.RegattaLogDefineMarkEvent;
import com.sap.sailing.domain.abstractlog.regatta.events.RegattaLogDeviceCompetitorMappingEvent;
import com.sap.sailing.domain.abstractlog.regatta.events.RegattaLogDeviceMarkMappingEvent;
import com.sap.sailing.domain.abstractlog.regatta.events.RegattaLogRegisterCompetitorEvent;
@@ -60,4 +61,9 @@ public class MongoRegattaLogStoreVisitor implements RegattaLogEventVisitor {
public void visit(RegattaLogSetCompetitorTimeOnDistanceAllowancePerNauticalMileEvent event) {
mongoObjectFactory.storeRegattaLogEvent(regattaLikeIdentifier, event);
}
@Override
public void visit(RegattaLogDefineMarkEvent event) {
mongoObjectFactory.storeRegattaLogEvent(regattaLikeIdentifier, event);
}
}
@@ -14,9 +14,9 @@ import com.mongodb.DBCollection;
import com.mongodb.DBCursor;
import com.mongodb.DBObject;
import com.mongodb.QueryBuilder;
import com.sap.sailing.domain.abstractlog.AbstractLog;
import com.sap.sailing.domain.abstractlog.shared.analyzing.DeviceCompetitorMappingFinder;
import com.sap.sailing.domain.abstractlog.shared.analyzing.DeviceMarkMappingFinder;
import com.sap.sailing.domain.abstractlog.regatta.RegattaLog;
import com.sap.sailing.domain.abstractlog.regatta.tracking.analyzing.impl.RegattaLogDeviceCompetitorMappingFinder;
import com.sap.sailing.domain.abstractlog.regatta.tracking.analyzing.impl.RegattaLogDeviceMarkMappingFinder;
import com.sap.sailing.domain.base.Competitor;
import com.sap.sailing.domain.base.Mark;
import com.sap.sailing.domain.common.racelog.tracking.TransformationException;
@@ -107,9 +107,9 @@ public class MongoGPSFixStoreImpl implements MongoGPSFixStore {
}
@Override
public void loadCompetitorTrack(DynamicGPSFixTrack<Competitor, GPSFixMoving> track, AbstractLog<?, ?> log, Competitor competitor)
public void loadCompetitorTrack(DynamicGPSFixTrack<Competitor, GPSFixMoving> track, RegattaLog log, Competitor competitor)
throws NoCorrespondingServiceRegisteredException, TransformationException{
List<DeviceMapping<Competitor>> mappings = new DeviceCompetitorMappingFinder<>(log).analyze().get(competitor);
List<DeviceMapping<Competitor>> mappings = new RegattaLogDeviceCompetitorMappingFinder(log).analyze().get(competitor);
if (mappings != null) {
for (DeviceMapping<Competitor> mapping : mappings) {
loadTrack(track, mapping.getDevice(), mapping.getTimeRange().from(), mapping.getTimeRange().to(), true /*inclusive*/);
@@ -118,9 +118,9 @@ public class MongoGPSFixStoreImpl implements MongoGPSFixStore {
}
@Override
public void loadMarkTrack(DynamicGPSFixTrack<Mark, GPSFix> track, AbstractLog<?, ?> log, Mark mark)
public void loadMarkTrack(DynamicGPSFixTrack<Mark, GPSFix> track, RegattaLog log, Mark mark)
throws NoCorrespondingServiceRegisteredException, TransformationException{
List<DeviceMapping<Mark>> mappings = new DeviceMarkMappingFinder<>(log).analyze().get(mark);
List<DeviceMapping<Mark>> mappings = new RegattaLogDeviceMarkMappingFinder(log).analyze().get(mark);
if (mappings != null) {
for (DeviceMapping<Mark> mapping : mappings) {
loadTrack(track, mapping.getDevice(), mapping.getTimeRange().from(), mapping.getTimeRange().to(), true /*inclusive*/);
@@ -192,9 +192,9 @@ public class MongoGPSFixStoreImpl implements MongoGPSFixStore {
}
@Override
public void loadCompetitorTrack(DynamicGPSFixTrack<Competitor, GPSFixMoving> track, AbstractLog<?, ?> log,
public void loadCompetitorTrack(DynamicGPSFixTrack<Competitor, GPSFixMoving> track, RegattaLog log,
Competitor competitor, TimePoint start, TimePoint end) throws TransformationException {
List<DeviceMapping<Competitor>> mappings = new DeviceCompetitorMappingFinder<>(log).analyze().get(competitor);
List<DeviceMapping<Competitor>> mappings = new RegattaLogDeviceCompetitorMappingFinder(log).analyze().get(competitor);
if (mappings != null) {
for (DeviceMapping<Competitor> mapping : mappings) {
final TimePoint from = Util.getLatestOfTimePoints(start, mapping.getTimeRange().from());
@@ -211,9 +211,9 @@ public class MongoGPSFixStoreImpl implements MongoGPSFixStore {
}
@Override
public void loadMarkTrack(DynamicGPSFixTrack<Mark, GPSFix> track, AbstractLog<?, ?> log, Mark mark,
public void loadMarkTrack(DynamicGPSFixTrack<Mark, GPSFix> track, RegattaLog log, Mark mark,
TimePoint start, TimePoint end) throws TransformationException, NoCorrespondingServiceRegisteredException {
List<DeviceMapping<Mark>> mappings = new DeviceMarkMappingFinder<>(log).analyze().get(mark);
List<DeviceMapping<Mark>> mappings = new RegattaLogDeviceMarkMappingFinder(log).analyze().get(mark);
if (mappings != null) {
for (DeviceMapping<Mark> mapping : mappings) {
final TimePoint from = Util.getLatestOfTimePoints(start, mapping.getTimeRange().from());
@@ -261,5 +261,4 @@ public class MongoGPSFixStoreImpl implements MongoGPSFixStore {
}
return ((Number) result.get(FieldNames.NUM_FIXES.name())).longValue();
}
}
@@ -3,6 +3,8 @@ package com.sap.sailing.domain.racelogtracking.test;
import static com.sap.sse.common.Util.size;
import static junit.framework.Assert.assertEquals;
import java.util.UUID;
import org.junit.After;
import org.junit.Before;
@@ -10,8 +12,10 @@ import com.sap.sailing.domain.abstractlog.AbstractLogEventAuthor;
import com.sap.sailing.domain.abstractlog.impl.LogEventAuthorImpl;
import com.sap.sailing.domain.abstractlog.race.RaceLog;
import com.sap.sailing.domain.abstractlog.race.impl.RaceLogImpl;
import com.sap.sailing.domain.abstractlog.race.tracking.impl.RaceLogDeviceCompetitorMappingEventImpl;
import com.sap.sailing.domain.abstractlog.race.tracking.impl.RaceLogDeviceMarkMappingEventImpl;
import com.sap.sailing.domain.abstractlog.regatta.RegattaLog;
import com.sap.sailing.domain.abstractlog.regatta.events.impl.RegattaLogDeviceCompetitorMappingEventImpl;
import com.sap.sailing.domain.abstractlog.regatta.events.impl.RegattaLogDeviceMarkMappingEventImpl;
import com.sap.sailing.domain.abstractlog.regatta.impl.RegattaLogImpl;
import com.sap.sailing.domain.base.Competitor;
import com.sap.sailing.domain.base.DomainFactory;
import com.sap.sailing.domain.base.Mark;
@@ -40,11 +44,12 @@ public class AbstractGPSFixStoreTest {
new MockDeviceAndSessionIdentifierWithGPSFixesDeserializer();
protected final DeviceIdentifier device = new SmartphoneImeiIdentifier("a");
protected RaceLog raceLog;
protected RegattaLog regattaLog;
protected GPSFixStore store;
protected final Competitor comp = DomainFactory.INSTANCE.getOrCreateCompetitor("comp", "comp", null, null, null, null, null, /* timeOnTimeFactor */ null, /* timeOnDistanceAllowanceInSecondsPerNauticalMile */ null);
protected final Mark mark = DomainFactory.INSTANCE.getOrCreateMark("mark");
private final AbstractLogEventAuthor author = new LogEventAuthorImpl("author", 0);
protected final AbstractLogEventAuthor author = new LogEventAuthorImpl("author", 0);
protected GPSFixMoving createFix(long millis, double lat, double lng, double knots, double degrees) {
return new GPSFixMovingImpl(new DegreePosition(lat, lng),
@@ -55,6 +60,7 @@ public class AbstractGPSFixStoreTest {
public void setServiceAndRaceLog() {
service = new RacingEventServiceImpl(null, null, serviceFinderFactory);
raceLog = new RaceLogImpl("racelog");
regattaLog = new RegattaLogImpl("regattalog");
store = new MongoGPSFixStoreImpl(service.getMongoObjectFactory(), service.getDomainObjectFactory(),
serviceFinderFactory);
}
@@ -66,17 +72,17 @@ public class AbstractGPSFixStoreTest {
mongoOF.getGPSFixMetadataCollection().drop();
}
protected void map(RaceLog raceLog, Competitor comp, DeviceIdentifier device, long from, long to) {
raceLog.add(new RaceLogDeviceCompetitorMappingEventImpl(MillisecondsTimePoint.now(), author, 0,
protected void map(RegattaLog regattaLog, Competitor comp, DeviceIdentifier device, long from, long to) {
regattaLog.add(new RegattaLogDeviceCompetitorMappingEventImpl(MillisecondsTimePoint.now(), MillisecondsTimePoint.now(), author, UUID.randomUUID(),
comp, device, new MillisecondsTimePoint(from), new MillisecondsTimePoint(to)));
}
protected void map(Competitor comp, DeviceIdentifier device, long from, long to) {
map(raceLog, comp, device, from, to);
map(regattaLog, comp, device, from, to);
}
protected void map(Mark mark, DeviceIdentifier device, long from, long to) {
raceLog.add(new RaceLogDeviceMarkMappingEventImpl(MillisecondsTimePoint.now(), author, 0,
regattaLog.add(new RegattaLogDeviceMarkMappingEventImpl(MillisecondsTimePoint.now(), MillisecondsTimePoint.now(), author, UUID.randomUUID(),
mark, device, new MillisecondsTimePoint(from), new MillisecondsTimePoint(to)));
}
@@ -19,8 +19,8 @@ import org.junit.rules.ExpectedException;
import com.sap.sailing.domain.abstractlog.AbstractLogEventAuthor;
import com.sap.sailing.domain.abstractlog.race.RaceLog;
import com.sap.sailing.domain.abstractlog.race.tracking.impl.RaceLogDeviceCompetitorMappingEventImpl;
import com.sap.sailing.domain.abstractlog.race.tracking.impl.RaceLogRegisterCompetitorEventImpl;
import com.sap.sailing.domain.abstractlog.race.tracking.impl.RaceLogUseCompetitorsFromRaceLogEventImpl;
import com.sap.sailing.domain.abstractlog.regatta.RegattaLog;
import com.sap.sailing.domain.abstractlog.regatta.events.impl.RegattaLogDeviceCompetitorMappingEventImpl;
import com.sap.sailing.domain.abstractlog.regatta.events.impl.RegattaLogRegisterCompetitorEventImpl;
@@ -160,6 +160,7 @@ public class CreateAndTrackWithRaceLogTest {
Exception {
RaceColumn column = leaderboard.getRaceColumnByName(columnName);
RegattaLog regattaLog = leaderboard.getRegattaLike().getRegattaLog();
RaceLog raceLog = column.getRaceLog(fleet);
// can denote racelog for tracking
@@ -171,10 +172,10 @@ public class CreateAndTrackWithRaceLogTest {
Competitor comp1 = DomainFactory.INSTANCE.getOrCreateCompetitor("comp1", "comp1", null, null, null, null, null,
/* timeOnTimeFactor */ null, /* timeOnDistanceAllowancePerNauticalMile */ null);
DeviceIdentifier dev1 = new SmartphoneImeiIdentifier("dev1");
raceLog.add(new RaceLogDeviceCompetitorMappingEventImpl(t(), author, 0, comp1, dev1, t(0), t(10)));
regattaLog.add(new RegattaLogDeviceCompetitorMappingEventImpl(t(), t(), author, 0, comp1, dev1, t(0), t(10)));
addFixes0(dev1);
raceLog.add(new RaceLogUseCompetitorsFromRaceLogEventImpl(t(), author, t(), UUID.randomUUID(), 0));
raceLog.add(new RaceLogRegisterCompetitorEventImpl(t(), author, 0, comp1));
// start tracking
adapter.startTracking(service, leaderboard, column, fleet);
@@ -182,9 +183,9 @@ public class CreateAndTrackWithRaceLogTest {
TrackedRace race = column.getTrackedRace(fleet);
assertNotNull(race);
race.waitForLoadingFromGPSFixStoreToFinishRunning(raceLog);
race.waitForLoadingFromGPSFixStoreToFinishRunning(regattaLog);
addFixes1(race, comp1, dev1);
raceLog.add(new RaceLogDeviceCompetitorMappingEventImpl(t(), author, 0, comp1, dev1, t(11), t(20)));
regattaLog.add(new RegattaLogDeviceCompetitorMappingEventImpl(t(), t(), author, 0, comp1, dev1, t(11), t(20)));
// add another mapping on the fly, other old fixes should be loaded
addFixes2(race, comp1, dev1);
@@ -1,9 +1,6 @@
package com.sap.sailing.domain.racelogtracking.test.impl;
import static junit.framework.Assert.assertEquals;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.lessThanOrEqualTo;
import static org.mockito.Mockito.mock;
import java.util.Arrays;
@@ -11,9 +8,8 @@ import java.util.Collections;
import org.junit.Test;
import com.sap.sailing.domain.abstractlog.race.RaceLog;
import com.sap.sailing.domain.abstractlog.race.analyzing.impl.RaceLogResolver;
import com.sap.sailing.domain.abstractlog.race.impl.RaceLogImpl;
import com.sap.sailing.domain.abstractlog.regatta.events.impl.RegattaLogDefineMarkEventImpl;
import com.sap.sailing.domain.base.BoatClass;
import com.sap.sailing.domain.base.Competitor;
import com.sap.sailing.domain.base.Course;
@@ -27,7 +23,6 @@ import com.sap.sailing.domain.base.impl.RaceDefinitionImpl;
import com.sap.sailing.domain.base.impl.RegattaImpl;
import com.sap.sailing.domain.base.impl.WaypointImpl;
import com.sap.sailing.domain.common.racelog.tracking.TransformationException;
import com.sap.sailing.domain.common.tracking.GPSFixMoving;
import com.sap.sailing.domain.racelog.impl.EmptyRaceLogStore;
import com.sap.sailing.domain.racelog.tracking.test.mock.SmartphoneImeiIdentifier;
import com.sap.sailing.domain.racelogtracking.DeviceIdentifier;
@@ -35,7 +30,6 @@ import com.sap.sailing.domain.racelogtracking.test.AbstractGPSFixStoreTest;
import com.sap.sailing.domain.ranking.OneDesignRankingMetric;
import com.sap.sailing.domain.regattalog.impl.EmptyRegattaLogStore;
import com.sap.sailing.domain.tracking.TrackedRegatta;
import com.sap.sailing.domain.tracking.impl.AbstractRaceChangeListener;
import com.sap.sailing.domain.tracking.impl.DynamicTrackedRaceImpl;
import com.sap.sailing.domain.tracking.impl.DynamicTrackedRegattaImpl;
import com.sap.sailing.domain.tracking.impl.EmptyWindStore;
@@ -46,10 +40,6 @@ import com.sap.sse.common.impl.TimeRangeImpl;
public class TrackedRaceLoadsFixesTest extends AbstractGPSFixStoreTest {
private final BoatClass boatClass = DomainFactory.INSTANCE.getOrCreateBoatClass("49er");
private int numberOfSwitchesBetweenLoadingRaceLogs = 0;
private Integer previouslyLoading = null;
private int numFixesReceived = 0;
@Test
public void doesRaceLoadOnlyBetweenStartAndEndOfTracking() throws TransformationException,
NoCorrespondingServiceRegisteredException, InterruptedException {
@@ -57,6 +47,8 @@ public class TrackedRaceLoadsFixesTest extends AbstractGPSFixStoreTest {
/* timeOnTimeFactor */ null, /* timeOnDistanceAllowancePerNauticalMile */ null);
Mark mark2 = DomainFactory.INSTANCE.getOrCreateMark("mark2");
DeviceIdentifier markDevice = new SmartphoneImeiIdentifier("imei2");
regattaLog.add(new RegattaLogDefineMarkEventImpl(new MillisecondsTimePoint(1), author, new MillisecondsTimePoint(1), 0, mark));
regattaLog.add(new RegattaLogDefineMarkEventImpl(new MillisecondsTimePoint(2), author, new MillisecondsTimePoint(1), 0, mark2));
Course course = new CourseImpl("course", Arrays.asList(new Waypoint[] { new WaypointImpl(mark),
new WaypointImpl(mark2) }));
RaceDefinition race = new RaceDefinitionImpl("race", course, boatClass, Arrays.asList(new Competitor[] { comp, comp2 }));
@@ -80,7 +72,8 @@ public class TrackedRaceLoadsFixesTest extends AbstractGPSFixStoreTest {
trackedRace.setEndOfTrackingReceived(new MillisecondsTimePoint(2000));
trackedRace.attachRaceLog(raceLog);
trackedRace.waitForLoadingFromGPSFixStoreToFinishRunning(raceLog);
trackedRace.attachRegattaLog(regattaLog);
trackedRace.waitForLoadingFromGPSFixStoreToFinishRunning(regattaLog);
testNumberOfRawFixes(trackedRace.getTrack(comp), 1);
testNumberOfRawFixes(trackedRace.getOrCreateTrack(mark), 1);
@@ -99,6 +92,8 @@ public class TrackedRaceLoadsFixesTest extends AbstractGPSFixStoreTest {
Competitor comp2 = DomainFactory.INSTANCE.getOrCreateCompetitor("comp2", "comp2", null, null, null, null, null,
/* timeOnTimeFactor */ null, /* timeOnDistanceAllowancePerNauticalMile */ null);
Mark mark2 = DomainFactory.INSTANCE.getOrCreateMark("mark2");
regattaLog.add(new RegattaLogDefineMarkEventImpl(new MillisecondsTimePoint(1), author, new MillisecondsTimePoint(1), 0, mark));
regattaLog.add(new RegattaLogDefineMarkEventImpl(new MillisecondsTimePoint(2), author, new MillisecondsTimePoint(1), 0, mark2));
DeviceIdentifier device2 = new SmartphoneImeiIdentifier("imei2");
DeviceIdentifier device3 = new SmartphoneImeiIdentifier("imei3");
Course course = new CourseImpl("course", Arrays.asList(new Waypoint[] { new WaypointImpl(mark),
@@ -128,9 +123,10 @@ public class TrackedRaceLoadsFixesTest extends AbstractGPSFixStoreTest {
DynamicTrackedRaceImpl trackedRace = new DynamicTrackedRaceImpl(regatta, race,
Collections.<Sideline> emptyList(), EmptyWindStore.INSTANCE, store, 0, 0, 0, /*useMarkPassingCalculator*/ false,
OneDesignRankingMetric::new, mock(RaceLogResolver.class));
trackedRace.attachRaceLog(raceLog);
trackedRace.waitForLoadingFromGPSFixStoreToFinishRunning(raceLog);
trackedRace.attachRegattaLog(regattaLog);
trackedRace.waitForLoadingFromGPSFixStoreToFinishRunning(regattaLog);
testNumberOfRawFixes(trackedRace.getTrack(comp), 10002);
testNumberOfRawFixes(trackedRace.getTrack(comp2), 1);
@@ -151,53 +147,4 @@ public class TrackedRaceLoadsFixesTest extends AbstractGPSFixStoreTest {
assertEquals(2, store.getNumberOfFixes(device));
assertEquals(TimeRangeImpl.create(100, 200), store.getTimeRangeCoveredByFixes(device));
}
@Test
public void attachTwoRaceLogsAndSeeIfLoadingIsSerializedNicely() throws TransformationException,
NoCorrespondingServiceRegisteredException, InterruptedException {
Course course = new CourseImpl("course", Collections.<Waypoint> emptyList());
RaceDefinition race = new RaceDefinitionImpl("race", course, boatClass,
Arrays.asList(new Competitor[] { comp }));
RaceLog raceLog2 = new RaceLogImpl("raceLog 2");
final int numFixes = 10000;
map(comp, device, 0, numFixes / 2);
map(raceLog2, comp, device, numFixes / 2 + 1, numFixes);
for (int i = 0; i < numFixes; i++) {
store.storeFix(device, createFix(i, 10, 20, 30, 40));
}
TrackedRegatta regatta = new DynamicTrackedRegattaImpl(new RegattaImpl(EmptyRaceLogStore.INSTANCE,
EmptyRegattaLogStore.INSTANCE, RegattaImpl.getDefaultName("regatta", boatClass.getName()), boatClass, /* startDate */
null, /* endDate */null, null, null, "a", null));
DynamicTrackedRaceImpl trackedRace = new DynamicTrackedRaceImpl(regatta, race,
Collections.<Sideline> emptyList(), EmptyWindStore.INSTANCE, store, 0, 0, 0, /*useMarkPassingCalculator*/ false,
OneDesignRankingMetric::new, mock(RaceLogResolver.class));
trackedRace.addListener(new AbstractRaceChangeListener() {
@Override
public void competitorPositionChanged(GPSFixMoving fix, Competitor competitor) {
numFixesReceived++;
int currentlyLoading = fix.getTimePoint().asMillis() <= numFixes / 2 ? 1 : 2;
if (previouslyLoading == null) {
previouslyLoading = currentlyLoading;
} else if (previouslyLoading != currentlyLoading) {
previouslyLoading = currentlyLoading;
numberOfSwitchesBetweenLoadingRaceLogs++;
}
}
});
trackedRace.attachRaceLog(raceLog);
trackedRace.attachRaceLog(raceLog2);
trackedRace.waitForLoadingFromGPSFixStoreToFinishRunning(raceLog);
trackedRace.waitForLoadingFromGPSFixStoreToFinishRunning(raceLog2);
assertThat("switch at most once between the two race logs while loading",
numberOfSwitchesBetweenLoadingRaceLogs, lessThanOrEqualTo(1));
assertThat("number of fixes added to race equal to number of fixes in GPSFixStore", numFixesReceived,
equalTo(numFixes));
}
}
@@ -5,7 +5,6 @@ import java.util.Set;
import com.sap.sailing.domain.abstractlog.race.RaceLog;
import com.sap.sailing.domain.abstractlog.race.RaceLogCourseDesignChangedEvent;
import com.sap.sailing.domain.abstractlog.race.tracking.RaceLogDefineMarkEvent;
import com.sap.sailing.domain.abstractlog.race.tracking.RaceLogDenoteForTrackingEvent;
import com.sap.sailing.domain.abstractlog.race.tracking.RaceLogStartTrackingEvent;
import com.sap.sailing.domain.abstractlog.regatta.RegattaLog;
@@ -26,6 +25,7 @@ import com.sap.sailing.domain.racelogtracking.impl.RaceLogRaceTracker;
import com.sap.sailing.domain.tracking.RaceHandle;
import com.sap.sailing.domain.tracking.TrackedRace;
import com.sap.sailing.server.RacingEventService;
import com.sap.sse.common.Util.Pair;
import com.sap.sse.common.mail.MailException;
public interface RaceLogTrackingAdapter {
@@ -76,27 +76,11 @@ public interface RaceLogTrackingAdapter {
throws NotDenotableForRaceLogTrackingException;
/**
* @see #pingMark(RaceLog, Mark, GPSFix, RacingEventService) using a random {@link PingDeviceIdentifier}
*/
void pingMark(RaceLog raceLogToAddTo, Mark mark, GPSFix gpsFix, RacingEventService service);
/**
* @see #pingMark(RaceLog, Mark, GPSFix, RacingEventService)
* Add a fix to the {@link GPSFixStore}, and create a mapping with a virtual device for exactly that time point
* in the {@code regattaLogToAddTo}, mapping the virtual device to the {@code mark}.
*/
void pingMark(RegattaLog regattaLogToAddTo, Mark mark, GPSFix gpsFix, RacingEventService service);
/**
* If not yet registered, register the competitors in {@code competitors}, and unregister all already registered
* competitors not in {@code competitors}.
*/
void registerCompetitors(RacingEventService service, RaceLog raceLog, Set<Competitor> competitors);
/**
* If not yet registered, register the competitors in {@code competitors}, and unregister all already registered
* competitors not in {@code competitors}.
*/
void registerCompetitors(RacingEventService service, RegattaLog regattaLog, Set<Competitor> competitors);
/**
* Invite competitors for tracking via the Tracking App by sending out emails.
*
@@ -114,16 +98,11 @@ public interface RaceLogTrackingAdapter {
String emails, Locale locale) throws MailException;
/**
* Duplicate the course in the newest {@link RaceLogCourseDesignChangedEvent} in {@code from} race log to the
* {@code to} race logs. The {@link Mark}s and {@link ControlPoint}s are duplicated and not reused. This also
* inserts the necessary {@link RaceLogDefineMarkEvent}s into the {@code to} race logs.
* Copy the course in the newest {@link RaceLogCourseDesignChangedEvent} in {@code from} race log to the {@code to}
* race logs. The {@link Mark}s and {@link ControlPoint}s are reused and not duplicated.
*/
void copyCourse(RaceLog fromRaceLog, Set<RaceLog> toRaceLogs, SharedDomainFactory baseDomainFactory,
RacingEventService service);
/**
* Duplicate the competitor registrations from the {@code from} race log to the {@code to} race logs.
*/
void copyCompetitors(RaceLog from, Set<RaceLog> to,
RacingEventService service);
void copyCompetitors(RaceColumn fromRaceColumn, Fleet fromFleet, Iterable<Pair<RaceColumn, Fleet>> toRaces);
}
@@ -9,12 +9,14 @@ import com.sap.sailing.domain.abstractlog.race.RaceLog;
import com.sap.sailing.domain.abstractlog.race.analyzing.impl.RaceLogResolver;
import com.sap.sailing.domain.abstractlog.race.tracking.analyzing.impl.RaceInformationFinder;
import com.sap.sailing.domain.abstractlog.race.tracking.analyzing.impl.RaceLogTrackingStateAnalyzer;
import com.sap.sailing.domain.abstractlog.regatta.RegattaLog;
import com.sap.sailing.domain.base.BoatClass;
import com.sap.sailing.domain.base.DomainFactory;
import com.sap.sailing.domain.base.Fleet;
import com.sap.sailing.domain.base.RaceColumn;
import com.sap.sailing.domain.base.Regatta;
import com.sap.sailing.domain.base.impl.RegattaImpl;
import com.sap.sailing.domain.common.racelog.tracking.DoesNotHaveRegattaLogException;
import com.sap.sailing.domain.common.racelog.tracking.RaceNotCreatedException;
import com.sap.sailing.domain.leaderboard.Leaderboard;
import com.sap.sailing.domain.racelog.tracking.GPSFixStore;
@@ -97,6 +99,14 @@ public class RaceLogConnectivityParams implements RaceTrackingConnectivityParame
public Leaderboard getLeaderboard() {
return leaderboard;
}
public RegattaLog getRegattaLog() throws DoesNotHaveRegattaLogException {
if (leaderboard instanceof HasRegattaLike) {
return (((HasRegattaLike) leaderboard).getRegattaLike().getRegattaLog());
} else {
throw new DoesNotHaveRegattaLogException();
}
}
public RacingEventService getService() {
return service;
@@ -13,9 +13,6 @@ import java.util.logging.Level;
import java.util.logging.Logger;
import com.sap.sailing.domain.abstractlog.AbstractLog;
import com.sap.sailing.domain.abstractlog.MultiLogAnalyzer;
import com.sap.sailing.domain.abstractlog.MultiLogAnalyzer.MapWithValueCollectionReducer;
import com.sap.sailing.domain.abstractlog.MultiLogAnalyzer.SetReducer;
import com.sap.sailing.domain.abstractlog.race.RaceLog;
import com.sap.sailing.domain.abstractlog.race.RaceLogCourseDesignChangedEvent;
import com.sap.sailing.domain.abstractlog.race.RaceLogEndOfTrackingEvent;
@@ -24,23 +21,18 @@ import com.sap.sailing.domain.abstractlog.race.RaceLogStartOfTrackingEvent;
import com.sap.sailing.domain.abstractlog.race.analyzing.impl.LastPublishedCourseDesignFinder;
import com.sap.sailing.domain.abstractlog.race.analyzing.impl.RaceLogResolver;
import com.sap.sailing.domain.abstractlog.race.impl.BaseRaceLogEventVisitor;
import com.sap.sailing.domain.abstractlog.race.tracking.RaceLogDefineMarkEvent;
import com.sap.sailing.domain.abstractlog.race.tracking.RaceLogDenoteForTrackingEvent;
import com.sap.sailing.domain.abstractlog.race.tracking.RaceLogDeviceCompetitorMappingEvent;
import com.sap.sailing.domain.abstractlog.race.tracking.RaceLogDeviceMarkMappingEvent;
import com.sap.sailing.domain.abstractlog.race.tracking.RaceLogStartTrackingEvent;
import com.sap.sailing.domain.abstractlog.race.tracking.analyzing.impl.RaceInformationFinder;
import com.sap.sailing.domain.abstractlog.race.tracking.analyzing.impl.RaceLogTrackingStateAnalyzer;
import com.sap.sailing.domain.abstractlog.regatta.RegattaLog;
import com.sap.sailing.domain.abstractlog.regatta.RegattaLogEventVisitor;
import com.sap.sailing.domain.abstractlog.regatta.events.RegattaLogDefineMarkEvent;
import com.sap.sailing.domain.abstractlog.regatta.events.RegattaLogDeviceCompetitorMappingEvent;
import com.sap.sailing.domain.abstractlog.regatta.events.RegattaLogDeviceMarkMappingEvent;
import com.sap.sailing.domain.abstractlog.regatta.impl.BaseRegattaLogEventVisitor;
import com.sap.sailing.domain.abstractlog.shared.analyzing.DeviceCompetitorMappingFinder;
import com.sap.sailing.domain.abstractlog.shared.analyzing.DeviceMarkMappingFinder;
import com.sap.sailing.domain.abstractlog.shared.analyzing.RegisteredCompetitorsAnalyzer;
import com.sap.sailing.domain.abstractlog.shared.events.DeviceCompetitorMappingEvent;
import com.sap.sailing.domain.abstractlog.shared.events.DeviceMarkMappingEvent;
import com.sap.sailing.domain.abstractlog.regatta.tracking.analyzing.impl.RegattaLogDeviceCompetitorMappingFinder;
import com.sap.sailing.domain.abstractlog.regatta.tracking.analyzing.impl.RegattaLogDeviceMarkMappingFinder;
import com.sap.sailing.domain.base.BoatClass;
import com.sap.sailing.domain.base.Competitor;
import com.sap.sailing.domain.base.ControlPoint;
@@ -60,6 +52,7 @@ import com.sap.sailing.domain.common.PassingInstruction;
import com.sap.sailing.domain.common.RegattaAndRaceIdentifier;
import com.sap.sailing.domain.common.TrackedRaceStatusEnum;
import com.sap.sailing.domain.common.abstractlog.NotRevokableException;
import com.sap.sailing.domain.common.racelog.tracking.DoesNotHaveRegattaLogException;
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.TransformationException;
@@ -75,6 +68,7 @@ import com.sap.sailing.domain.tracking.DynamicTrackedRace;
import com.sap.sailing.domain.tracking.DynamicTrackedRegatta;
import com.sap.sailing.domain.tracking.RaceHandle;
import com.sap.sailing.domain.tracking.RaceTracker;
import com.sap.sailing.domain.tracking.TrackedRace;
import com.sap.sailing.domain.tracking.WindStore;
import com.sap.sailing.domain.tracking.WindTrack;
import com.sap.sailing.domain.tracking.impl.TrackedRaceStatusImpl;
@@ -128,21 +122,6 @@ public class RaceLogRaceTracker implements RaceTracker, GPSFixReceivedListener {
for (AbstractLog<?, ?> log : params.getLogHierarchy()) {
if (log instanceof RaceLog) {
RaceLogEventVisitor visitor = new BaseRaceLogEventVisitor() {
@Override
public void visit(RaceLogDeviceCompetitorMappingEvent event) {
RaceLogRaceTracker.this.onDeviceCompetitorMappingEvent(event);
}
@Override
public void visit(RaceLogDeviceMarkMappingEvent event) {
RaceLogRaceTracker.this.onDeviceMarkMappingEvent(event);
}
@Override
public void visit(RaceLogDefineMarkEvent event) {
RaceLogRaceTracker.this.onDefineMarkEvent(event);
}
@Override
public void visit(RaceLogStartTrackingEvent event) {
RaceLogRaceTracker.this.onStartTrackingEvent(event);
@@ -174,6 +153,11 @@ public class RaceLogRaceTracker implements RaceTracker, GPSFixReceivedListener {
public void visit(RegattaLogDeviceMarkMappingEvent event) {
RaceLogRaceTracker.this.onDeviceMarkMappingEvent(event);
}
@Override
public void visit(RegattaLogDefineMarkEvent event) {
RaceLogRaceTracker.this.onDefineMarkEvent(event);
}
};
visitors.put(log, visitor);
((RegattaLog) log).addListener(visitor);
@@ -247,14 +231,12 @@ public class RaceLogRaceTracker implements RaceTracker, GPSFixReceivedListener {
return params.getRaceLog().getId();
}
private Map<Competitor, List<DeviceMapping<Competitor>>> getNewCompetitorMappings() {
return new MultiLogAnalyzer<>(new DeviceCompetitorMappingFinder.Factory(),
new MapWithValueCollectionReducer<>(), params.getLogHierarchy()).analyze();
private Map<Competitor, List<DeviceMapping<Competitor>>> getNewCompetitorMappings() throws DoesNotHaveRegattaLogException {
return new RegattaLogDeviceCompetitorMappingFinder(params.getRegattaLog()).analyze();
}
private Map<Mark, List<DeviceMapping<Mark>>> getNewMarkMappings() {
return new MultiLogAnalyzer<>(new DeviceMarkMappingFinder.Factory(), new MapWithValueCollectionReducer<>(),
params.getLogHierarchy()).analyze();
private Map<Mark, List<DeviceMapping<Mark>>> getNewMarkMappings() throws DoesNotHaveRegattaLogException {
return new RegattaLogDeviceMarkMappingFinder(params.getRegattaLog()).analyze();
}
/**
@@ -266,34 +248,41 @@ public class RaceLogRaceTracker implements RaceTracker, GPSFixReceivedListener {
if (trackingTimesFromRaceLog == null) {
TimePoint earliestMappingStart = new MillisecondsTimePoint(Long.MAX_VALUE);
TimePoint latestMappingEnd = new MillisecondsTimePoint(Long.MIN_VALUE);
for (List<? extends DeviceMapping<?>> list : competitorMappings.values()) {
for (DeviceMapping<?> mapping : list) {
if (mapping.getTimeRange().from().before(earliestMappingStart)) {
earliestMappingStart = mapping.getTimeRange().from();
}
if (mapping.getTimeRange().to().after(latestMappingEnd)) {
latestMappingEnd = mapping.getTimeRange().to();
}
earliestMappingStart = getUpdatedEarliestMappingStart(earliestMappingStart, mapping.getTimeRange().from());
latestMappingEnd = getUpdatedLatestMappingEnd(latestMappingEnd, mapping.getTimeRange().to());
}
}
for (List<? extends DeviceMapping<?>> list : markMappings.values()) {
for (DeviceMapping<?> mapping : list) {
if (mapping.getTimeRange().from().before(earliestMappingStart)) {
earliestMappingStart = mapping.getTimeRange().from();
}
if (mapping.getTimeRange().to().after(latestMappingEnd)) {
latestMappingEnd = mapping.getTimeRange().to();
}
earliestMappingStart = getUpdatedEarliestMappingStart(earliestMappingStart, mapping.getTimeRange().from());
latestMappingEnd = getUpdatedLatestMappingEnd(latestMappingEnd, mapping.getTimeRange().to());
}
}
trackedRace.setStartOfTrackingReceived(earliestMappingStart);
trackedRace.setEndOfTrackingReceived(latestMappingEnd);
trackedRace.setStartOfTrackingReceived(earliestMappingStart == null ? TimePoint.BeginningOfTime : earliestMappingStart);
trackedRace.setEndOfTrackingReceived(latestMappingEnd == null ? TimePoint.EndOfTime : latestMappingEnd);
}
}
private TimePoint getUpdatedEarliestMappingStart(TimePoint earliestMappingStart, final TimePoint from) {
if (from == null) {
earliestMappingStart = null; // no further updates; one open interval means startOfTracking shall be the beginning of time
} else if (earliestMappingStart != null && from.before(earliestMappingStart)) {
earliestMappingStart = from;
}
return earliestMappingStart;
}
private TimePoint getUpdatedLatestMappingEnd(TimePoint latestMappingEnd, final TimePoint to) {
if (to == null) {
latestMappingEnd = null; // no further updates; one open interval means startOfTracking shall be the beginning of time
} else if (latestMappingEnd != null && to.after(latestMappingEnd)) {
latestMappingEnd = to;
}
return latestMappingEnd;
}
private <ItemT extends WithID, FixT extends GPSFix> boolean hasMappingAlreadyBeenLoaded(
DeviceMapping<ItemT> newMapping, List<DeviceMapping<ItemT>> oldMappings) {
if (oldMappings == null) {
@@ -326,7 +315,16 @@ public class RaceLogRaceTracker implements RaceTracker, GPSFixReceivedListener {
return result;
}
private void updateMarkMappings(boolean loadIfNotCovered) {
/**
* Adjusts the contents of {@link #markMappings} according to the device mappings for marks found in the regatta
* log. Afterwards, the start end end of tracking is {@link #updateStartAndEndOfTracking() updated}.
*
* @param loadIfNotCovered
* If <code>true</code>, for additional time ranges added compared to the previous contents of
* {@link #markMappings}, their fixes are loaded from the {@link #gpsFixStore}.
* @throws DoesNotHaveRegattaLogException
*/
private void updateMarkMappings(boolean loadIfNotCovered) throws DoesNotHaveRegattaLogException {
assert trackedRace != null;
// TODO remove fixes, if mappings have been removed
// check if there are new time ranges not covered so far
@@ -360,9 +358,13 @@ public class RaceLogRaceTracker implements RaceTracker, GPSFixReceivedListener {
updateStartAndEndOfTracking();
}
private void onDeviceMarkMappingEvent(DeviceMarkMappingEvent<?> event) {
private void onDeviceMarkMappingEvent(RegattaLogDeviceMarkMappingEvent event) {
if (trackedRace != null) {
updateMarkMappings(true);
try {
updateMarkMappings(true);
} catch (DoesNotHaveRegattaLogException e) {
logger.warning("Could not load update mark mappings as RegattaLog couldn't be found");
}
gpsFixStore.addListener(this, event.getDevice());
}
}
@@ -373,20 +375,35 @@ public class RaceLogRaceTracker implements RaceTracker, GPSFixReceivedListener {
* {@link RaceLogDefineMarkEvent} is received, the existence of the track for that mark in the {@link TrackedRace}
* has to be ensured, also ensuring that the mark will exist in the mark tracks map key set.
*/
private void onDefineMarkEvent(RaceLogDefineMarkEvent event) {
private void onDefineMarkEvent(RegattaLogDefineMarkEvent event) {
if (trackedRace != null) {
trackedRace.getOrCreateTrack(event.getMark());
}
}
private void onDeviceCompetitorMappingEvent(DeviceCompetitorMappingEvent<?> event) {
private void onDeviceCompetitorMappingEvent(RegattaLogDeviceCompetitorMappingEvent event) {
if (trackedRace != null) {
updateCompetitorMappings(true);
try {
updateCompetitorMappings(true);
} catch (DoesNotHaveRegattaLogException e) {
logger.warning("Could not load update competitor mappings as RegattaLog couldn't be found");
}
gpsFixStore.addListener(this, event.getDevice());
}
}
private void updateCompetitorMappings(boolean loadIfNotCovered) {
/**
* Adjusts the {@link #competitorMappings} map according to the competitor registrations for the race managed by
* this tracked, either from the regatta log or the race log. Then, the {@link TrackedRace}'s start and end of
* tracking time frame is {@link #updateStartAndEndOfTracking() updated} from the mapping intervals.
*
* @param loadIfNotCovered
* if <code>true</code>, the GPS fixes for the mappings will be loaded based on a comparison of the
* previous mappings from {@link #competitorMappings} and the new mappings.
*
* @throws DoesNotHaveRegattaLogException
*/
private void updateCompetitorMappings(boolean loadIfNotCovered) throws DoesNotHaveRegattaLogException {
// TODO remove fixes, if mappings have been removed
// check if there are new time ranges not covered so far
@@ -466,9 +483,7 @@ public class RaceLogRaceTracker implements RaceTracker, GPSFixReceivedListener {
}
throw new RaceNotCreatedException(String.format("Race for racelog (%s) has already been created", raceLog));
}
// check both the racelog and regattalog for registered competitors
Set<Competitor> competitors = new MultiLogAnalyzer<>(RegisteredCompetitorsAnalyzer.Factory.INSTANCE,
new SetReducer<Competitor>(), params.getLogHierarchy()).analyze();
Iterable<Competitor> competitors = raceColumn.getAllCompetitors(params.getFleet());
Serializable raceId = denoteEvent.getRaceId();
final RaceDefinition raceDef = new RaceDefinitionImpl(raceName, course, boatClass, competitors, raceId);
Iterable<Sideline> sidelines = Collections.<Sideline> emptyList();
@@ -486,8 +501,12 @@ public class RaceLogRaceTracker implements RaceTracker, GPSFixReceivedListener {
}
}
// update the device mappings (without loading the fixes, as the TrackedRace does this itself on startup)
updateCompetitorMappings(false);
updateMarkMappings(false);
try {
updateCompetitorMappings(false);
updateMarkMappings(false);
} catch (DoesNotHaveRegattaLogException e) {
logger.warning("Could not load update mark and competitor mappings as RegattaLog couldn't be found");
}
// add listeners for devices in mappings already present
addListeners(competitorMappings);
addListeners(markMappings);
@@ -3,13 +3,12 @@ package com.sap.sailing.domain.racelogtracking.impl;
import java.io.IOException;
import java.io.InputStream;
import java.util.HashSet;
import java.util.List;
import java.util.Locale;
import java.util.Set;
import java.util.UUID;
import java.util.function.Function;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.stream.StreamSupport;
import javax.activation.DataHandler;
import javax.activation.DataSource;
@@ -22,33 +21,19 @@ import javax.mail.util.ByteArrayDataSource;
import org.osgi.framework.ServiceReference;
import com.google.zxing.WriterException;
import com.sap.sailing.domain.abstractlog.AbstractLog;
import com.sap.sailing.domain.abstractlog.AbstractLogEvent;
import com.sap.sailing.domain.abstractlog.AbstractLogEventAuthor;
import com.sap.sailing.domain.abstractlog.impl.AllEventsOfTypeFinder;
import com.sap.sailing.domain.abstractlog.impl.LastEventOfTypeFinder;
import com.sap.sailing.domain.abstractlog.race.RaceLog;
import com.sap.sailing.domain.abstractlog.race.RaceLogEvent;
import com.sap.sailing.domain.abstractlog.race.RaceLogEventVisitor;
import com.sap.sailing.domain.abstractlog.race.analyzing.impl.LastPublishedCourseDesignFinder;
import com.sap.sailing.domain.abstractlog.race.impl.RaceLogCourseDesignChangedEventImpl;
import com.sap.sailing.domain.abstractlog.race.tracking.RaceLogDefineMarkEvent;
import com.sap.sailing.domain.abstractlog.race.tracking.RaceLogDenoteForTrackingEvent;
import com.sap.sailing.domain.abstractlog.race.tracking.RaceLogDeviceMarkMappingEvent;
import com.sap.sailing.domain.abstractlog.race.tracking.RaceLogStartTrackingEvent;
import com.sap.sailing.domain.abstractlog.race.tracking.analyzing.impl.RaceLogTrackingStateAnalyzer;
import com.sap.sailing.domain.abstractlog.race.tracking.impl.RaceLogDefineMarkEventImpl;
import com.sap.sailing.domain.abstractlog.race.tracking.impl.RaceLogDenoteForTrackingEventImpl;
import com.sap.sailing.domain.abstractlog.race.tracking.impl.RaceLogDeviceMarkMappingEventImpl;
import com.sap.sailing.domain.abstractlog.race.tracking.impl.RaceLogRegisterCompetitorEventImpl;
import com.sap.sailing.domain.abstractlog.race.tracking.impl.RaceLogStartTrackingEventImpl;
import com.sap.sailing.domain.abstractlog.regatta.RegattaLog;
import com.sap.sailing.domain.abstractlog.regatta.RegattaLogEvent;
import com.sap.sailing.domain.abstractlog.regatta.RegattaLogEventVisitor;
import com.sap.sailing.domain.abstractlog.regatta.events.impl.RegattaLogDeviceMarkMappingEventImpl;
import com.sap.sailing.domain.abstractlog.regatta.events.impl.RegattaLogRegisterCompetitorEventImpl;
import com.sap.sailing.domain.abstractlog.shared.analyzing.RegisteredCompetitorsAnalyzer;
import com.sap.sailing.domain.abstractlog.shared.events.RegisterCompetitorEvent;
import com.sap.sailing.domain.base.BoatClass;
import com.sap.sailing.domain.base.Competitor;
import com.sap.sailing.domain.base.CourseBase;
@@ -63,6 +48,7 @@ import com.sap.sailing.domain.base.Waypoint;
import com.sap.sailing.domain.base.impl.CourseDataImpl;
import com.sap.sailing.domain.common.RegattaIdentifier;
import com.sap.sailing.domain.common.abstractlog.NotRevokableException;
import com.sap.sailing.domain.common.racelog.tracking.CompetitorRegistrationOnRaceLogDisabledException;
import com.sap.sailing.domain.common.racelog.tracking.DeviceMappingConstants;
import com.sap.sailing.domain.common.racelog.tracking.NotDenotableForRaceLogTrackingException;
import com.sap.sailing.domain.common.racelog.tracking.NotDenotedForRaceLogTrackingException;
@@ -70,10 +56,8 @@ import com.sap.sailing.domain.common.racelog.tracking.RaceLogRaceTrackerExistsEx
import com.sap.sailing.domain.common.racelog.tracking.RaceLogTrackingState;
import com.sap.sailing.domain.common.racelog.tracking.TransformationException;
import com.sap.sailing.domain.common.tracking.GPSFix;
import com.sap.sailing.domain.leaderboard.FlexibleLeaderboard;
import com.sap.sailing.domain.leaderboard.Leaderboard;
import com.sap.sailing.domain.leaderboard.RegattaLeaderboard;
import com.sap.sailing.domain.racelogtracking.DeviceIdentifier;
import com.sap.sailing.domain.racelogtracking.PingDeviceIdentifierImpl;
import com.sap.sailing.domain.racelogtracking.RaceLogTrackingAdapter;
import com.sap.sailing.domain.tracking.RaceHandle;
@@ -82,6 +66,7 @@ import com.sap.sailing.server.RacingEventService;
import com.sap.sse.common.NoCorrespondingServiceRegisteredException;
import com.sap.sse.common.TimePoint;
import com.sap.sse.common.Util;
import com.sap.sse.common.Util.Pair;
import com.sap.sse.common.impl.MillisecondsTimePoint;
import com.sap.sse.common.mail.MailException;
import com.sap.sse.mail.MailService;
@@ -150,44 +135,44 @@ public class RaceLogTrackingAdapterImpl implements RaceLogTrackingAdapter {
@Override
public void denoteRaceForRaceLogTracking(RacingEventService service, Leaderboard leaderboard,
RaceColumn raceColumn, Fleet fleet, String raceName) throws NotDenotableForRaceLogTrackingException {
BoatClass boatClass = null;
final BoatClass boatClass;
if (leaderboard instanceof RegattaLeaderboard) {
RegattaLeaderboard rLeaderboard = (RegattaLeaderboard) leaderboard;
boatClass = rLeaderboard.getRegatta().getBoatClass();
} else {
throw new NotDenotableForRaceLogTrackingException(
"Can only denote races in RegattaLeaderboards for RaceLog-tracking");
if (!Util.isEmpty(raceColumn.getAllCompetitors(fleet))) {
boatClass = findDominatingBoatClass(raceColumn.getAllCompetitors(fleet));
} else if (!Util.isEmpty(raceColumn.getAllCompetitors())) {
boatClass = findDominatingBoatClass(raceColumn.getAllCompetitors());
} else if (!Util.isEmpty(leaderboard.getAllCompetitors())) {
boatClass = findDominatingBoatClass(leaderboard.getAllCompetitors());
} else {
throw new NotDenotableForRaceLogTrackingException("Couldn't infer boat class, no competitors on race and leaderboard");
}
}
if (raceName == null) {
raceName = leaderboard.getName() + " " + raceColumn.getName() + " " + fleet.getName();
}
RaceLog raceLog = raceColumn.getRaceLog(fleet);
assert raceLog != null : new NotDenotableForRaceLogTrackingException("No RaceLog found in place");
if (new RaceLogTrackingStateAnalyzer(raceLog).analyze().isForTracking()) {
throw new NotDenotableForRaceLogTrackingException("Already denoted for tracking");
}
RaceLogEvent event = new RaceLogDenoteForTrackingEventImpl(MillisecondsTimePoint.now(),
service.getServerAuthor(), raceLog.getCurrentPassId(), raceName, boatClass, UUID.randomUUID());
raceLog.add(event);
}
private BoatClass findDominatingBoatClass(Iterable<Competitor> allCompetitors) {
return Util.getDominantObject(()->StreamSupport.stream(allCompetitors.spliterator(), /* parallel */ false).map(c->c.getBoat().getBoatClass()).iterator());
}
@Override
public void denoteAllRacesForRaceLogTracking(final RacingEventService service, final Leaderboard leaderboard)
throws NotDenotableForRaceLogTrackingException {
if (leaderboard instanceof FlexibleLeaderboard) {
throw new NotDenotableForRaceLogTrackingException("Can only use regatta leaderboards for RaceLog-tracking");
}
for (RaceColumn column : leaderboard.getRaceColumns()) {
for (Fleet fleet : column.getFleets()) {
try {
denoteRaceForRaceLogTracking(service, leaderboard, column, fleet, null);
} catch (NotDenotableForRaceLogTrackingException e) {
}
denoteRaceForRaceLogTracking(service, leaderboard, column, fleet, null);
}
}
}
@@ -202,18 +187,6 @@ public class RaceLogTrackingAdapterImpl implements RaceLogTrackingAdapter {
return new RaceLogTrackingStateAnalyzer(raceColumn.getRaceLog(fleet)).analyze();
}
private void revokeAlreadyDefinedMarks(RaceLog raceLog, AbstractLogEventAuthor author) {
List<RaceLogEvent> markEvents = new AllEventsOfTypeFinder<>(raceLog, /* only unrevoked */true,
RaceLogDefineMarkEvent.class).analyze();
for (RaceLogEvent event : markEvents) {
try {
raceLog.revokeEvent(author, event, "removing mark that was already defined");
} catch (NotRevokableException e) {
logger.log(Level.WARNING, "Could not remove mark that was already defined by adding RevokeEvent", e);
}
}
}
@Override
public void copyCourse(RaceLog fromRaceLog, Set<RaceLog> toRaceLogs, SharedDomainFactory baseDomainFactory,
RacingEventService service) {
@@ -223,29 +196,16 @@ public class RaceLogTrackingAdapterImpl implements RaceLogTrackingAdapter {
course.getWaypoints().forEach(wp -> Util.addAll(wp.getMarks(), marks));
}
final List<RaceLogEvent> raceLogDeviceMarkMappingEvents = new AllEventsOfTypeFinder<>(fromRaceLog, /*
* only
* unrevoked
*/true,
RaceLogDeviceMarkMappingEvent.class).analyze();
for (RaceLog toRaceLog : toRaceLogs) {
if (new RaceLogTrackingStateAnalyzer(toRaceLog).analyze().isForTracking()) {
if (course != null) {
CourseBase newCourse = new CourseDataImpl("Copy of \"" + course.getName() + "\"");
TimePoint now = MillisecondsTimePoint.now();
int i = 0;
revokeAlreadyDefinedMarks(toRaceLog, service.getServerAuthor());
for (Waypoint oldWaypoint : course.getWaypoints()) {
newCourse.addWaypoint(i++, oldWaypoint);
}
for (Mark mark : marks) {
RaceLogEvent event = new RaceLogDefineMarkEventImpl(now, service.getServerAuthor(),
toRaceLog.getCurrentPassId(), mark);
toRaceLog.add(event);
}
for (RaceLogEvent raceLogDeviceMarkMappingEvent : raceLogDeviceMarkMappingEvents) {
toRaceLog.add(raceLogDeviceMarkMappingEvent);
}
int passId = toRaceLog.getCurrentPassId();
RaceLogEvent newCourseEvent = new RaceLogCourseDesignChangedEventImpl(now,
service.getServerAuthor(), passId, newCourse);
@@ -257,23 +217,31 @@ public class RaceLogTrackingAdapterImpl implements RaceLogTrackingAdapter {
}
@Override
public void copyCompetitors(RaceLog fromRaceLog, Set<RaceLog> toRaceLogs, RacingEventService service) {
final Set<Competitor> competitors = new RegisteredCompetitorsAnalyzer<>(fromRaceLog).analyze();
for (RaceLog toRaceLog : toRaceLogs) {
registerCompetitors(service, toRaceLog, competitors);
public void copyCompetitors(final RaceColumn fromRaceColumn, final Fleet fromFleet, final Iterable<Pair<RaceColumn, Fleet>> toRaces) {
Iterable<Competitor> competitorsToCopy = fromRaceColumn.getAllCompetitors(fromFleet);
for (Pair<RaceColumn, Fleet> toRace : toRaces) {
final RaceColumn toRaceColumn = toRace.getA();
final Fleet toFleet = toRace.getB();
try {
if (toRaceColumn.isCompetitorRegistrationInRacelogEnabled(toFleet)) {
toRaceColumn.registerCompetitors(competitorsToCopy, toFleet);
} else {
toRaceColumn.enableCompetitorRegistrationOnRaceLog(toFleet);
toRaceColumn.registerCompetitors(competitorsToCopy, toFleet);
}
} catch (CompetitorRegistrationOnRaceLogDisabledException e1) {
// cannot happen as we explicitly checked successfully before, or enabled it when the check failed; still produce a log documenting this strangeness:
logger.log(Level.WARNING, "Internal error: race column "+toRaceColumn.getName()+" does not accept competitor registration although it should", e1);
}
}
}
@FunctionalInterface
private static interface DeviceMarkMappingEventFactory<VisitorT, EventT extends AbstractLogEvent<VisitorT>> {
EventT createDeviceMarkMapping(DeviceIdentifier device, TimePoint timePoint);
}
private <VisitorT, EventT extends AbstractLogEvent<VisitorT>, LogT extends AbstractLog<EventT, VisitorT>> void pingMark(
LogT log, Mark mark, GPSFix gpsFix, RacingEventService service,
DeviceMarkMappingEventFactory<VisitorT, EventT> factory, DeviceIdentifier device) {
TimePoint time = gpsFix.getTimePoint();
EventT mapping = factory.createDeviceMarkMapping(device, time);
@Override
public void pingMark(RegattaLog log, Mark mark, GPSFix gpsFix, RacingEventService service) {
final PingDeviceIdentifierImpl device = new PingDeviceIdentifierImpl();
final TimePoint timePoint = gpsFix.getTimePoint();
final RegattaLogEvent mapping = new RegattaLogDeviceMarkMappingEventImpl(timePoint,
timePoint, service.getServerAuthor(), UUID.randomUUID(), mark, device, timePoint, timePoint);
log.add(mapping);
try {
service.getGPSFixStore().storeFix(device, gpsFix);
@@ -282,30 +250,6 @@ public class RaceLogTrackingAdapterImpl implements RaceLogTrackingAdapter {
}
}
@Override
public void pingMark(RaceLog raceLog, Mark mark, GPSFix gpsFix, RacingEventService service) {
DeviceMarkMappingEventFactory<RaceLogEventVisitor, RaceLogEvent> raceLogEventFactory =
(DeviceIdentifier dev, TimePoint timePoint) -> new RaceLogDeviceMarkMappingEventImpl(timePoint, service
.getServerAuthor(), raceLog.getCurrentPassId(), mark, dev, timePoint, timePoint);
pingMark(
raceLog,
mark,
gpsFix,
service,
raceLogEventFactory,
new PingDeviceIdentifierImpl());
}
@Override
public void pingMark(RegattaLog regattaLog, Mark mark, GPSFix gpsFix, RacingEventService service) {
DeviceMarkMappingEventFactory<RegattaLogEventVisitor, RegattaLogEvent> regattaLogEventFactory =
(DeviceIdentifier dev, TimePoint timePoint) -> new RegattaLogDeviceMarkMappingEventImpl(timePoint,
timePoint, service.getServerAuthor(), UUID.randomUUID(), mark, dev, timePoint, timePoint);
pingMark(regattaLog, mark, gpsFix, service,
regattaLogEventFactory,
new PingDeviceIdentifierImpl());
}
@Override
public void removeDenotationForRaceLogTracking(RacingEventService service, RaceLog raceLog) {
RaceLogEvent denoteForTrackingEvent = new LastEventOfTypeFinder<>(raceLog, true,
@@ -321,55 +265,6 @@ public class RaceLogTrackingAdapterImpl implements RaceLogTrackingAdapter {
}
}
private <LogT extends AbstractLog<EventT, VisitorT>, EventT extends AbstractLogEvent<VisitorT>, VisitorT> void registerCompetitors(
AbstractLogEventAuthor author, LogT log, Set<Competitor> competitors,
Function<Competitor, EventT> registerEventFactory) {
Set<Competitor> alreadyRegistered = new HashSet<Competitor>(new RegisteredCompetitorsAnalyzer<>(log).analyze());
Set<Competitor> toBeRegistered = new HashSet<Competitor>();
for (Competitor c : competitors) {
toBeRegistered.add(c);
}
Set<Competitor> toBeRemoved = new HashSet<Competitor>(alreadyRegistered);
toBeRemoved.removeAll(toBeRegistered);
toBeRegistered.removeAll(alreadyRegistered);
// register
for (Competitor c : toBeRegistered) {
log.add(registerEventFactory.apply(c));
}
// unregister
for (EventT event : log.getUnrevokedEventsDescending()) {
if (event instanceof RegisterCompetitorEvent) {
RegisterCompetitorEvent<?> registerEvent = (RegisterCompetitorEvent<?>) event;
if (toBeRemoved.contains(registerEvent.getCompetitor())) {
try {
log.revokeEvent(author, event,
"unregistering competitor because no longer selected for registration");
} catch (NotRevokableException e) {
logger.log(Level.WARNING, "could not unregister competitor by adding RevokeEvent", e);
}
}
}
}
}
@Override
public void registerCompetitors(RacingEventService service, RaceLog raceLog, Set<Competitor> competitors) {
registerCompetitors(service.getServerAuthor(), raceLog, competitors,
c -> new RaceLogRegisterCompetitorEventImpl(MillisecondsTimePoint.now(), service.getServerAuthor(),
raceLog.getCurrentPassId(), c));
}
@Override
public void registerCompetitors(RacingEventService service, RegattaLog regattaLog, Set<Competitor> competitors) {
registerCompetitors(service.getServerAuthor(), regattaLog, competitors,
c -> new RegattaLogRegisterCompetitorEventImpl(MillisecondsTimePoint.now(),
MillisecondsTimePoint.now(), service.getServerAuthor(), UUID.randomUUID(), c));
}
private MailService getMailService() {
ServiceReference<MailService> ref = Activator.getContext().getServiceReference(MailService.class);
if (ref == null) {
@@ -1,115 +0,0 @@
package com.sap.sailing.domain.racelog.analyzing.test;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.hasItem;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.UUID;
import org.junit.Before;
import org.junit.Test;
import com.sap.sailing.domain.abstractlog.AbstractLogEventAuthor;
import com.sap.sailing.domain.abstractlog.MultiLogAnalyzer;
import com.sap.sailing.domain.abstractlog.impl.LogEventAuthorImpl;
import com.sap.sailing.domain.abstractlog.race.RaceLog;
import com.sap.sailing.domain.abstractlog.race.impl.RaceLogImpl;
import com.sap.sailing.domain.abstractlog.race.tracking.impl.RaceLogDeviceCompetitorMappingEventImpl;
import com.sap.sailing.domain.abstractlog.race.tracking.impl.RaceLogRegisterCompetitorEventImpl;
import com.sap.sailing.domain.abstractlog.regatta.RegattaLog;
import com.sap.sailing.domain.abstractlog.regatta.events.impl.RegattaLogDeviceCompetitorMappingEventImpl;
import com.sap.sailing.domain.abstractlog.regatta.events.impl.RegattaLogRegisterCompetitorEventImpl;
import com.sap.sailing.domain.abstractlog.regatta.impl.RegattaLogImpl;
import com.sap.sailing.domain.abstractlog.shared.analyzing.DeviceMappingFinder;
import com.sap.sailing.domain.abstractlog.shared.analyzing.RegisteredCompetitorsAnalyzer;
import com.sap.sailing.domain.base.Competitor;
import com.sap.sailing.domain.base.impl.CompetitorImpl;
import com.sap.sailing.domain.racelogtracking.DeviceIdentifier;
import com.sap.sailing.domain.racelogtracking.DeviceMapping;
import com.sap.sailing.domain.racelogtracking.impl.SmartphoneUUIDIdentifierImpl;
import com.sap.sse.common.TimePoint;
import com.sap.sse.common.WithID;
import com.sap.sse.common.impl.MillisecondsTimePoint;
public class MultiLogAnalyzerTest {
private static TimePoint now() {
return MillisecondsTimePoint.now();
}
private static TimePoint t(long millis) {
return new MillisecondsTimePoint(millis);
}
private static UUID uuid() {
return UUID.randomUUID();
}
private RaceLog raceLog;
private RegattaLog regattaLog;
private AbstractLogEventAuthor author;
private static Competitor createCompetitor(int n) {
return new CompetitorImpl(n, n + "", null, null, null, null, null, /* timeOnTimeFactor */ null, /* timeOnDistanceAllowancePerNauticalMile */ null);
}
private static DeviceIdentifier createDevice() {
return new SmartphoneUUIDIdentifierImpl(UUID.randomUUID());
}
@Before
public void setup() {
raceLog = new RaceLogImpl(0);
regattaLog = new RegattaLogImpl(0);
author = new LogEventAuthorImpl("test", 0);
}
@Test
public void registerCompetitorsInRaceAndRegattaLog() {
Competitor c1 = createCompetitor(1);
Competitor c2 = createCompetitor(2);
Competitor c3 = createCompetitor(3);
raceLog.add(new RaceLogRegisterCompetitorEventImpl(now(), now(), author, uuid(), 0, c1));
regattaLog.add(new RegattaLogRegisterCompetitorEventImpl(now(), now(), author, uuid(), c2));
raceLog.add(new RaceLogRegisterCompetitorEventImpl(now(), now(), author, uuid(), 0, c3));
regattaLog.add(new RegattaLogRegisterCompetitorEventImpl(now(), now(), author, uuid(), c3));
Set<Competitor> result = new MultiLogAnalyzer<>(
RegisteredCompetitorsAnalyzer.Factory.INSTANCE, new MultiLogAnalyzer.SetReducer<Competitor>(), raceLog,
regattaLog).analyze();
assertThat("competitor 1 added", result, hasItem(c1));
assertThat("competitor 2 added", result, hasItem(c2));
assertThat("competitor 3 added", result, hasItem(c3));
assertThat("only three items in total", result.size(), equalTo(3));
}
@Test
public void deviceMappingsInRaceAndRegattaLog() {
Competitor c1 = createCompetitor(1);
Competitor c2 = createCompetitor(2);
DeviceIdentifier d1 = createDevice();
DeviceIdentifier d2 = createDevice();
raceLog.add(new RaceLogDeviceCompetitorMappingEventImpl(now(), now(), author, 0, 0, c1, d1, t(0), t(10)));
raceLog.add(new RaceLogDeviceCompetitorMappingEventImpl(now(), now(), author, 1, 0, c1, d2, t(30), t(40)));
regattaLog.add(new RegattaLogDeviceCompetitorMappingEventImpl(now(), now(), author, 2, c2, d2, t(10), t(20)));
// and one for same item (competitor) in other log
regattaLog.add(new RegattaLogDeviceCompetitorMappingEventImpl(now(), now(), author, 3, c1, d1, t(10),
t(20)));
Map<WithID, List<DeviceMapping<WithID>>> result = new MultiLogAnalyzer<>(
new DeviceMappingFinder.Factory<>(), new MultiLogAnalyzer.MapWithValueCollectionReducer<>(), raceLog,
regattaLog).analyze();
assertThat("mappings for two competitors", result.size(), equalTo(2));
assertThat("three mappings for competitor 1 ", result.get(c1).size(), equalTo(3));
assertThat("one mapping for competitor 2", result.get(c2).size(), equalTo(1));
}
}
@@ -16,10 +16,6 @@ import com.sap.sailing.domain.abstractlog.race.RaceLog;
import com.sap.sailing.domain.abstractlog.race.RaceLogStartTimeEvent;
import com.sap.sailing.domain.abstractlog.race.impl.RaceLogImpl;
import com.sap.sailing.domain.abstractlog.race.impl.RaceLogStartTimeEventImpl;
import com.sap.sailing.domain.abstractlog.race.tracking.RaceLogDeviceCompetitorMappingEvent;
import com.sap.sailing.domain.abstractlog.race.tracking.impl.RaceLogDeviceCompetitorMappingEventImpl;
import com.sap.sailing.domain.racelog.tracking.test.mock.SmartphoneImeiIdentifier;
import com.sap.sailing.domain.test.AbstractLeaderboardTest;
import com.sap.sse.common.Util;
import com.sap.sse.common.impl.MillisecondsTimePoint;
@@ -76,29 +72,6 @@ public class SerializeRaceLogEventsTest {
}
}
@Test
public void testRaceLogSerializationWithEventContainingDeviceIdentifier() throws IOException, ClassNotFoundException {
RaceLogDeviceCompetitorMappingEvent mappingEvent = new RaceLogDeviceCompetitorMappingEventImpl(
MillisecondsTimePoint.now(), new LogEventAuthorImpl("Author Name", /* priority */0), 0,
AbstractLeaderboardTest.createCompetitor("Test Competitor"), new SmartphoneImeiIdentifier("1948364938463903"), new MillisecondsTimePoint(0), new MillisecondsTimePoint(10));
raceLog.add(mappingEvent);
oos.writeObject(raceLog);
ObjectInputStream ois = getObjectInputStream();
RaceLog rl = (RaceLog) ois.readObject();
raceLog.lockForRead();
rl.lockForRead();
try {
RaceLogDeviceCompetitorMappingEvent expected = ((RaceLogDeviceCompetitorMappingEvent) raceLog.getFirstRawFix());
RaceLogDeviceCompetitorMappingEvent actual = ((RaceLogDeviceCompetitorMappingEvent) rl.getFirstRawFix());
assertEquals(Util.size(raceLog.getRawFixes()), Util.size(rl.getRawFixes()));
assertEquals(expected.getDevice().getIdentifierType(), actual.getDevice().getIdentifierType());
} finally {
rl.unlockAfterRead();
raceLog.unlockAfterRead();
}
}
private ObjectInputStream getObjectInputStream() throws IOException {
return new ObjectInputStream(new ByteArrayInputStream(bos.toByteArray()));
}
@@ -1,61 +0,0 @@
package com.sap.sailing.domain.racelog.tracking.analyzing.test;
import java.util.UUID;
import junit.framework.Assert;
import org.junit.Test;
import com.sap.sailing.domain.abstractlog.race.RaceLogEvent;
import com.sap.sailing.domain.abstractlog.race.RaceLogRevokeEvent;
import com.sap.sailing.domain.abstractlog.race.impl.RaceLogRevokeEventImpl;
import com.sap.sailing.domain.abstractlog.race.tracking.impl.RaceLogDeviceCompetitorMappingEventImpl;
import com.sap.sse.common.Util;
public class RevokeEventTest extends AbstractRaceLogTrackingTest {
@Test
public void revokedEventIsExcluded() {
RaceLogEvent event = new RaceLogDeviceCompetitorMappingEventImpl(now, now, author, UUID.randomUUID(), 0, null, null, null, null);
RaceLogRevokeEvent revokeEvent = new RaceLogRevokeEventImpl(now.plus(1), now.plus(1), author, UUID.randomUUID(), 0, event.getId(),
null, null, null);
log.add(event);
log.add(revokeEvent);
log.lockForRead();
Assert.assertFalse(Util.contains(log.getUnrevokedEvents(), event));
log.unlockAfterRead();
}
@Test
public void eventRevokedByAuthorWithLowerPrioIsNotExcluded() {
RaceLogEvent event = new RaceLogDeviceCompetitorMappingEventImpl(now, now, author, UUID.randomUUID(), 0, null, null, null, null);
RaceLogRevokeEvent revokeEvent = new RaceLogRevokeEventImpl(now.plus(1), now.plus(1), author1, UUID.randomUUID(), 0, event.getId(),
null, null, null);
log.add(event);
log.add(revokeEvent);
log.lockForRead();
Assert.assertTrue(Util.contains(log.getUnrevokedEvents(), event));
log.unlockAfterRead();
}
@Test
public void revokingRevokeEventIsNotHarmful() {
RaceLogEvent event = new RaceLogDeviceCompetitorMappingEventImpl(now, now, author, UUID.randomUUID(), 0, null, null, null, null);
RaceLogRevokeEvent revokeEvent = new RaceLogRevokeEventImpl(now.plus(1), now.plus(1), author, UUID.randomUUID(), 0, event.getId(),
null, null, null);
RaceLogRevokeEvent revokeEvent2 = new RaceLogRevokeEventImpl(now.plus(2), now.plus(2), author, UUID.randomUUID(), 2, revokeEvent.getId(),
null, null, null);
log.add(event);
log.add(revokeEvent);
log.lockForRead();
Assert.assertFalse(Util.contains(log.getUnrevokedEvents(), event));
Assert.assertFalse(Util.contains(log.getUnrevokedEvents(), revokeEvent));
Assert.assertFalse(Util.contains(log.getUnrevokedEvents(), revokeEvent2));
log.unlockAfterRead();
}
}
@@ -0,0 +1,29 @@
package com.sap.sailing.domain.regattalog.tracking.analyzing.test;
import org.junit.Before;
import com.sap.sailing.domain.abstractlog.AbstractLogEventAuthor;
import com.sap.sailing.domain.abstractlog.impl.LogEventAuthorImpl;
import com.sap.sailing.domain.abstractlog.regatta.RegattaLog;
import com.sap.sailing.domain.abstractlog.regatta.impl.RegattaLogImpl;
import com.sap.sse.common.TimePoint;
import com.sap.sse.common.impl.MillisecondsTimePoint;
public abstract class AbstractRegattaLogTrackingTest {
protected RegattaLog log;
protected final AbstractLogEventAuthor author = new LogEventAuthorImpl("author0", 0);
protected final AbstractLogEventAuthor author1 = new LogEventAuthorImpl("author1", 1);
protected final TimePoint now = MillisecondsTimePoint.now();
public AbstractRegattaLogTrackingTest() {
super();
}
@Before
public void setup() {
log = new RegattaLogImpl("log");
}
}
@@ -1,4 +1,4 @@
package com.sap.sailing.domain.racelog.tracking.analyzing.test;
package com.sap.sailing.domain.regattalog.tracking.analyzing.test;
import static org.junit.Assert.assertEquals;
@@ -11,10 +11,10 @@ import junit.framework.Assert;
import org.junit.Test;
import com.sap.sailing.domain.abstractlog.AbstractLogEventAuthor;
import com.sap.sailing.domain.abstractlog.race.RaceLogEvent;
import com.sap.sailing.domain.abstractlog.race.tracking.impl.RaceLogCloseOpenEndedDeviceMappingEventImpl;
import com.sap.sailing.domain.abstractlog.race.tracking.impl.RaceLogDeviceCompetitorMappingEventImpl;
import com.sap.sailing.domain.abstractlog.shared.analyzing.DeviceCompetitorMappingFinder;
import com.sap.sailing.domain.abstractlog.regatta.RegattaLogEvent;
import com.sap.sailing.domain.abstractlog.regatta.events.impl.RegattaLogCloseOpenEndedDeviceMappingEventImpl;
import com.sap.sailing.domain.abstractlog.regatta.events.impl.RegattaLogDeviceCompetitorMappingEventImpl;
import com.sap.sailing.domain.abstractlog.regatta.tracking.analyzing.impl.RegattaLogDeviceCompetitorMappingFinder;
import com.sap.sailing.domain.base.Competitor;
import com.sap.sailing.domain.base.impl.CompetitorImpl;
import com.sap.sailing.domain.racelog.tracking.test.mock.SmartphoneImeiIdentifier;
@@ -23,7 +23,7 @@ import com.sap.sailing.domain.racelogtracking.DeviceMapping;
import com.sap.sse.common.TimePoint;
import com.sap.sse.common.impl.MillisecondsTimePoint;
public class DeviceMappingFinderTest extends AbstractRaceLogTrackingTest {
public class DeviceMappingFinderTest extends AbstractRegattaLogTrackingTest {
private final Competitor competitor = new CompetitorImpl("comp", "Comp", null, null, null, null, null, /* timeOnTimeFactor */ null, /* timeOnDistanceAllowancePerNauticalMile */ null);
private final Competitor competitor2 = new CompetitorImpl("comp2", "Comp2", null, null, null, null, null, /* timeOnTimeFactor */ null, /* timeOnDistanceAllowancePerNauticalMile */ null);
private final DeviceIdentifier device = new SmartphoneImeiIdentifier("imei");
@@ -31,7 +31,7 @@ public class DeviceMappingFinderTest extends AbstractRaceLogTrackingTest {
private int time = 0;
private List<DeviceMapping<Competitor>> getMappings() {
return new DeviceCompetitorMappingFinder<>(log).analyze().get(competitor);
return new RegattaLogDeviceCompetitorMappingFinder(log).analyze().get(competitor);
}
private TimePoint t() {
@@ -43,14 +43,14 @@ public class DeviceMappingFinderTest extends AbstractRaceLogTrackingTest {
}
private Serializable addMapping(AbstractLogEventAuthor author, DeviceIdentifier device, Long from, Long to, Competitor item) {
RaceLogEvent mapping = new RaceLogDeviceCompetitorMappingEventImpl(t(), t(), author, UUID.randomUUID(), 0, item, device,
RegattaLogEvent mapping = new RegattaLogDeviceCompetitorMappingEventImpl(t(), t(), author, UUID.randomUUID(), item, device,
t(from), t(to));
log.add(mapping);
return mapping.getId();
}
private void closeMapping(AbstractLogEventAuthor author, DeviceIdentifier device, Serializable mappingId, long millis) {
RaceLogEvent mapping = new RaceLogCloseOpenEndedDeviceMappingEventImpl(t(), t(), author, UUID.randomUUID(), 0, mappingId,
RegattaLogEvent mapping = new RegattaLogCloseOpenEndedDeviceMappingEventImpl(t(), author, t(), UUID.randomUUID(), mappingId,
new MillisecondsTimePoint(millis));
log.add(mapping);
}
@@ -0,0 +1,61 @@
package com.sap.sailing.domain.regattalog.tracking.analyzing.test;
import java.util.UUID;
import junit.framework.Assert;
import org.junit.Test;
import com.sap.sailing.domain.abstractlog.regatta.RegattaLogEvent;
import com.sap.sailing.domain.abstractlog.regatta.events.RegattaLogRevokeEvent;
import com.sap.sailing.domain.abstractlog.regatta.events.impl.RegattaLogDeviceCompetitorMappingEventImpl;
import com.sap.sailing.domain.abstractlog.regatta.events.impl.RegattaLogRevokeEventImpl;
import com.sap.sse.common.Util;
public class RevokeEventTest extends AbstractRegattaLogTrackingTest {
@Test
public void revokedEventIsExcluded() {
RegattaLogEvent event = new RegattaLogDeviceCompetitorMappingEventImpl(now, now, author, UUID.randomUUID(), null, null, null, null);
RegattaLogRevokeEvent revokeEvent = new RegattaLogRevokeEventImpl(now.plus(1), now.plus(1), author, UUID.randomUUID(), event.getId(),
null, null, null);
log.add(event);
log.add(revokeEvent);
log.lockForRead();
Assert.assertFalse(Util.contains(log.getUnrevokedEvents(), event));
log.unlockAfterRead();
}
@Test
public void eventRevokedByAuthorWithLowerPrioIsNotExcluded() {
RegattaLogEvent event = new RegattaLogDeviceCompetitorMappingEventImpl(now, now, author, UUID.randomUUID(), null, null, null, null);
RegattaLogRevokeEvent revokeEvent = new RegattaLogRevokeEventImpl(now.plus(1), now.plus(1), author1, UUID.randomUUID(), event.getId(),
null, null, null);
log.add(event);
log.add(revokeEvent);
log.lockForRead();
Assert.assertTrue(Util.contains(log.getUnrevokedEvents(), event));
log.unlockAfterRead();
}
@Test
public void revokingRevokeEventIsNotHarmful() {
RegattaLogEvent event = new RegattaLogDeviceCompetitorMappingEventImpl(now, now, author, UUID.randomUUID(), null, null, null, null);
RegattaLogRevokeEvent revokeEvent = new RegattaLogRevokeEventImpl(now.plus(1), now.plus(1), author, UUID.randomUUID(), event.getId(),
null, null, null);
RegattaLogRevokeEvent revokeEvent2 = new RegattaLogRevokeEventImpl(now.plus(2), now.plus(2), author, UUID.randomUUID(), revokeEvent.getId(),
null, null, null);
log.add(event);
log.add(revokeEvent);
log.lockForRead();
Assert.assertFalse(Util.contains(log.getUnrevokedEvents(), event));
Assert.assertFalse(Util.contains(log.getUnrevokedEvents(), revokeEvent));
Assert.assertFalse(Util.contains(log.getUnrevokedEvents(), revokeEvent2));
log.unlockAfterRead();
}
}
@@ -9,8 +9,8 @@ import com.sap.sailing.domain.abstractlog.BaseLogAnalyzer;
/**
* Finds all events in the log which is an {@code instanceof} {@link #ofType}.
*
* @author Fredrik Teschke
*
*/
public class AllEventsOfTypeFinder<LogT extends AbstractLog<EventT, VisitorT>, EventT extends AbstractLogEvent<VisitorT>,
VisitorT> extends BaseLogAnalyzer<LogT, EventT, VisitorT, List<EventT>> {
@@ -0,0 +1,30 @@
package com.sap.sailing.domain.abstractlog.race;
import java.io.Serializable;
import com.sap.sailing.domain.common.MaxPointsReason;
import com.sap.sse.common.TimePoint;
/**
* holds the competitor ID, the competitor name, the finishing rank, an optional score, the optional {@link MaxPointReason} and
* an optional finishing time, important for handicapped races. An optional comment for the competitor's result can also be
* provided as a simple {@link String}, such as a reason for a disqualification or a redress given.
*
* @author Axel Uhl (D043530)
*
*/
public interface CompetitorResult extends Serializable {
Serializable getCompetitorId();
String getCompetitorDisplayName();
int getOneBasedRank();
MaxPointsReason getMaxPointsReason();
Double getScore();
TimePoint getFinishingTime();
String getComment();
}
@@ -1,15 +1,10 @@
package com.sap.sailing.domain.abstractlog.race;
import java.io.Serializable;
import java.util.List;
import com.sap.sailing.domain.common.MaxPointsReason;
import com.sap.sse.common.Util;
/**
* A triple holding the competitor ID, the competitor name and the {@link MaxPointReason} documenting the score for the
* competitor
* A set of competitor results; order does not tell anything about the finishing order which can be seen from
* the {@link CompetitorResult#getRank}.
*/
public interface CompetitorResults extends List<Util.Triple<Serializable, String, MaxPointsReason>> {
public interface CompetitorResults extends Iterable<CompetitorResult> {
boolean add(CompetitorResult result);
}
@@ -1,13 +1,10 @@
package com.sap.sailing.domain.abstractlog.race;
import com.sap.sailing.domain.abstractlog.race.scoring.RaceLogAdditionalScoringInformationEvent;
import com.sap.sailing.domain.abstractlog.race.tracking.RaceLogCloseOpenEndedDeviceMappingEvent;
import com.sap.sailing.domain.abstractlog.race.tracking.RaceLogDefineMarkEvent;
import com.sap.sailing.domain.abstractlog.race.tracking.RaceLogDenoteForTrackingEvent;
import com.sap.sailing.domain.abstractlog.race.tracking.RaceLogDeviceCompetitorMappingEvent;
import com.sap.sailing.domain.abstractlog.race.tracking.RaceLogDeviceMarkMappingEvent;
import com.sap.sailing.domain.abstractlog.race.tracking.RaceLogRegisterCompetitorEvent;
import com.sap.sailing.domain.abstractlog.race.tracking.RaceLogStartTrackingEvent;
import com.sap.sailing.domain.abstractlog.race.tracking.RaceLogUseCompetitorsFromRaceLogEvent;
public interface RaceLogEventVisitor {
@@ -39,19 +36,11 @@ public interface RaceLogEventVisitor {
public void visit(RaceLogWindFixEvent event);
public void visit(RaceLogDeviceCompetitorMappingEvent event);
public void visit(RaceLogDeviceMarkMappingEvent event);
public void visit(RaceLogDenoteForTrackingEvent event);
public void visit(RaceLogStartTrackingEvent event);
public void visit(RaceLogRegisterCompetitorEvent event);
public void visit(RaceLogDefineMarkEvent event);
public void visit(RaceLogCloseOpenEndedDeviceMappingEvent event);
public void visit(RaceLogAdditionalScoringInformationEvent additionalScoringInformation);
@@ -64,4 +53,6 @@ public interface RaceLogEventVisitor {
public void visit(RaceLogStartOfTrackingEvent event);
public void visit(RaceLogEndOfTrackingEvent event);
public void visit(RaceLogUseCompetitorsFromRaceLogEvent event);
}
@@ -2,10 +2,10 @@ package com.sap.sailing.domain.abstractlog.race;
/**
* This RaceLog evet type confirms the entered positioning list. Since we do not guarantee the order of incoming events from the app (due to possible
* connectivity issues), this event type contains the the confirmed positioning list again. Although this racelog event type contains the same information
* such as {@link RaceLogFinishPositioningListChangedEvent} we keep it for backwards compatibility reasons.
*
* This RaceLog event type confirms the entered positioning list. Since we do not guarantee the order of incoming events
* from the app (due to possible connectivity issues), this event type contains the the confirmed positioning list
* again. Although this racelog event type contains the same information such as
* {@link RaceLogFinishPositioningListChangedEvent} we keep it for backwards compatibility reasons.
*/
public interface RaceLogFinishPositioningConfirmedEvent extends RaceLogFinishPositioningEvent {
@@ -1,6 +1,11 @@
package com.sap.sailing.domain.abstractlog.race;
/**
* Captures a temporary race result description. The result is not final yet and needs to be confirmed by
* a {@link RaceLogFinishPositioningConfirmedEvent} before it is adopted by other parts of the model. This
* type of event can be used to store the interims state of a result editing process before the result
* if committed.
*/
public interface RaceLogFinishPositioningListChangedEvent extends RaceLogFinishPositioningEvent {
}
@@ -19,7 +19,6 @@ public class ConfirmedFinishPositioningListFinder extends RaceLogAnalyzer<Compet
return finishPositioningEvent.getPositionedCompetitorsIDsNamesMaxPointsReasons();
}
}
return null;
}
}
@@ -19,8 +19,6 @@ public class LastPublishedCourseDesignFinder extends RaceLogAnalyzer<CourseBase>
return courseDesignEvent.getCourseDesign();
}
}
return null;
}
}
@@ -0,0 +1,30 @@
package com.sap.sailing.domain.abstractlog.race.analyzing.impl;
import java.util.Collections;
import java.util.Set;
import com.sap.sailing.domain.abstractlog.race.RaceLog;
import com.sap.sailing.domain.abstractlog.race.tracking.analyzing.impl.RaceLogUsesOwnCompetitorsAnalyzer;
import com.sap.sailing.domain.abstractlog.shared.analyzing.CompetitorsInLogAnalyzer;
import com.sap.sailing.domain.base.Competitor;
public class RaceLogRegisteredCompetitorsAnalyzer extends RaceLogAnalyzer<Set<Competitor>> {
public RaceLogRegisteredCompetitorsAnalyzer(RaceLog raceLog) {
super(raceLog);
}
@Override
protected Set<Competitor> performAnalysis() {
final Set<Competitor> result;
if (new RaceLogUsesOwnCompetitorsAnalyzer(getLog()).analyze()){
// get Events from RaceLog
result = new CompetitorsInLogAnalyzer<>(getLog()).analyze();
} else {
// as we're explicitly only trying to find those registrations in the RaceLog, we won't
// return anything from the regatta log.
result = Collections.emptySet();
}
return result;
}
}
@@ -22,13 +22,10 @@ import com.sap.sailing.domain.abstractlog.race.RaceLogStartTimeEvent;
import com.sap.sailing.domain.abstractlog.race.RaceLogSuppressedMarkPassingsEvent;
import com.sap.sailing.domain.abstractlog.race.RaceLogWindFixEvent;
import com.sap.sailing.domain.abstractlog.race.scoring.RaceLogAdditionalScoringInformationEvent;
import com.sap.sailing.domain.abstractlog.race.tracking.RaceLogCloseOpenEndedDeviceMappingEvent;
import com.sap.sailing.domain.abstractlog.race.tracking.RaceLogDefineMarkEvent;
import com.sap.sailing.domain.abstractlog.race.tracking.RaceLogDenoteForTrackingEvent;
import com.sap.sailing.domain.abstractlog.race.tracking.RaceLogDeviceCompetitorMappingEvent;
import com.sap.sailing.domain.abstractlog.race.tracking.RaceLogDeviceMarkMappingEvent;
import com.sap.sailing.domain.abstractlog.race.tracking.RaceLogRegisterCompetitorEvent;
import com.sap.sailing.domain.abstractlog.race.tracking.RaceLogStartTrackingEvent;
import com.sap.sailing.domain.abstractlog.race.tracking.RaceLogUseCompetitorsFromRaceLogEvent;
public abstract class AbstractRaceLogChangedVisitor implements RaceLogEventVisitor {
protected abstract void notifyListenerAboutEventAdded(RaceLogEvent event);
@@ -92,16 +89,6 @@ public abstract class AbstractRaceLogChangedVisitor implements RaceLogEventVisit
notifyListenerAboutEventAdded(event);
}
@Override
public void visit(RaceLogDeviceCompetitorMappingEvent event) {
notifyListenerAboutEventAdded(event);
}
@Override
public void visit(RaceLogDeviceMarkMappingEvent event) {
notifyListenerAboutEventAdded(event);
}
@Override
public void visit(RaceLogDenoteForTrackingEvent event) {
notifyListenerAboutEventAdded(event);
@@ -121,16 +108,6 @@ public abstract class AbstractRaceLogChangedVisitor implements RaceLogEventVisit
public void visit(RaceLogRegisterCompetitorEvent event) {
notifyListenerAboutEventAdded(event);
}
@Override
public void visit(RaceLogDefineMarkEvent event) {
notifyListenerAboutEventAdded(event);
}
@Override
public void visit(RaceLogCloseOpenEndedDeviceMappingEvent event) {
notifyListenerAboutEventAdded(event);
}
@Override
public void visit(RaceLogAdditionalScoringInformationEvent additionalScoringInformation) {
@@ -161,4 +138,9 @@ public abstract class AbstractRaceLogChangedVisitor implements RaceLogEventVisit
public void visit(RaceLogEndOfTrackingEvent event) {
notifyListenerAboutEventAdded(event);
}
@Override
public void visit(RaceLogUseCompetitorsFromRaceLogEvent event) {
notifyListenerAboutEventAdded(event);
}
}
@@ -21,13 +21,10 @@ import com.sap.sailing.domain.abstractlog.race.RaceLogStartTimeEvent;
import com.sap.sailing.domain.abstractlog.race.RaceLogSuppressedMarkPassingsEvent;
import com.sap.sailing.domain.abstractlog.race.RaceLogWindFixEvent;
import com.sap.sailing.domain.abstractlog.race.scoring.RaceLogAdditionalScoringInformationEvent;
import com.sap.sailing.domain.abstractlog.race.tracking.RaceLogCloseOpenEndedDeviceMappingEvent;
import com.sap.sailing.domain.abstractlog.race.tracking.RaceLogDefineMarkEvent;
import com.sap.sailing.domain.abstractlog.race.tracking.RaceLogDenoteForTrackingEvent;
import com.sap.sailing.domain.abstractlog.race.tracking.RaceLogDeviceCompetitorMappingEvent;
import com.sap.sailing.domain.abstractlog.race.tracking.RaceLogDeviceMarkMappingEvent;
import com.sap.sailing.domain.abstractlog.race.tracking.RaceLogRegisterCompetitorEvent;
import com.sap.sailing.domain.abstractlog.race.tracking.RaceLogStartTrackingEvent;
import com.sap.sailing.domain.abstractlog.race.tracking.RaceLogUseCompetitorsFromRaceLogEvent;
/**
* Base class implementing {@link RaceLogEventVisitor}. Every method is implemented as a no-op.
@@ -99,16 +96,6 @@ public abstract class BaseRaceLogEventVisitor implements RaceLogEventVisitor {
}
@Override
public void visit(RaceLogDeviceCompetitorMappingEvent event) {
}
@Override
public void visit(RaceLogDeviceMarkMappingEvent event) {
}
@Override
public void visit(RaceLogDenoteForTrackingEvent event) {
@@ -129,16 +116,6 @@ public abstract class BaseRaceLogEventVisitor implements RaceLogEventVisitor {
}
@Override
public void visit(RaceLogDefineMarkEvent event) {
}
@Override
public void visit(RaceLogCloseOpenEndedDeviceMappingEvent event) {
}
@Override
public void visit(RaceLogAdditionalScoringInformationEvent event) {
@@ -168,4 +145,9 @@ public abstract class BaseRaceLogEventVisitor implements RaceLogEventVisitor {
public void visit(RaceLogStartOfTrackingEvent event) {
}
@Override
public void visit(RaceLogUseCompetitorsFromRaceLogEvent event) {
}
}
@@ -0,0 +1,135 @@
package com.sap.sailing.domain.abstractlog.race.impl;
import java.io.Serializable;
import com.sap.sailing.domain.abstractlog.race.CompetitorResult;
import com.sap.sailing.domain.common.MaxPointsReason;
import com.sap.sse.common.TimePoint;
public class CompetitorResultImpl implements CompetitorResult {
private static final long serialVersionUID = 4928351242700897387L;
private final Serializable competitorId;
private final String competitorDisplayName;
private final int oneBasedRank;
private final MaxPointsReason maxPointsReason;
private final Double score;
private final TimePoint finishingTime;
private final String comment;
public CompetitorResultImpl(Serializable competitorId, String competitorDisplayName, int oneBasedRank,
MaxPointsReason maxPointsReason, Double score, TimePoint finishingTime, String comment) {
super();
this.competitorId = competitorId;
this.competitorDisplayName = competitorDisplayName;
this.oneBasedRank = oneBasedRank;
this.maxPointsReason = maxPointsReason;
this.score = score;
this.finishingTime = finishingTime;
this.comment = comment;
}
@Override
public Serializable getCompetitorId() {
return competitorId;
}
@Override
public String getCompetitorDisplayName() {
return competitorDisplayName;
}
@Override
public int getOneBasedRank() {
return oneBasedRank;
}
@Override
public MaxPointsReason getMaxPointsReason() {
return maxPointsReason;
}
@Override
public Double getScore() {
return score;
}
@Override
public TimePoint getFinishingTime() {
return finishingTime;
}
@Override
public String getComment() {
return comment;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((comment == null) ? 0 : comment.hashCode());
result = prime * result + ((competitorDisplayName == null) ? 0 : competitorDisplayName.hashCode());
result = prime * result + ((competitorId == null) ? 0 : competitorId.hashCode());
result = prime * result + ((finishingTime == null) ? 0 : finishingTime.hashCode());
result = prime * result + ((maxPointsReason == null) ? 0 : maxPointsReason.hashCode());
result = prime * result + oneBasedRank;
result = prime * result + ((score == null) ? 0 : score.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
CompetitorResultImpl other = (CompetitorResultImpl) obj;
if (comment == null) {
if (other.comment != null)
return false;
} else if (!comment.equals(other.comment))
return false;
if (competitorDisplayName == null) {
if (other.competitorDisplayName != null)
return false;
} else if (!competitorDisplayName.equals(other.competitorDisplayName))
return false;
if (competitorId == null) {
if (other.competitorId != null)
return false;
} else if (!competitorId.equals(other.competitorId))
return false;
if (finishingTime == null) {
if (other.finishingTime != null)
return false;
} else if (!finishingTime.equals(other.finishingTime))
return false;
if (maxPointsReason != other.maxPointsReason)
return false;
if (oneBasedRank != other.oneBasedRank)
return false;
if (score == null) {
if (other.score != null)
return false;
} else if (!score.equals(other.score))
return false;
return true;
}
@Override
public String toString() {
return "CompetitorResultImpl [competitorId=" + competitorId + ", competitorName=" + competitorDisplayName + ", rank="
+ oneBasedRank + ", maxPointsReason=" + maxPointsReason + ", score=" + score + ", finishingTime="
+ finishingTime + ", comment=" + comment + "]";
}
}
@@ -1,14 +1,10 @@
package com.sap.sailing.domain.abstractlog.race.impl;
import java.io.Serializable;
import java.util.ArrayList;
import com.sap.sailing.domain.abstractlog.race.CompetitorResult;
import com.sap.sailing.domain.abstractlog.race.CompetitorResults;
import com.sap.sailing.domain.common.MaxPointsReason;
import com.sap.sse.common.Util;
public class CompetitorResultsImpl extends ArrayList<Util.Triple<Serializable, String, MaxPointsReason>> implements CompetitorResults {
public class CompetitorResultsImpl extends ArrayList<CompetitorResult> implements CompetitorResults {
private static final long serialVersionUID = 4928351242700897387L;
}
@@ -1,10 +0,0 @@
package com.sap.sailing.domain.abstractlog.race.tracking;
import com.sap.sailing.domain.abstractlog.race.RaceLogEvent;
import com.sap.sailing.domain.abstractlog.race.RaceLogEventVisitor;
import com.sap.sailing.domain.abstractlog.shared.events.CloseOpenEndedDeviceMappingEvent;
public interface RaceLogCloseOpenEndedDeviceMappingEvent extends RaceLogEvent,
CloseOpenEndedDeviceMappingEvent<RaceLogEventVisitor> {
}
@@ -1,15 +0,0 @@
package com.sap.sailing.domain.abstractlog.race.tracking;
import com.sap.sailing.domain.abstractlog.Revokable;
import com.sap.sailing.domain.abstractlog.race.RaceLogEvent;
import com.sap.sailing.domain.base.Mark;
/**
* Defines a mark, that can then be used to build a course.
*
* @author Fredrik Teschke
*
*/
public interface RaceLogDefineMarkEvent extends RaceLogEvent, Revokable {
Mark getMark();
}
@@ -5,7 +5,7 @@ import java.io.Serializable;
import com.sap.sailing.domain.abstractlog.Revokable;
import com.sap.sailing.domain.abstractlog.race.RaceLog;
import com.sap.sailing.domain.abstractlog.race.RaceLogEvent;
import com.sap.sailing.domain.abstractlog.shared.events.DeviceMappingEvent;
import com.sap.sailing.domain.abstractlog.regatta.events.RegattaLogDeviceMappingEvent;
import com.sap.sailing.domain.base.BoatClass;
/**
@@ -13,7 +13,7 @@ import com.sap.sailing.domain.base.BoatClass;
* for creating this race will be accumulated in this RaceLog. Once it is present, the
* actual {@link TrackedRace} can then be created from this information, and fixes for
* competitors and marks that arrive on the server, for which a corresponding
* {@link DeviceMappingEvent} exists will be added to the race.
* {@link RegattaLogDeviceMappingEvent} exists will be added to the race.
* @author Fredrik Teschke
*
*/
@@ -1,10 +0,0 @@
package com.sap.sailing.domain.abstractlog.race.tracking;
import com.sap.sailing.domain.abstractlog.race.RaceLogEvent;
import com.sap.sailing.domain.abstractlog.race.RaceLogEventVisitor;
import com.sap.sailing.domain.abstractlog.shared.events.DeviceCompetitorMappingEvent;
public interface RaceLogDeviceCompetitorMappingEvent extends RaceLogEvent,
DeviceCompetitorMappingEvent<RaceLogEventVisitor> {
}
@@ -1,10 +0,0 @@
package com.sap.sailing.domain.abstractlog.race.tracking;
import com.sap.sailing.domain.abstractlog.race.RaceLogEvent;
import com.sap.sailing.domain.abstractlog.race.RaceLogEventVisitor;
import com.sap.sailing.domain.abstractlog.shared.events.DeviceMarkMappingEvent;
public interface RaceLogDeviceMarkMappingEvent extends RaceLogEvent,
DeviceMarkMappingEvent<RaceLogEventVisitor> {
}
@@ -3,7 +3,6 @@ package com.sap.sailing.domain.abstractlog.race.tracking;
import com.sap.sailing.domain.abstractlog.Revokable;
import com.sap.sailing.domain.abstractlog.race.RaceLog;
import com.sap.sailing.domain.abstractlog.race.RaceLogEvent;
import com.sap.sailing.domain.abstractlog.race.tracking.impl.RaceLogDeviceCompetitorMappingEventImpl;
/**
* Closes the phase during which {@link RaceLogDeviceCompetitorMappingEventImpl}s actually result
@@ -0,0 +1,19 @@
package com.sap.sailing.domain.abstractlog.race.tracking;
import com.sap.sailing.domain.abstractlog.Revokable;
import com.sap.sailing.domain.abstractlog.race.RaceLogEvent;
import com.sap.sailing.domain.abstractlog.race.tracking.analyzing.impl.RaceLogUsesOwnCompetitorsAnalyzer;
/**
* This is a marker event, which marks a {@link RaceLog} for using it's own competitor registrations. When present,
* competitors are not registered on the RegattaLog corresponding to the RaceLog, but on the RaceLog itself. This is for
* example used for split fleets.
*
* See bug2851.
*
* @see RaceLogUsesOwnCompetitorsAnalyzer
* @author Jan Bross (D056848)
*
*/
public interface RaceLogUseCompetitorsFromRaceLogEvent extends RaceLogEvent, Revokable {
}
@@ -1,38 +0,0 @@
package com.sap.sailing.domain.abstractlog.race.tracking.analyzing.impl;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import com.sap.sailing.domain.abstractlog.AbstractLog;
import com.sap.sailing.domain.abstractlog.MultiLogAnalyzer.AnalyzerFactory;
import com.sap.sailing.domain.abstractlog.race.RaceLog;
import com.sap.sailing.domain.abstractlog.race.RaceLogEvent;
import com.sap.sailing.domain.abstractlog.race.analyzing.impl.RaceLogAnalyzer;
import com.sap.sailing.domain.abstractlog.race.tracking.RaceLogDefineMarkEvent;
import com.sap.sailing.domain.base.Mark;
public class RaceLogDefinedMarkFinder extends RaceLogAnalyzer<Collection<Mark>> {
public RaceLogDefinedMarkFinder(RaceLog raceLog) {
super(raceLog);
}
public static class Factory implements AnalyzerFactory<Collection<Mark>> {
@Override
public RaceLogAnalyzer<Collection<Mark>> createAnalyzer(AbstractLog<?, ?> log) {
return new RaceLogDefinedMarkFinder((RaceLog) log);
}
}
@Override
protected Collection<Mark> performAnalysis() {
List<Mark> result = new ArrayList<Mark>();
for (RaceLogEvent event : getLog().getUnrevokedEvents()) {
if (event instanceof RaceLogDefineMarkEvent) {
RaceLogDefineMarkEvent dME = (RaceLogDefineMarkEvent) event;
result.add(dME.getMark());
}
}
return result;
}
}
@@ -1,16 +0,0 @@
package com.sap.sailing.domain.abstractlog.race.tracking.analyzing.impl;
import com.sap.sailing.domain.abstractlog.race.RaceLog;
import com.sap.sailing.domain.abstractlog.race.RaceLogEvent;
import com.sap.sailing.domain.abstractlog.race.RaceLogEventVisitor;
import com.sap.sailing.domain.abstractlog.shared.analyzing.LastPingMappingEventFinder;
import com.sap.sse.common.WithID;
public class RaceLogLastPingMappingEventFinder<ItemT extends WithID>
extends LastPingMappingEventFinder<RaceLog, RaceLogEvent, RaceLogEventVisitor, ItemT> {
public RaceLogLastPingMappingEventFinder(RaceLog log, WithID forItem) {
super(log, forItem);
}
}
@@ -1,30 +0,0 @@
package com.sap.sailing.domain.abstractlog.race.tracking.analyzing.impl;
import java.io.Serializable;
import com.sap.sailing.domain.abstractlog.AbstractLogEventAuthor;
import com.sap.sailing.domain.abstractlog.race.RaceLog;
import com.sap.sailing.domain.abstractlog.race.RaceLogEvent;
import com.sap.sailing.domain.abstractlog.race.RaceLogEventVisitor;
import com.sap.sailing.domain.abstractlog.race.tracking.RaceLogCloseOpenEndedDeviceMappingEvent;
import com.sap.sailing.domain.abstractlog.race.tracking.impl.RaceLogCloseOpenEndedDeviceMappingEventImpl;
import com.sap.sailing.domain.abstractlog.shared.analyzing.OpenEndedDeviceMappingCloser;
import com.sap.sailing.domain.racelogtracking.DeviceMapping;
import com.sap.sse.common.TimePoint;
public class RaceLogOpenEndedDeviceMappingCloser extends
OpenEndedDeviceMappingCloser<RaceLog, RaceLogEvent, RaceLogEventVisitor, RaceLogCloseOpenEndedDeviceMappingEvent> {
public RaceLogOpenEndedDeviceMappingCloser(RaceLog log, DeviceMapping<?> mapping, AbstractLogEventAuthor author,
TimePoint closingTimePoint) {
super(log, mapping, author, closingTimePoint);
}
@Override
protected RaceLogCloseOpenEndedDeviceMappingEvent createCloseEvent(TimePoint logicalTimePoint,
Serializable eventToCloseId) {
return new RaceLogCloseOpenEndedDeviceMappingEventImpl(
logicalTimePoint, author, getLog().getCurrentPassId(), eventToCloseId, closingTimePoint);
}
}
@@ -0,0 +1,29 @@
package com.sap.sailing.domain.abstractlog.race.tracking.analyzing.impl;
import java.util.List;
import com.sap.sailing.domain.abstractlog.impl.AllEventsOfTypeFinder;
import com.sap.sailing.domain.abstractlog.race.RaceLog;
import com.sap.sailing.domain.abstractlog.race.RaceLogEvent;
import com.sap.sailing.domain.abstractlog.race.analyzing.impl.RaceLogAnalyzer;
import com.sap.sailing.domain.abstractlog.race.tracking.RaceLogUseCompetitorsFromRaceLogEvent;
/**
* Determines whether the race log claims to authoritatively define the competitors for the race to which it belongs.
* This depends on the presence of an unrevoked {@link RaceLogUseCompetitorsFromRaceLogEvent} event in the race log.
*
* @author Jan Bross
*
*/
public class RaceLogUsesOwnCompetitorsAnalyzer extends RaceLogAnalyzer<Boolean>{
public RaceLogUsesOwnCompetitorsAnalyzer(RaceLog raceLog) {
super(raceLog);
}
@Override
protected Boolean performAnalysis() {
RaceLog raceLog = getLog();
List<RaceLogEvent> event = new AllEventsOfTypeFinder<>(raceLog, /*only unrevoked*/ true, RaceLogUseCompetitorsFromRaceLogEvent.class).analyze();
return event.size() >= 1;
}
}
@@ -0,0 +1,43 @@
package com.sap.sailing.domain.abstractlog.race.tracking.analyzing.impl;
import java.util.Set;
import com.sap.sailing.domain.abstractlog.race.RaceLog;
import com.sap.sailing.domain.abstractlog.race.analyzing.impl.RaceLogAnalyzer;
import com.sap.sailing.domain.abstractlog.regatta.RegattaLog;
import com.sap.sailing.domain.abstractlog.shared.analyzing.CompetitorsInLogAnalyzer;
import com.sap.sailing.domain.base.Competitor;
/**
* Used to find competitors of a race based on {@link RaceLog} and {@link RegattaLog} contents. Checks whether the
* competitors for the given race are registered on the RaceLog via {@link RaceLogUsesOwnCompetitorsAnalyzer} or on the
* RegattaLog and fetches the competitors appropriately.
*
* Should not be used by clients directly. Instead, get the competitor set from the {@code RaceColumn}, using either one
* of {@code getAllCompetitors()} and {@code getAllCompetitors(Fleet)}. Those methods automatically check whether a
* tracked race is present, which takes precedence over the Race/RegattaLog.
*
* @author Jan Bross (D056848)
*
*/
public class RegisteredCompetitorsAnalyzer extends RaceLogAnalyzer<Set<Competitor>> {
private RegattaLog regattaLog;
public RegisteredCompetitorsAnalyzer(RaceLog raceLog, RegattaLog regattaLog) {
super(raceLog);
this.regattaLog = regattaLog;
}
@Override
protected Set<Competitor> performAnalysis() {
final Set<Competitor> result;
if (new RaceLogUsesOwnCompetitorsAnalyzer(getLog()).analyze()) {
// get Events from RaceLog
result = new CompetitorsInLogAnalyzer<>(getLog()).analyze();
} else {
// get Events from RegattaLog
result = new CompetitorsInLogAnalyzer<>(regattaLog).analyze();
}
return result;
}
}
@@ -1,49 +0,0 @@
package com.sap.sailing.domain.abstractlog.race.tracking.impl;
import java.io.Serializable;
import java.util.List;
import com.sap.sailing.domain.abstractlog.AbstractLogEventAuthor;
import com.sap.sailing.domain.abstractlog.race.RaceLogEvent;
import com.sap.sailing.domain.abstractlog.race.RaceLogEventData;
import com.sap.sailing.domain.abstractlog.race.RaceLogEventVisitor;
import com.sap.sailing.domain.abstractlog.race.impl.RaceLogEventDataImpl;
import com.sap.sailing.domain.abstractlog.shared.events.impl.AbstractDeviceMappingEventImpl;
import com.sap.sailing.domain.base.Competitor;
import com.sap.sailing.domain.racelogtracking.DeviceIdentifier;
import com.sap.sse.common.TimePoint;
import com.sap.sse.common.WithID;
public abstract class AbstractRaceLogDeviceMappingEventImpl<ItemT extends WithID>
extends AbstractDeviceMappingEventImpl<RaceLogEventVisitor, ItemT> implements RaceLogEvent {
private static final long serialVersionUID = -5114645637316367845L;
private final RaceLogEventData raceLogEventData;
public AbstractRaceLogDeviceMappingEventImpl(TimePoint createdAt, TimePoint logicalTimePoint,
AbstractLogEventAuthor author, Serializable id, int passId, ItemT mappedTo, DeviceIdentifier device,
TimePoint from, TimePoint to) {
super(createdAt, logicalTimePoint, author, id, mappedTo, device, from, to);
this.raceLogEventData = new RaceLogEventDataImpl(null, passId);
}
public AbstractRaceLogDeviceMappingEventImpl(TimePoint logicalTimePoint,
AbstractLogEventAuthor author, int passId, ItemT mappedTo, DeviceIdentifier device,
TimePoint from, TimePoint to) {
this(now(), logicalTimePoint, author, randId(), passId, mappedTo, device, from, to);
}
@Override
public int getPassId() {
return raceLogEventData.getPassId();
}
@Override
public List<Competitor> getInvolvedBoats() {
return raceLogEventData.getInvolvedBoats();
}
@Override
public String toString() {
return raceLogEventData.toString();
}
}
@@ -1,52 +0,0 @@
package com.sap.sailing.domain.abstractlog.race.tracking.impl;
import java.io.Serializable;
import java.util.List;
import com.sap.sailing.domain.abstractlog.AbstractLogEventAuthor;
import com.sap.sailing.domain.abstractlog.race.RaceLogEventData;
import com.sap.sailing.domain.abstractlog.race.RaceLogEventVisitor;
import com.sap.sailing.domain.abstractlog.race.impl.RaceLogEventDataImpl;
import com.sap.sailing.domain.abstractlog.race.tracking.RaceLogCloseOpenEndedDeviceMappingEvent;
import com.sap.sailing.domain.abstractlog.shared.events.impl.BaseCloseOpenEndedDeviceMappingEventImpl;
import com.sap.sailing.domain.base.Competitor;
import com.sap.sse.common.TimePoint;
public class RaceLogCloseOpenEndedDeviceMappingEventImpl extends
BaseCloseOpenEndedDeviceMappingEventImpl<RaceLogEventVisitor> implements
RaceLogCloseOpenEndedDeviceMappingEvent {
private static final long serialVersionUID = -5114645637316367845L;
private final RaceLogEventData raceLogEventData;
public RaceLogCloseOpenEndedDeviceMappingEventImpl(TimePoint createdAt, TimePoint logicalTimePoint,
AbstractLogEventAuthor author, Serializable id, int passId, Serializable deviceMappingEventId,
TimePoint closingTimePoint) {
super(createdAt, logicalTimePoint, author, id, deviceMappingEventId, closingTimePoint);
this.raceLogEventData = new RaceLogEventDataImpl(null, passId);
}
public RaceLogCloseOpenEndedDeviceMappingEventImpl(TimePoint logicalTimePoint, AbstractLogEventAuthor author,
int passId, Serializable deviceMappingEventId, TimePoint closingTimePoint) {
this(now(), logicalTimePoint, author, randId(), passId, deviceMappingEventId, closingTimePoint);
}
@Override
public int getPassId() {
return raceLogEventData.getPassId();
}
@Override
public List<Competitor> getInvolvedBoats() {
return raceLogEventData.getInvolvedBoats();
}
@Override
public String toString() {
return raceLogEventData.toString();
}
@Override
public void accept(RaceLogEventVisitor visitor) {
visitor.visit(this);
}
}
@@ -1,43 +0,0 @@
package com.sap.sailing.domain.abstractlog.race.tracking.impl;
import java.io.Serializable;
import com.sap.sailing.domain.abstractlog.AbstractLogEventAuthor;
import com.sap.sailing.domain.abstractlog.race.RaceLogEventVisitor;
import com.sap.sailing.domain.abstractlog.race.impl.RaceLogEventImpl;
import com.sap.sailing.domain.abstractlog.race.tracking.RaceLogDefineMarkEvent;
import com.sap.sailing.domain.base.Mark;
import com.sap.sse.common.TimePoint;
public class RaceLogDefineMarkEventImpl extends RaceLogEventImpl implements RaceLogDefineMarkEvent {
private static final long serialVersionUID = 277007856878002208L;
private final Mark mark;
public RaceLogDefineMarkEventImpl(TimePoint createdAt, TimePoint logicalTimePoint, AbstractLogEventAuthor author,
Serializable pId, int pPassId, Mark mark) {
super(createdAt, logicalTimePoint, author, pId, pPassId);
this.mark = mark;
}
public RaceLogDefineMarkEventImpl(TimePoint logicalTimePoint, AbstractLogEventAuthor author,
int pPassId, Mark mark) {
this(now(), logicalTimePoint, author, randId(), pPassId, mark);
}
@Override
public void accept(RaceLogEventVisitor visitor) {
visitor.visit(this);
}
@Override
public Mark getMark() {
return mark;
}
@Override
public String getShortInfo() {
return mark.toString();
}
}
@@ -1,31 +0,0 @@
package com.sap.sailing.domain.abstractlog.race.tracking.impl;
import java.io.Serializable;
import com.sap.sailing.domain.abstractlog.AbstractLogEventAuthor;
import com.sap.sailing.domain.abstractlog.race.RaceLogEventVisitor;
import com.sap.sailing.domain.abstractlog.race.tracking.RaceLogDeviceCompetitorMappingEvent;
import com.sap.sailing.domain.base.Competitor;
import com.sap.sailing.domain.racelogtracking.DeviceIdentifier;
import com.sap.sse.common.TimePoint;
public class RaceLogDeviceCompetitorMappingEventImpl extends AbstractRaceLogDeviceMappingEventImpl<Competitor>
implements RaceLogDeviceCompetitorMappingEvent {
public RaceLogDeviceCompetitorMappingEventImpl(TimePoint createdAt, TimePoint logicalTimePoint,
AbstractLogEventAuthor author, Serializable pId, int pPassId, Competitor mappedTo, DeviceIdentifier device,
TimePoint from, TimePoint to) {
super(createdAt, logicalTimePoint, author, pId, pPassId, mappedTo, device, from, to);
}
public RaceLogDeviceCompetitorMappingEventImpl(TimePoint logicalTimePoint, AbstractLogEventAuthor author,
int pPassId, Competitor mappedTo, DeviceIdentifier device, TimePoint from, TimePoint to) {
super(logicalTimePoint, author, pPassId, mappedTo, device, from, to);
}
private static final long serialVersionUID = -1494030544804758753L;
@Override
public void accept(RaceLogEventVisitor visitor) {
visitor.visit(this);
}
}
@@ -1,31 +0,0 @@
package com.sap.sailing.domain.abstractlog.race.tracking.impl;
import java.io.Serializable;
import com.sap.sailing.domain.abstractlog.AbstractLogEventAuthor;
import com.sap.sailing.domain.abstractlog.race.RaceLogEventVisitor;
import com.sap.sailing.domain.abstractlog.race.tracking.RaceLogDeviceMarkMappingEvent;
import com.sap.sailing.domain.base.Mark;
import com.sap.sailing.domain.racelogtracking.DeviceIdentifier;
import com.sap.sse.common.TimePoint;
public class RaceLogDeviceMarkMappingEventImpl extends AbstractRaceLogDeviceMappingEventImpl<Mark> implements
RaceLogDeviceMarkMappingEvent {
private static final long serialVersionUID = -7223543830755457196L;
public RaceLogDeviceMarkMappingEventImpl(TimePoint createdAt, TimePoint logicalTimePoint,
AbstractLogEventAuthor author, Serializable pId, int pPassId, Mark mappedTo, DeviceIdentifier device,
TimePoint from, TimePoint to) {
super(createdAt, logicalTimePoint, author, pId, pPassId, mappedTo, device, from, to);
}
public RaceLogDeviceMarkMappingEventImpl(TimePoint logicalTimePoint, AbstractLogEventAuthor author, int pPassId,
Mark mappedTo, DeviceIdentifier device, TimePoint from, TimePoint to) {
super(logicalTimePoint, author, pPassId, mappedTo, device, from, to);
}
@Override
public void accept(RaceLogEventVisitor visitor) {
visitor.visit(this);
}
}
@@ -0,0 +1,31 @@
package com.sap.sailing.domain.abstractlog.race.tracking.impl;
import java.io.Serializable;
import com.sap.sailing.domain.abstractlog.AbstractLogEventAuthor;
import com.sap.sailing.domain.abstractlog.race.RaceLogEventVisitor;
import com.sap.sailing.domain.abstractlog.race.impl.RaceLogEventImpl;
import com.sap.sailing.domain.abstractlog.race.tracking.RaceLogUseCompetitorsFromRaceLogEvent;
import com.sap.sse.common.TimePoint;
public class RaceLogUseCompetitorsFromRaceLogEventImpl extends RaceLogEventImpl implements
RaceLogUseCompetitorsFromRaceLogEvent {
private static final long serialVersionUID = -5114645637316367845L;
public RaceLogUseCompetitorsFromRaceLogEventImpl(TimePoint createdAt, AbstractLogEventAuthor author,
TimePoint logicalTimePoint, Serializable id, int passId)
throws IllegalArgumentException {
super(createdAt, logicalTimePoint, author, id, null, passId);
}
@Override
public String toString() {
return "This RaceLog uses the competitors registered on the RaceLog instead of the competitors on the RegattaLog";
}
@Override
public void accept(RaceLogEventVisitor visitor) {
visitor.visit(this);
}
}
@@ -1,6 +1,7 @@
package com.sap.sailing.domain.abstractlog.regatta;
import com.sap.sailing.domain.abstractlog.regatta.events.RegattaLogCloseOpenEndedDeviceMappingEvent;
import com.sap.sailing.domain.abstractlog.regatta.events.RegattaLogDefineMarkEvent;
import com.sap.sailing.domain.abstractlog.regatta.events.RegattaLogDeviceCompetitorMappingEvent;
import com.sap.sailing.domain.abstractlog.regatta.events.RegattaLogDeviceMarkMappingEvent;
import com.sap.sailing.domain.abstractlog.regatta.events.RegattaLogRegisterCompetitorEvent;
@@ -22,4 +23,6 @@ public interface RegattaLogEventVisitor {
void visit(RegattaLogSetCompetitorTimeOnTimeFactorEvent event);
void visit(RegattaLogSetCompetitorTimeOnDistanceAllowancePerNauticalMileEvent event);
void visit(RegattaLogDefineMarkEvent event);
}
@@ -1,10 +1,26 @@
package com.sap.sailing.domain.abstractlog.regatta.events;
import java.io.Serializable;
import com.sap.sailing.domain.abstractlog.Revokable;
import com.sap.sailing.domain.abstractlog.regatta.RegattaLogEvent;
import com.sap.sailing.domain.abstractlog.regatta.RegattaLogEventVisitor;
import com.sap.sailing.domain.abstractlog.shared.events.CloseOpenEndedDeviceMappingEvent;
public interface RegattaLogCloseOpenEndedDeviceMappingEvent extends RegattaLogEvent,
CloseOpenEndedDeviceMappingEvent<RegattaLogEventVisitor> {
import com.sap.sse.common.TimePoint;
/**
* Closes the time range of a {@link RegattaLogDeviceMappingEvent}. This means that the {@link #getClosingTimePoint() timepoint} provided
* by this event is substituted for the missing timepoint in the {@code DeviceMappingEvent} it refers to.
* @author Fredrik Teschke
*
*/
public interface RegattaLogCloseOpenEndedDeviceMappingEvent extends RegattaLogEvent, Revokable {
/**
* Returns the timepoint that shall substitute the missing one in the corresponding {@link RegattaLogDeviceMappingEvent}.
*/
TimePoint getClosingTimePoint();
/**
* Returns the {@code id} of the event for which this event provides the closing timepoint.
* @return
*/
Serializable getDeviceMappingEventId();
}
@@ -0,0 +1,12 @@
package com.sap.sailing.domain.abstractlog.regatta.events;
import com.sap.sailing.domain.abstractlog.regatta.RegattaLogEvent;
import com.sap.sailing.domain.base.Mark;
/**
* Defines a mark, that can then be used to build a course.
*
*/
public interface RegattaLogDefineMarkEvent extends RegattaLogEvent {
Mark getMark();
}
@@ -1,10 +1,7 @@
package com.sap.sailing.domain.abstractlog.regatta.events;
import com.sap.sailing.domain.abstractlog.regatta.RegattaLogEvent;
import com.sap.sailing.domain.abstractlog.regatta.RegattaLogEventVisitor;
import com.sap.sailing.domain.abstractlog.shared.events.DeviceCompetitorMappingEvent;
public interface RegattaLogDeviceCompetitorMappingEvent extends RegattaLogEvent,
DeviceCompetitorMappingEvent<RegattaLogEventVisitor> {
}
package com.sap.sailing.domain.abstractlog.regatta.events;
import com.sap.sailing.domain.base.Competitor;
public interface RegattaLogDeviceCompetitorMappingEvent extends RegattaLogDeviceMappingEvent<Competitor> {
}
@@ -1,8 +1,8 @@
package com.sap.sailing.domain.abstractlog.shared.events;
package com.sap.sailing.domain.abstractlog.regatta.events;
import com.sap.sailing.domain.abstractlog.AbstractLogEvent;
import com.sap.sailing.domain.abstractlog.Revokable;
import com.sap.sailing.domain.abstractlog.race.tracking.analyzing.impl.RaceLogDefinedMarkFinder;
import com.sap.sailing.domain.abstractlog.regatta.RegattaLogEvent;
import com.sap.sailing.domain.abstractlog.regatta.tracking.analyzing.impl.RegattaLogDefinedMarkAnalyzer;
import com.sap.sailing.domain.base.Competitor;
import com.sap.sailing.domain.base.Mark;
import com.sap.sailing.domain.racelogtracking.DeviceIdentifier;
@@ -17,12 +17,12 @@ import com.sap.sse.common.WithID;
* as the semantics of somehow later limiting this range would become unclear
* <p>
* If one end of the time range enclosed by {@link #getFrom()} and {@link #getTo()} is open, this can be closed
* by a {@link CloseOpenEndedDeviceMappingEvent}.
* by a {@link RegattaLogCloseOpenEndedDeviceMappingEvent}.
*
* @see RaceLogDefinedMarkFinder for rules by which {@link DeviceMapping}s are derived from these events.
* @see RegattaLogDefinedMarkAnalyzer for rules by which {@link DeviceMapping}s are derived from these events.
* @author Fredrik Teschke
*/
public interface DeviceMappingEvent<VisitorT, ItemType extends WithID> extends AbstractLogEvent<VisitorT>, Revokable {
public interface RegattaLogDeviceMappingEvent<ItemType extends WithID> extends RegattaLogEvent, Revokable {
ItemType getMappedTo();
DeviceIdentifier getDevice();
@@ -1,16 +1,16 @@
package com.sap.sailing.domain.abstractlog.shared.events.impl;
package com.sap.sailing.domain.abstractlog.regatta.events;
import java.io.Serializable;
import com.sap.sailing.domain.abstractlog.AbstractLogEventAuthor;
import com.sap.sailing.domain.abstractlog.impl.AbstractLogEventImpl;
import com.sap.sailing.domain.abstractlog.shared.events.DeviceMappingEvent;
import com.sap.sailing.domain.abstractlog.regatta.RegattaLogEventVisitor;
import com.sap.sailing.domain.racelogtracking.DeviceIdentifier;
import com.sap.sse.common.TimePoint;
import com.sap.sse.common.WithID;
public abstract class AbstractDeviceMappingEventImpl<VisitorT, ItemType extends WithID> extends AbstractLogEventImpl<VisitorT> implements
DeviceMappingEvent<VisitorT, ItemType> {
public abstract class RegattaLogDeviceMappingEventImpl<ItemType extends WithID> extends AbstractLogEventImpl<RegattaLogEventVisitor> implements
RegattaLogDeviceMappingEvent<ItemType> {
private static final long serialVersionUID = -8439653251231710356L;
private final ItemType mappedTo;
@@ -18,7 +18,7 @@ DeviceMappingEvent<VisitorT, ItemType> {
private final TimePoint from;
private final TimePoint to;
public AbstractDeviceMappingEventImpl(TimePoint createdAt, TimePoint logicalTimePoint,
public RegattaLogDeviceMappingEventImpl(TimePoint createdAt, TimePoint logicalTimePoint,
AbstractLogEventAuthor author, Serializable id, ItemType mappedTo,
DeviceIdentifier device, TimePoint from, TimePoint to) {
super(createdAt, logicalTimePoint, author, id);
@@ -28,7 +28,7 @@ DeviceMappingEvent<VisitorT, ItemType> {
this.to = to;
}
public AbstractDeviceMappingEventImpl(TimePoint logicalTimePoint,
public RegattaLogDeviceMappingEventImpl(TimePoint logicalTimePoint,
AbstractLogEventAuthor author, ItemType mappedTo,
DeviceIdentifier device, TimePoint from, TimePoint to) {
this(now(), logicalTimePoint, author, randId(), mappedTo, device, from, to);
@@ -1,10 +1,9 @@
package com.sap.sailing.domain.abstractlog.regatta.events;
import com.sap.sailing.domain.abstractlog.regatta.RegattaLogEvent;
import com.sap.sailing.domain.abstractlog.regatta.RegattaLogEventVisitor;
import com.sap.sailing.domain.abstractlog.shared.events.DeviceMarkMappingEvent;
public interface RegattaLogDeviceMarkMappingEvent extends RegattaLogEvent,
DeviceMarkMappingEvent<RegattaLogEventVisitor> {
}
package com.sap.sailing.domain.abstractlog.regatta.events;
import com.sap.sailing.domain.abstractlog.regatta.RegattaLogEvent;
import com.sap.sailing.domain.base.Mark;
public interface RegattaLogDeviceMarkMappingEvent extends RegattaLogDeviceMappingEvent<Mark>, RegattaLogEvent {
}
@@ -3,25 +3,43 @@ package com.sap.sailing.domain.abstractlog.regatta.events.impl;
import java.io.Serializable;
import com.sap.sailing.domain.abstractlog.AbstractLogEventAuthor;
import com.sap.sailing.domain.abstractlog.impl.AbstractLogEventImpl;
import com.sap.sailing.domain.abstractlog.regatta.RegattaLogEventVisitor;
import com.sap.sailing.domain.abstractlog.regatta.events.RegattaLogCloseOpenEndedDeviceMappingEvent;
import com.sap.sailing.domain.abstractlog.shared.events.impl.BaseCloseOpenEndedDeviceMappingEventImpl;
import com.sap.sse.common.TimePoint;
public class RegattaLogCloseOpenEndedDeviceMappingEventImpl extends BaseCloseOpenEndedDeviceMappingEventImpl<RegattaLogEventVisitor>
implements RegattaLogCloseOpenEndedDeviceMappingEvent {
public class RegattaLogCloseOpenEndedDeviceMappingEventImpl extends AbstractLogEventImpl<RegattaLogEventVisitor>
implements RegattaLogCloseOpenEndedDeviceMappingEvent {
private static final long serialVersionUID = -5114645637316367845L;
public RegattaLogCloseOpenEndedDeviceMappingEventImpl(TimePoint createdAt, AbstractLogEventAuthor author,
TimePoint logicalTimePoint, Serializable id, Serializable deviceMappingEventId,
TimePoint closingTimePoint) {
super(createdAt, logicalTimePoint, author, id, deviceMappingEventId, closingTimePoint);
private final Serializable deviceMappingEventId;
private final TimePoint closingTimePoint;
public RegattaLogCloseOpenEndedDeviceMappingEventImpl(TimePoint createdAt, AbstractLogEventAuthor author, TimePoint logicalTimePoint,
Serializable pId, Serializable deviceMappingEventId, TimePoint closingTimePoint) {
super(createdAt, logicalTimePoint, author, pId);
this.deviceMappingEventId = deviceMappingEventId;
this.closingTimePoint = closingTimePoint;
}
public RegattaLogCloseOpenEndedDeviceMappingEventImpl(AbstractLogEventAuthor author,
TimePoint logicalTimePoint, Serializable deviceMappingEventId,
TimePoint closingTimePoint) {
super(logicalTimePoint, author, deviceMappingEventId, closingTimePoint);
public RegattaLogCloseOpenEndedDeviceMappingEventImpl(TimePoint logicalTimePoint, AbstractLogEventAuthor author,
Serializable deviceMappingEventId, TimePoint closingTimePoint) {
this( now(), author, logicalTimePoint, randId(), deviceMappingEventId, closingTimePoint);
}
@Override
public Serializable getDeviceMappingEventId() {
return deviceMappingEventId;
}
@Override
public TimePoint getClosingTimePoint() {
return closingTimePoint;
}
@Override
public String getShortInfo() {
return "closing mapping (id: " + deviceMappingEventId + ") at " + closingTimePoint;
}
@Override
@@ -0,0 +1,38 @@
package com.sap.sailing.domain.abstractlog.regatta.events.impl;
import java.io.Serializable;
import com.sap.sailing.domain.abstractlog.AbstractLogEventAuthor;
import com.sap.sailing.domain.abstractlog.impl.AbstractLogEventImpl;
import com.sap.sailing.domain.abstractlog.regatta.RegattaLogEventVisitor;
import com.sap.sailing.domain.abstractlog.regatta.events.RegattaLogDefineMarkEvent;
import com.sap.sailing.domain.base.Mark;
import com.sap.sse.common.TimePoint;
public class RegattaLogDefineMarkEventImpl extends AbstractLogEventImpl<RegattaLogEventVisitor> implements RegattaLogDefineMarkEvent {
private static final long serialVersionUID = -5114645637316367845L;
protected final Mark mark;
public RegattaLogDefineMarkEventImpl(TimePoint createdAt, AbstractLogEventAuthor author, TimePoint logicalTimePoint,
Serializable pId, Mark mark) {
super(createdAt, logicalTimePoint, author, pId);
this.mark = mark;
}
@Override
public void accept(RegattaLogEventVisitor visitor) {
visitor.visit(this);
}
@Override
public Mark getMark() {
return mark;
}
@Override
public String getShortInfo() {
return "mark: "+mark.toString();
}
}
@@ -5,13 +5,12 @@ import java.io.Serializable;
import com.sap.sailing.domain.abstractlog.AbstractLogEventAuthor;
import com.sap.sailing.domain.abstractlog.regatta.RegattaLogEventVisitor;
import com.sap.sailing.domain.abstractlog.regatta.events.RegattaLogDeviceCompetitorMappingEvent;
import com.sap.sailing.domain.abstractlog.shared.events.impl.AbstractDeviceMappingEventImpl;
import com.sap.sailing.domain.abstractlog.regatta.events.RegattaLogDeviceMappingEventImpl;
import com.sap.sailing.domain.base.Competitor;
import com.sap.sailing.domain.racelogtracking.DeviceIdentifier;
import com.sap.sse.common.TimePoint;
public class RegattaLogDeviceCompetitorMappingEventImpl extends
AbstractDeviceMappingEventImpl<RegattaLogEventVisitor, Competitor> implements
public class RegattaLogDeviceCompetitorMappingEventImpl extends RegattaLogDeviceMappingEventImpl<Competitor> implements
RegattaLogDeviceCompetitorMappingEvent {
public RegattaLogDeviceCompetitorMappingEventImpl(TimePoint createdAt, TimePoint logicalTimePoint,
AbstractLogEventAuthor author, Serializable pId, Competitor mappedTo, DeviceIdentifier device,
@@ -19,9 +18,8 @@ public class RegattaLogDeviceCompetitorMappingEventImpl extends
super(createdAt, logicalTimePoint, author, pId, mappedTo, device, from, to);
}
public RegattaLogDeviceCompetitorMappingEventImpl(TimePoint logicalTimePoint,
AbstractLogEventAuthor author, Competitor mappedTo, DeviceIdentifier device,
TimePoint from, TimePoint to) {
public RegattaLogDeviceCompetitorMappingEventImpl(TimePoint logicalTimePoint, AbstractLogEventAuthor author,
Competitor mappedTo, DeviceIdentifier device, TimePoint from, TimePoint to) {
super(logicalTimePoint, author, mappedTo, device, from, to);
}
@@ -4,18 +4,19 @@ import java.io.Serializable;
import com.sap.sailing.domain.abstractlog.AbstractLogEventAuthor;
import com.sap.sailing.domain.abstractlog.regatta.RegattaLogEventVisitor;
import com.sap.sailing.domain.abstractlog.regatta.events.RegattaLogDeviceMappingEventImpl;
import com.sap.sailing.domain.abstractlog.regatta.events.RegattaLogDeviceMarkMappingEvent;
import com.sap.sailing.domain.abstractlog.shared.events.impl.AbstractDeviceMappingEventImpl;
import com.sap.sailing.domain.base.Mark;
import com.sap.sailing.domain.racelogtracking.DeviceIdentifier;
import com.sap.sse.common.TimePoint;
public class RegattaLogDeviceMarkMappingEventImpl extends AbstractDeviceMappingEventImpl<RegattaLogEventVisitor, Mark>
implements RegattaLogDeviceMarkMappingEvent {
public class RegattaLogDeviceMarkMappingEventImpl extends RegattaLogDeviceMappingEventImpl<Mark> implements
RegattaLogDeviceMarkMappingEvent {
private static final long serialVersionUID = -7223543830755457196L;
public RegattaLogDeviceMarkMappingEventImpl(TimePoint createdAt, TimePoint logicalTimePoint, AbstractLogEventAuthor author,
Serializable pId, Mark mappedTo, DeviceIdentifier device, TimePoint from, TimePoint to) {
public RegattaLogDeviceMarkMappingEventImpl(TimePoint createdAt, TimePoint logicalTimePoint,
AbstractLogEventAuthor author, Serializable pId, Mark mappedTo, DeviceIdentifier device, TimePoint from,
TimePoint to) {
super(createdAt, logicalTimePoint, author, pId, mappedTo, device, from, to);
}
@@ -2,6 +2,7 @@ package com.sap.sailing.domain.abstractlog.regatta.impl;
import com.sap.sailing.domain.abstractlog.regatta.RegattaLogEventVisitor;
import com.sap.sailing.domain.abstractlog.regatta.events.RegattaLogCloseOpenEndedDeviceMappingEvent;
import com.sap.sailing.domain.abstractlog.regatta.events.RegattaLogDefineMarkEvent;
import com.sap.sailing.domain.abstractlog.regatta.events.RegattaLogDeviceCompetitorMappingEvent;
import com.sap.sailing.domain.abstractlog.regatta.events.RegattaLogDeviceMarkMappingEvent;
import com.sap.sailing.domain.abstractlog.regatta.events.RegattaLogRegisterCompetitorEvent;
@@ -39,4 +40,7 @@ public class BaseRegattaLogEventVisitor implements RegattaLogEventVisitor {
public void visit(RegattaLogSetCompetitorTimeOnDistanceAllowancePerNauticalMileEvent event) {
}
@Override
public void visit(RegattaLogDefineMarkEvent event) {
}
}
@@ -3,6 +3,7 @@ package com.sap.sailing.domain.abstractlog.regatta.impl;
import com.sap.sailing.domain.abstractlog.regatta.RegattaLogEvent;
import com.sap.sailing.domain.abstractlog.regatta.RegattaLogEventVisitor;
import com.sap.sailing.domain.abstractlog.regatta.events.RegattaLogCloseOpenEndedDeviceMappingEvent;
import com.sap.sailing.domain.abstractlog.regatta.events.RegattaLogDefineMarkEvent;
import com.sap.sailing.domain.abstractlog.regatta.events.RegattaLogDeviceCompetitorMappingEvent;
import com.sap.sailing.domain.abstractlog.regatta.events.RegattaLogDeviceMarkMappingEvent;
import com.sap.sailing.domain.abstractlog.regatta.events.RegattaLogRegisterCompetitorEvent;
@@ -47,4 +48,9 @@ public abstract class RegattaLogEventListener implements RegattaLogEventVisitor
public void visit(RegattaLogSetCompetitorTimeOnDistanceAllowancePerNauticalMileEvent event) {
eventAdded(event);
}
@Override
public void visit(RegattaLogDefineMarkEvent event) {
eventAdded(event);
}
}
@@ -0,0 +1,22 @@
package com.sap.sailing.domain.abstractlog.regatta.tracking.analyzing.impl;
import com.sap.sailing.domain.abstractlog.BaseLogAnalyzer;
import com.sap.sailing.domain.abstractlog.regatta.RegattaLog;
import com.sap.sailing.domain.abstractlog.regatta.RegattaLogEvent;
import com.sap.sailing.domain.abstractlog.regatta.RegattaLogEventVisitor;
public abstract class RegattaLogAnalyzer<ResultType> extends BaseLogAnalyzer
<RegattaLog, RegattaLogEvent, RegattaLogEventVisitor, ResultType> {
public RegattaLogAnalyzer(RegattaLog raceLog) {
super(raceLog);
}
protected Iterable<RegattaLogEvent> getPassEvents() {
return log.getFixes();
}
protected Iterable<RegattaLogEvent> getPassEventsDescending() {
return log.getFixesDescending();
}
}
@@ -0,0 +1,31 @@
package com.sap.sailing.domain.abstractlog.regatta.tracking.analyzing.impl;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import com.sap.sailing.domain.abstractlog.impl.AllEventsOfTypeFinder;
import com.sap.sailing.domain.abstractlog.regatta.RegattaLog;
import com.sap.sailing.domain.abstractlog.regatta.RegattaLogEvent;
import com.sap.sailing.domain.abstractlog.regatta.events.RegattaLogDefineMarkEvent;
import com.sap.sailing.domain.base.Mark;
public class RegattaLogDefinedMarkAnalyzer extends RegattaLogAnalyzer<Collection<Mark>> {
public RegattaLogDefinedMarkAnalyzer(RegattaLog log) {
super(log);
}
@Override
protected Collection<Mark> performAnalysis() {
List<Mark> result = new ArrayList<Mark>();
List<RegattaLogEvent> defineMarkEvents = new AllEventsOfTypeFinder<>(log, true, RegattaLogDefineMarkEvent.class)
.analyze();
for (RegattaLogEvent event : defineMarkEvents) {
RegattaLogDefineMarkEvent dME = (RegattaLogDefineMarkEvent) event;
result.add(dME.getMark());
}
return result;
}
}
@@ -0,0 +1,18 @@
package com.sap.sailing.domain.abstractlog.regatta.tracking.analyzing.impl;
import com.sap.sailing.domain.abstractlog.regatta.RegattaLog;
import com.sap.sailing.domain.abstractlog.regatta.events.RegattaLogDeviceCompetitorMappingEvent;
import com.sap.sailing.domain.abstractlog.regatta.events.RegattaLogDeviceMappingEvent;
import com.sap.sailing.domain.base.Competitor;
public class RegattaLogDeviceCompetitorMappingFinder extends RegattaLogDeviceMappingFinder<Competitor> {
public RegattaLogDeviceCompetitorMappingFinder(RegattaLog log) {
super(log);
}
@Override
protected boolean isValidMapping(RegattaLogDeviceMappingEvent<?> mapping) {
return mapping instanceof RegattaLogDeviceCompetitorMappingEvent;
}
}
@@ -0,0 +1,103 @@
package com.sap.sailing.domain.abstractlog.regatta.tracking.analyzing.impl;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.logging.Logger;
import com.sap.sailing.domain.abstractlog.race.RaceLog;
import com.sap.sailing.domain.abstractlog.regatta.RegattaLog;
import com.sap.sailing.domain.abstractlog.regatta.RegattaLogEvent;
import com.sap.sailing.domain.abstractlog.regatta.events.RegattaLogCloseOpenEndedDeviceMappingEvent;
import com.sap.sailing.domain.abstractlog.regatta.events.RegattaLogDeviceMappingEvent;
import com.sap.sailing.domain.racelogtracking.DeviceIdentifier;
import com.sap.sailing.domain.racelogtracking.DeviceMapping;
import com.sap.sailing.domain.racelogtracking.impl.DeviceMappingImpl;
import com.sap.sse.common.TimePoint;
import com.sap.sse.common.TimeRange;
import com.sap.sse.common.WithID;
import com.sap.sse.common.impl.TimeRangeImpl;
/**
* Extracts the {@link DeviceMapping}s with the appropriate {@link TimeRange}s from the {@link RaceLog}.
* Based on the {@link RegattaLogDeviceMappingEvent}s found in the {@code RaceLog} for the tracked {@code items}
* ({@code Competitor}s and {@code Marks}), the actual mappings are created.
* <p>
* Mappings can be defined with an open-ended time range (e.g. track this from now on), which should then be
* closed by a corresponding {@link RegattaLogCloseOpenEndedDeviceMappingEvent}.
* <p>
* The process of removing conflicts between mappings to ensure that only one mapping was active for
* one tracked item has been removed. Instead, every {@code DeviceMappingEvent} now results directly in one
* {@code DeviceMapping}, the only changes being introduced by closing open time ranges in cases where an
* according {@code CloseOpenEndedDeviceMappingEvent} exists.
*/
public class RegattaLogDeviceMappingFinder<ItemT extends WithID> extends RegattaLogAnalyzer<Map<ItemT, List<DeviceMapping<ItemT>>>> {
private static Logger logger = Logger.getLogger(RegattaLogDeviceMappingFinder.class.getName());
public RegattaLogDeviceMappingFinder(RegattaLog log) {
super(log);
}
protected boolean isValidMapping(RegattaLogDeviceMappingEvent<?> mapping) {
return mapping instanceof RegattaLogDeviceMappingEvent;
}
protected DeviceMapping<ItemT> createMapping(DeviceIdentifier device, ItemT item,
TimePoint from, TimePoint to, Serializable originalEventId) {
return new DeviceMappingImpl<ItemT>(item, device, new TimeRangeImpl(from, to),
Collections.singletonList(originalEventId));
}
private <T, U> List<U> getItemSet(Map<T, List<U>> map, T item) {
List<U> list = map.get(item);
if (list == null) {
list = new ArrayList<U>();
map.put(item, list);
}
return list;
}
@Override
protected Map<ItemT, List<DeviceMapping<ItemT>>> performAnalysis() {
Map<ItemT, List<RegattaLogDeviceMappingEvent<ItemT>>> events = new HashMap<ItemT, List<RegattaLogDeviceMappingEvent<ItemT>>>();
Map<ItemT, List<DeviceMapping<ItemT>>> mappings = new HashMap<ItemT, List<DeviceMapping<ItemT>>>();
Map<Serializable, RegattaLogCloseOpenEndedDeviceMappingEvent> closingEvents = new HashMap<Serializable, RegattaLogCloseOpenEndedDeviceMappingEvent>();
for (RegattaLogEvent e : getLog().getUnrevokedEvents()) {
if (e instanceof RegattaLogDeviceMappingEvent && isValidMapping(((RegattaLogDeviceMappingEvent<?>) e))) {
@SuppressWarnings("unchecked")
RegattaLogDeviceMappingEvent<ItemT> mappingEvent = (RegattaLogDeviceMappingEvent<ItemT>) e;
getItemSet(events, mappingEvent.getMappedTo()).add(mappingEvent);
} else if (e instanceof RegattaLogCloseOpenEndedDeviceMappingEvent) {
//a higher priority closing events for the same mapping event overwrites the lower priority one
RegattaLogCloseOpenEndedDeviceMappingEvent closingEvent = (RegattaLogCloseOpenEndedDeviceMappingEvent) e;
closingEvents.put(closingEvent.getDeviceMappingEventId(), closingEvent);
}
}
for (ItemT item : events.keySet()) {
mappings.put(item, closeOpenRanges(events.get(item), item, closingEvents));
}
return mappings;
}
private List<DeviceMapping<ItemT>> closeOpenRanges(List<RegattaLogDeviceMappingEvent<ItemT>> events, ItemT item,
Map<Serializable, RegattaLogCloseOpenEndedDeviceMappingEvent> closingEvents) {
List<DeviceMapping<ItemT>> result = new ArrayList<DeviceMapping<ItemT>>();
for (RegattaLogDeviceMappingEvent<ItemT> event : events) {
TimePoint from = event.getFrom();
TimePoint to = event.getTo();
TimePoint closingTimePoint = closingEvents.containsKey(event.getId()) ? closingEvents.get(event.getId())
.getClosingTimePoint() : null;
if (from == null) {
logger.severe("No start time set for DeviceMappingEvent with ID: " + event.getId());
}
if (to == null) {
to = closingTimePoint;
}
result.add(createMapping(event.getDevice(), item, from, to, event.getId()));
}
return result;
}
}
@@ -0,0 +1,18 @@
package com.sap.sailing.domain.abstractlog.regatta.tracking.analyzing.impl;
import com.sap.sailing.domain.abstractlog.regatta.RegattaLog;
import com.sap.sailing.domain.abstractlog.regatta.events.RegattaLogDeviceMappingEvent;
import com.sap.sailing.domain.abstractlog.regatta.events.RegattaLogDeviceMarkMappingEvent;
import com.sap.sailing.domain.base.Mark;
public class RegattaLogDeviceMarkMappingFinder extends RegattaLogDeviceMappingFinder<Mark> {
public RegattaLogDeviceMarkMappingFinder(RegattaLog log) {
super(log);
}
@Override
protected boolean isValidMapping(RegattaLogDeviceMappingEvent<?> mapping) {
return mapping instanceof RegattaLogDeviceMarkMappingEvent;
}
}
@@ -1,29 +1,55 @@
package com.sap.sailing.domain.abstractlog.regatta.tracking.analyzing.impl;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import com.sap.sailing.domain.abstractlog.AbstractLogEventAuthor;
import com.sap.sailing.domain.abstractlog.regatta.RegattaLog;
import com.sap.sailing.domain.abstractlog.regatta.RegattaLogEvent;
import com.sap.sailing.domain.abstractlog.regatta.RegattaLogEventVisitor;
import com.sap.sailing.domain.abstractlog.regatta.events.RegattaLogCloseOpenEndedDeviceMappingEvent;
import com.sap.sailing.domain.abstractlog.regatta.events.RegattaLogDeviceMappingEvent;
import com.sap.sailing.domain.abstractlog.regatta.events.impl.RegattaLogCloseOpenEndedDeviceMappingEventImpl;
import com.sap.sailing.domain.abstractlog.shared.analyzing.OpenEndedDeviceMappingCloser;
import com.sap.sailing.domain.racelogtracking.DeviceMapping;
import com.sap.sse.common.TimePoint;
import com.sap.sse.common.impl.MillisecondsTimePoint;
/**
* Generates events that close the events that are responsible for the {@link #mapping} that is passed to the
* constructor.
*
* @author Fredrik Teschke
*
*/
public class RegattaLogOpenEndedDeviceMappingCloser extends
OpenEndedDeviceMappingCloser<RegattaLog, RegattaLogEvent, RegattaLogEventVisitor, RegattaLogCloseOpenEndedDeviceMappingEvent> {
RegattaLogAnalyzer<List<RegattaLogCloseOpenEndedDeviceMappingEvent>> {
private final DeviceMapping<?> mapping;
protected final AbstractLogEventAuthor author;
protected final TimePoint closingTimePoint;
public RegattaLogOpenEndedDeviceMappingCloser(RegattaLog log, DeviceMapping<?> mapping, AbstractLogEventAuthor author,
TimePoint closingTimePoint) {
super(log, mapping, author, closingTimePoint);
public RegattaLogOpenEndedDeviceMappingCloser(RegattaLog log, DeviceMapping<?> mapping,
AbstractLogEventAuthor author, TimePoint closingTimePoint) {
super(log);
this.mapping = mapping;
this.author = author;
this.closingTimePoint = closingTimePoint;
}
protected RegattaLogCloseOpenEndedDeviceMappingEvent createCloseEvent(TimePoint logicalTimePoint,
Serializable eventToCloseId) {
return new RegattaLogCloseOpenEndedDeviceMappingEventImpl(logicalTimePoint, author, eventToCloseId,
closingTimePoint);
}
@Override
protected RegattaLogCloseOpenEndedDeviceMappingEvent createCloseEvent(TimePoint logicalTimePoint,
Serializable eventToCloseId) {
return new RegattaLogCloseOpenEndedDeviceMappingEventImpl(author,
logicalTimePoint, eventToCloseId, closingTimePoint);
protected List<RegattaLogCloseOpenEndedDeviceMappingEvent> performAnalysis() {
List<RegattaLogCloseOpenEndedDeviceMappingEvent> result = new ArrayList<RegattaLogCloseOpenEndedDeviceMappingEvent>();
for (Serializable eventId : mapping.getOriginalRaceLogEventIds()) {
RegattaLogDeviceMappingEvent<?> event = (RegattaLogDeviceMappingEvent<?>) getLog().getEventById(eventId);
if (event.getFrom() == null || event.getTo() == null) {
result.add(createCloseEvent(MillisecondsTimePoint.now(), event.getId()));
}
}
return result;
}
}
@@ -0,0 +1,57 @@
package com.sap.sailing.domain.abstractlog.shared.analyzing;
import java.util.HashSet;
import java.util.logging.Level;
import java.util.logging.Logger;
import com.sap.sailing.domain.abstractlog.AbstractLog;
import com.sap.sailing.domain.abstractlog.AbstractLogEvent;
import com.sap.sailing.domain.abstractlog.AbstractLogEventAuthor;
import com.sap.sailing.domain.abstractlog.BaseLogAnalyzer;
import com.sap.sailing.domain.abstractlog.shared.events.RegisterCompetitorEvent;
import com.sap.sailing.domain.base.Competitor;
import com.sap.sailing.domain.common.abstractlog.NotRevokableException;
import com.sap.sse.common.Util;
/**
* Generates events that close the events that are responsible for the {@link #mapping} that is passed to the
* constructor.
*
* @author Jan Broß
*
*/
public class CompetitorDeregistrator<LogT extends AbstractLog<EventT, VisitorT>, EventT extends AbstractLogEvent<VisitorT>, VisitorT>
extends BaseLogAnalyzer<LogT, EventT, VisitorT, Void> {
private static final Logger logger = Logger.getLogger(CompetitorDeregistrator.class.getName());
protected final Iterable<Competitor> competitorsToDeregister;
private AbstractLogEventAuthor eventAuthor;
public CompetitorDeregistrator(LogT log, Iterable<Competitor> competitorsToDeregister, AbstractLogEventAuthor eventAuthor) {
super(log);
this.competitorsToDeregister = competitorsToDeregister;
this.eventAuthor = eventAuthor;
}
@Override
protected Void performAnalysis() {
HashSet<Competitor> competitorSet = new HashSet<Competitor>();
Util.addAll(competitorsToDeregister, competitorSet);
for (EventT event : log.getUnrevokedEventsDescending()) {
if (event instanceof RegisterCompetitorEvent) {
RegisterCompetitorEvent<?> registerEvent = (RegisterCompetitorEvent<?>) event;
if (competitorSet.contains(registerEvent.getCompetitor())) {
try {
log.revokeEvent(eventAuthor, event,
"unregistering competitor because no longer selected for registration");
} catch (NotRevokableException e) {
logger.log(Level.WARNING, "could not unregister competitor by adding RevokeEvent", e);
}
}
}
}
return null;
}
}
@@ -0,0 +1,48 @@
package com.sap.sailing.domain.abstractlog.shared.analyzing;
import java.util.HashSet;
import java.util.Set;
import com.sap.sailing.domain.abstractlog.AbstractLog;
import com.sap.sailing.domain.abstractlog.AbstractLogEvent;
import com.sap.sailing.domain.abstractlog.BaseLogAnalyzer;
import com.sap.sailing.domain.abstractlog.race.analyzing.impl.RaceLogRegisteredCompetitorsAnalyzer;
import com.sap.sailing.domain.abstractlog.race.tracking.RaceLogUseCompetitorsFromRaceLogEvent;
import com.sap.sailing.domain.abstractlog.race.tracking.analyzing.impl.RegisteredCompetitorsAnalyzer;
import com.sap.sailing.domain.abstractlog.shared.events.RegisterCompetitorEvent;
import com.sap.sailing.domain.base.Competitor;
/**
* This class searches for RegisterCompetitorEvents in the given log.
*
* TLDR: It's likely, that you shouldn't use this, but you might want to use {@link RegisteredCompetitorsAnalyzer} or {@link RaceLogRegisteredCompetitorsAnalyzer}
*
* Note that solemnly analyzing a certain race or RegattaLog my not lead the correct registered competitors for the race
* corresponding to the RaceLog/the races corresponding to the RegattaLog.
*
* This is the case as by default the competitors registered on the RegattaLog are used for each race of the regatta
* ignoring the ones in the RaceLog (if present). The RaceLog may override this behavior with the
* {@link RaceLogUseCompetitorsFromRaceLogEvent}. Is an event of this type present, the competitors written into the
* RaceLog are used instead of the competitors in the RegattaLog.
*
*/
public class CompetitorsInLogAnalyzer<LogT extends AbstractLog<EventT, VisitorT>, EventT extends AbstractLogEvent<VisitorT>, VisitorT>
extends BaseLogAnalyzer<LogT, EventT, VisitorT, Set<Competitor>> {
public CompetitorsInLogAnalyzer(LogT log) {
super(log);
}
@Override
protected Set<Competitor> performAnalysis() {
Set<Competitor> result = new HashSet<Competitor>();
for (EventT event : getLog().getUnrevokedEvents()) {
if (event instanceof RegisterCompetitorEvent) {
result.add(((RegisterCompetitorEvent<?>) event).getCompetitor());
}
}
return result;
}
}
@@ -1,34 +0,0 @@
package com.sap.sailing.domain.abstractlog.shared.analyzing;
import java.util.List;
import java.util.Map;
import com.sap.sailing.domain.abstractlog.AbstractLog;
import com.sap.sailing.domain.abstractlog.AbstractLogEvent;
import com.sap.sailing.domain.abstractlog.LogAnalyzer;
import com.sap.sailing.domain.abstractlog.MultiLogAnalyzer.AnalyzerFactory;
import com.sap.sailing.domain.abstractlog.shared.events.DeviceCompetitorMappingEvent;
import com.sap.sailing.domain.abstractlog.shared.events.DeviceMappingEvent;
import com.sap.sailing.domain.base.Competitor;
import com.sap.sailing.domain.racelogtracking.DeviceMapping;
public class DeviceCompetitorMappingFinder<LogT extends AbstractLog<EventT, VisitorT>, EventT extends AbstractLogEvent<VisitorT>, VisitorT>
extends DeviceMappingFinder<LogT, EventT, VisitorT, Competitor> {
public static class Factory implements AnalyzerFactory<Map<Competitor, List<DeviceMapping<Competitor>>>> {
@SuppressWarnings({ "rawtypes", "unchecked" })
@Override
public LogAnalyzer<Map<Competitor, List<DeviceMapping<Competitor>>>> createAnalyzer(AbstractLog<?, ?> log) {
return new DeviceCompetitorMappingFinder(log);
}
}
public DeviceCompetitorMappingFinder(LogT log) {
super(log);
}
@Override
protected boolean isValidMapping(DeviceMappingEvent<?, ?> mapping) {
return mapping instanceof DeviceCompetitorMappingEvent;
}
}
@@ -1,117 +0,0 @@
package com.sap.sailing.domain.abstractlog.shared.analyzing;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.logging.Logger;
import com.sap.sailing.domain.abstractlog.AbstractLog;
import com.sap.sailing.domain.abstractlog.AbstractLogEvent;
import com.sap.sailing.domain.abstractlog.BaseLogAnalyzer;
import com.sap.sailing.domain.abstractlog.LogAnalyzer;
import com.sap.sailing.domain.abstractlog.MultiLogAnalyzer.AnalyzerFactory;
import com.sap.sailing.domain.abstractlog.race.RaceLog;
import com.sap.sailing.domain.abstractlog.shared.events.CloseOpenEndedDeviceMappingEvent;
import com.sap.sailing.domain.abstractlog.shared.events.DeviceMappingEvent;
import com.sap.sailing.domain.racelogtracking.DeviceIdentifier;
import com.sap.sailing.domain.racelogtracking.DeviceMapping;
import com.sap.sailing.domain.racelogtracking.impl.DeviceMappingImpl;
import com.sap.sse.common.TimePoint;
import com.sap.sse.common.TimeRange;
import com.sap.sse.common.WithID;
import com.sap.sse.common.impl.TimeRangeImpl;
/**
* Extracts the {@link DeviceMapping}s with the appropriate {@link TimeRange}s from the {@link RaceLog}.
* Based on the {@link DeviceMappingEvent}s found in the {@code RaceLog} for the tracked {@code items}
* ({@code Competitor}s and {@code Marks}), the actual mappings are created.
* <p>
* Mappings can be defined with an open-ended time range (e.g. track this from now on), which should then be
* closed by a corresponding {@link CloseOpenEndedDeviceMappingEvent}.
* <p>
* The process of removing conflicts between mappings to ensure that only one mapping was active for
* one tracked item has been removed. Instead, every {@code DeviceMappingEvent} now results directly in one
* {@code DeviceMapping}, the only changes being introduced by closing open time ranges in cases where an
* according {@code CloseOpenEndedDeviceMappingEvent} exists.
*/
public class DeviceMappingFinder<LogT extends AbstractLog<EventT, VisitorT>, EventT extends AbstractLogEvent<VisitorT>,
VisitorT, ItemT extends WithID> extends BaseLogAnalyzer<LogT, EventT, VisitorT, Map<ItemT, List<DeviceMapping<ItemT>>>> {
public static class Factory<ItemT extends WithID> implements AnalyzerFactory<Map<ItemT, List<DeviceMapping<ItemT>>>> {
@SuppressWarnings({ "rawtypes", "unchecked" })
@Override
public LogAnalyzer<Map<ItemT, List<DeviceMapping<ItemT>>>> createAnalyzer(AbstractLog<?, ?> log) {
return new DeviceMappingFinder(log);
}
}
private static Logger logger = Logger.getLogger(DeviceMappingFinder.class.getName());
public DeviceMappingFinder(LogT log) {
super(log);
}
protected boolean isValidMapping(DeviceMappingEvent<?, ?> mapping) {
return mapping instanceof DeviceMappingEvent;
}
protected DeviceMapping<ItemT> getMapping(DeviceIdentifier device, ItemT item,
TimePoint from, TimePoint to, Serializable originalEventId) {
return new DeviceMappingImpl<ItemT>(item, device, new TimeRangeImpl(from, to),
Collections.singletonList(originalEventId));
}
private <T, U> List<U> getItemSet(Map<T, List<U>> map, T item) {
List<U> list = map.get(item);
if (list == null) {
list = new ArrayList<U>();
map.put(item, list);
}
return list;
}
@Override
protected Map<ItemT, List<DeviceMapping<ItemT>>> performAnalysis() {
Map<ItemT, List<DeviceMappingEvent<?, ItemT>>> events = new HashMap<ItemT, List<DeviceMappingEvent<?, ItemT>>>();
Map<ItemT, List<DeviceMapping<ItemT>>> mappings = new HashMap<ItemT, List<DeviceMapping<ItemT>>>();
Map<Serializable, CloseOpenEndedDeviceMappingEvent<?>> closingEvents = new HashMap<Serializable, CloseOpenEndedDeviceMappingEvent<?>>();
for (EventT e : getLog().getUnrevokedEvents()) {
if (e instanceof DeviceMappingEvent && isValidMapping(((DeviceMappingEvent<?, ?>) e))) {
@SuppressWarnings("unchecked")
DeviceMappingEvent<?, ItemT> mappingEvent = (DeviceMappingEvent<?, ItemT>) e;
getItemSet(events, mappingEvent.getMappedTo()).add(mappingEvent);
} else if (e instanceof CloseOpenEndedDeviceMappingEvent) {
//a higher priority closing events for the same mapping event overwrites the lower priority one
CloseOpenEndedDeviceMappingEvent<?> closingEvent = (CloseOpenEndedDeviceMappingEvent<?>) e;
closingEvents.put(closingEvent.getDeviceMappingEventId(), closingEvent);
}
}
for (ItemT item : events.keySet()) {
mappings.put(item, closeOpenRanges(events.get(item), item, closingEvents));
}
return mappings;
}
private List<DeviceMapping<ItemT>> closeOpenRanges(List<DeviceMappingEvent<?, ItemT>> events, ItemT item,
Map<Serializable, CloseOpenEndedDeviceMappingEvent<?>> closingEvents) {
List<DeviceMapping<ItemT>> result = new ArrayList<DeviceMapping<ItemT>>();
for (DeviceMappingEvent<?, ItemT> event : events) {
TimePoint from = event.getFrom();
TimePoint to = event.getTo();
TimePoint closingTimePoint = closingEvents.containsKey(event.getId()) ?
closingEvents.get(event.getId()).getClosingTimePoint() : null;
if (from == null) logger.severe("No start time set for DeviceMappingEvent with ID: "+event.getId());
if (to == null) to = closingTimePoint;
result.add(getMapping(event.getDevice(), item, from, to, event.getId()));
}
return result;
}
}
@@ -1,34 +0,0 @@
package com.sap.sailing.domain.abstractlog.shared.analyzing;
import java.util.List;
import java.util.Map;
import com.sap.sailing.domain.abstractlog.AbstractLog;
import com.sap.sailing.domain.abstractlog.AbstractLogEvent;
import com.sap.sailing.domain.abstractlog.LogAnalyzer;
import com.sap.sailing.domain.abstractlog.MultiLogAnalyzer.AnalyzerFactory;
import com.sap.sailing.domain.abstractlog.shared.events.DeviceMappingEvent;
import com.sap.sailing.domain.abstractlog.shared.events.DeviceMarkMappingEvent;
import com.sap.sailing.domain.base.Mark;
import com.sap.sailing.domain.racelogtracking.DeviceMapping;
public class DeviceMarkMappingFinder<LogT extends AbstractLog<EventT, VisitorT>, EventT extends AbstractLogEvent<VisitorT>, VisitorT>
extends DeviceMappingFinder<LogT, EventT, VisitorT, Mark> {
public static class Factory implements AnalyzerFactory<Map<Mark, List<DeviceMapping<Mark>>>> {
@SuppressWarnings({ "rawtypes", "unchecked" })
@Override
public LogAnalyzer<Map<Mark, List<DeviceMapping<Mark>>>> createAnalyzer(AbstractLog<?, ?> log) {
return new DeviceMarkMappingFinder(log);
}
}
public DeviceMarkMappingFinder(LogT log) {
super(log);
}
@Override
protected boolean isValidMapping(DeviceMappingEvent<?, ?> mapping) {
return mapping instanceof DeviceMarkMappingEvent;
}
}
@@ -1,35 +0,0 @@
package com.sap.sailing.domain.abstractlog.shared.analyzing;
import com.sap.sailing.domain.abstractlog.AbstractLog;
import com.sap.sailing.domain.abstractlog.AbstractLogEvent;
import com.sap.sailing.domain.abstractlog.BaseLogAnalyzer;
import com.sap.sailing.domain.abstractlog.shared.events.DeviceMappingEvent;
import com.sap.sse.common.WithID;
public class LastPingMappingEventFinder <LogT extends AbstractLog<EventT, VisitorT>,
EventT extends AbstractLogEvent<VisitorT>, VisitorT, ItemT extends WithID>
extends BaseLogAnalyzer<LogT, EventT, VisitorT, DeviceMappingEvent<VisitorT, ItemT>> {
private final WithID item;
public LastPingMappingEventFinder(LogT log, WithID forItem) {
super(log);
this.item = forItem;
}
@Override
protected DeviceMappingEvent<VisitorT, ItemT> performAnalysis() {
for (EventT e : getLog().getUnrevokedEventsDescending()) {
if (e instanceof DeviceMappingEvent) {
DeviceMappingEvent<?, ?> mappingEvent = (DeviceMappingEvent<?, ?>) e;
if (item.equals(mappingEvent.getMappedTo()) && mappingEvent.getFrom() != null &&
mappingEvent.getTo() != null && mappingEvent.getFrom().equals(mappingEvent.getTo())) {
@SuppressWarnings("unchecked")
DeviceMappingEvent<VisitorT, ItemT> cast = (DeviceMappingEvent<VisitorT, ItemT>) mappingEvent;
return cast;
}
}
}
return null;
}
}
@@ -1,53 +0,0 @@
package com.sap.sailing.domain.abstractlog.shared.analyzing;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import com.sap.sailing.domain.abstractlog.AbstractLog;
import com.sap.sailing.domain.abstractlog.AbstractLogEvent;
import com.sap.sailing.domain.abstractlog.AbstractLogEventAuthor;
import com.sap.sailing.domain.abstractlog.BaseLogAnalyzer;
import com.sap.sailing.domain.abstractlog.shared.events.CloseOpenEndedDeviceMappingEvent;
import com.sap.sailing.domain.abstractlog.shared.events.DeviceMappingEvent;
import com.sap.sailing.domain.racelogtracking.DeviceMapping;
import com.sap.sse.common.TimePoint;
import com.sap.sse.common.impl.MillisecondsTimePoint;
/**
* Generates events that close the events that are responsible for the {@link #mapping}
* that is passed to the constructor.
* @author Fredrik Teschke
*
*/
public abstract class OpenEndedDeviceMappingCloser<LogT extends AbstractLog<EventT, VisitorT>,
EventT extends AbstractLogEvent<VisitorT>,VisitorT, CloseEventT extends CloseOpenEndedDeviceMappingEvent<VisitorT>>
extends BaseLogAnalyzer<LogT, EventT, VisitorT, List<CloseEventT>> {
private final DeviceMapping<?> mapping;
protected final AbstractLogEventAuthor author;
protected final TimePoint closingTimePoint;
public OpenEndedDeviceMappingCloser(LogT log, DeviceMapping<?> mapping, AbstractLogEventAuthor author,
TimePoint closingTimePoint) {
super(log);
this.mapping = mapping;
this.author = author;
this.closingTimePoint = closingTimePoint;
}
protected abstract CloseEventT createCloseEvent(TimePoint logicalTimePoint,
Serializable eventToCloseId);
@Override
protected List<CloseEventT> performAnalysis() {
List<CloseEventT> result = new ArrayList<CloseEventT>();
for (Serializable eventId : mapping.getOriginalRaceLogEventIds()) {
DeviceMappingEvent<?, ?> event = (DeviceMappingEvent<?, ?>) getLog().getEventById(eventId);
if (event.getFrom() == null || event.getTo() == null) {
result.add(createCloseEvent(MillisecondsTimePoint.now(), event.getId()));
}
}
return result;
}
}
@@ -1,52 +0,0 @@
package com.sap.sailing.domain.abstractlog.shared.analyzing;
import java.util.Collection;
import java.util.HashSet;
import java.util.Set;
import com.sap.sailing.domain.abstractlog.AbstractLog;
import com.sap.sailing.domain.abstractlog.AbstractLogEvent;
import com.sap.sailing.domain.abstractlog.BaseLogAnalyzer;
import com.sap.sailing.domain.abstractlog.MultiLogAnalyzer.AnalyzerFactory;
import com.sap.sailing.domain.abstractlog.race.RaceLog;
import com.sap.sailing.domain.abstractlog.shared.events.RegisterCompetitorEvent;
import com.sap.sailing.domain.base.Competitor;
/**
* Uses the {@link RegisterCompetitorEvent}s in the {@link RaceLog} to determine the competitors registered for this
* event.
*
* @author Fredrik Teschke
*
*/
public class RegisteredCompetitorsAnalyzer<LogT extends AbstractLog<EventT, VisitorT>, EventT extends AbstractLogEvent<VisitorT>, VisitorT>
extends BaseLogAnalyzer<LogT, EventT, VisitorT, Set<Competitor>> {
public static enum Factory implements AnalyzerFactory<Collection<Competitor>> {
INSTANCE;
@SuppressWarnings({ "rawtypes", "unchecked" })
@Override
public RegisteredCompetitorsAnalyzer createAnalyzer(AbstractLog<?, ?> log) {
return new RegisteredCompetitorsAnalyzer(log);
}
}
public RegisteredCompetitorsAnalyzer(LogT log) {
super(log);
}
@Override
protected Set<Competitor> performAnalysis() {
Set<Competitor> result = new HashSet<Competitor>();
for (EventT event : getLog().getUnrevokedEvents()) {
if (event instanceof RegisterCompetitorEvent) {
result.add(((RegisterCompetitorEvent<?>) event).getCompetitor());
}
}
return result;
}
}
@@ -1,26 +0,0 @@
package com.sap.sailing.domain.abstractlog.shared.events;
import java.io.Serializable;
import com.sap.sailing.domain.abstractlog.AbstractLogEvent;
import com.sap.sailing.domain.abstractlog.Revokable;
import com.sap.sse.common.TimePoint;
/**
* Closes the time range of a {@link DeviceMappingEvent}. This means that the {@link #getClosingTimePoint() timepoint} provided
* by this event is substituted for the missing timepoint in the {@code DeviceMappingEvent} it refers to.
* @author Fredrik Teschke
*
*/
public interface CloseOpenEndedDeviceMappingEvent<VisitorT> extends AbstractLogEvent<VisitorT>, Revokable {
/**
* Returns the timepoint that shall substitute the missing one in the corresponding {@link DeviceMappingEvent}.
*/
TimePoint getClosingTimePoint();
/**
* Returns the {@code id} of the event for which this event provides the closing timepoint.
* @return
*/
Serializable getDeviceMappingEventId();
}
@@ -1,7 +0,0 @@
package com.sap.sailing.domain.abstractlog.shared.events;
import com.sap.sailing.domain.base.Competitor;
public interface DeviceCompetitorMappingEvent<VisitorT> extends DeviceMappingEvent<VisitorT, Competitor> {
}
@@ -1,8 +0,0 @@
package com.sap.sailing.domain.abstractlog.shared.events;
import com.sap.sailing.domain.base.Mark;
public interface DeviceMarkMappingEvent<VisitorT> extends DeviceMappingEvent<VisitorT, Mark> {
}
@@ -1,43 +0,0 @@
package com.sap.sailing.domain.abstractlog.shared.events.impl;
import java.io.Serializable;
import com.sap.sailing.domain.abstractlog.AbstractLogEventAuthor;
import com.sap.sailing.domain.abstractlog.impl.AbstractLogEventImpl;
import com.sap.sailing.domain.abstractlog.shared.events.CloseOpenEndedDeviceMappingEvent;
import com.sap.sse.common.TimePoint;
public abstract class BaseCloseOpenEndedDeviceMappingEventImpl<VisitorT> extends AbstractLogEventImpl<VisitorT>
implements CloseOpenEndedDeviceMappingEvent<VisitorT> {
private static final long serialVersionUID = -2401732623610224918L;
private final Serializable deviceMappingEventId;
private final TimePoint closingTimePoint;
public BaseCloseOpenEndedDeviceMappingEventImpl(TimePoint createdAt, TimePoint logicalTimePoint,
AbstractLogEventAuthor author, Serializable pId, Serializable deviceMappingEventId, TimePoint closingTimePoint) {
super(createdAt, logicalTimePoint, author, pId);
this.deviceMappingEventId = deviceMappingEventId;
this.closingTimePoint = closingTimePoint;
}
public BaseCloseOpenEndedDeviceMappingEventImpl(TimePoint logicalTimePoint, AbstractLogEventAuthor author,
Serializable deviceMappingEventId, TimePoint closingTimePoint) {
this(now(), logicalTimePoint, author, randId(), deviceMappingEventId, closingTimePoint);
}
@Override
public Serializable getDeviceMappingEventId() {
return deviceMappingEventId;
}
@Override
public TimePoint getClosingTimePoint() {
return closingTimePoint;
}
@Override
public String getShortInfo() {
return "closing mapping (id: " + deviceMappingEventId + ") at " + closingTimePoint;
}
}
@@ -3,13 +3,13 @@ package com.sap.sailing.domain.racelogtracking;
import java.io.Serializable;
import java.util.List;
import com.sap.sailing.domain.abstractlog.shared.analyzing.DeviceMappingFinder;
import com.sap.sailing.domain.abstractlog.regatta.tracking.analyzing.impl.RegattaLogDeviceMappingFinder;
import com.sap.sse.common.TimeRange;
import com.sap.sse.common.Timed;
import com.sap.sse.common.WithID;
/**
* @see DeviceMappingFinder {@code DeviceMappings} are derived from {@code DeviceMappingEvents}. The {@link Timed} interface
* @see RegattaLogDeviceMappingFinder {@code DeviceMappings} are derived from {@code DeviceMappingEvents}. The {@link Timed} interface
* is to be implemented as providing the {@link TimeRange#from()} time point as the answer to {@link Timed#getTimePoint()}.
*
* @author Fredrik Teschke
@@ -4,7 +4,7 @@ import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import com.sap.sailing.domain.abstractlog.shared.events.DeviceMappingEvent;
import com.sap.sailing.domain.abstractlog.regatta.events.RegattaLogDeviceMappingEvent;
import com.sap.sailing.domain.racelogtracking.DeviceIdentifier;
import com.sap.sailing.domain.racelogtracking.DeviceMapping;
import com.sap.sse.common.TimePoint;
@@ -56,7 +56,7 @@ public class DeviceMappingImpl<ItemType extends WithID> implements DeviceMapping
return timeRange.from();
}
public static <T extends WithID> DeviceMapping<T> convertToDeviceMapping(DeviceMappingEvent<?, T> event) {
public static <T extends WithID> DeviceMapping<T> convertToDeviceMapping(RegattaLogDeviceMappingEvent<T> event) {
return new DeviceMappingImpl<T>(event.getMappedTo(), event.getDevice(), new TimeRangeImpl(event.getFrom(), event.getTo()),
event.getId());
}
@@ -21,6 +21,7 @@ import com.sap.sailing.domain.abstractlog.race.RaceLog;
import com.sap.sailing.domain.abstractlog.race.impl.RaceLogRevokeEventImpl;
import com.sap.sailing.domain.abstractlog.race.tracking.RaceLogRegisterCompetitorEvent;
import com.sap.sailing.domain.abstractlog.race.tracking.impl.RaceLogRegisterCompetitorEventImpl;
import com.sap.sailing.domain.abstractlog.race.tracking.impl.RaceLogUseCompetitorsFromRaceLogEventImpl;
import com.sap.sailing.domain.abstractlog.regatta.RegattaLog;
import com.sap.sailing.domain.abstractlog.regatta.events.RegattaLogRegisterCompetitorEvent;
import com.sap.sailing.domain.abstractlog.regatta.events.impl.RegattaLogRegisterCompetitorEventImpl;
@@ -107,7 +108,8 @@ public class CompetitorProviderCacheInvalidationTest extends AbstractLeaderboard
flexibleLeaderboard.addRaceColumn("R1", /* medalRace */ false);
RaceLog raceLog = flexibleLeaderboard.getRacelog("R1", LeaderboardNameConstants.DEFAULT_FLEET_NAME);
final int passId = 1;
final LogEventAuthorImpl author = new LogEventAuthorImpl("Me", 0);
final LogEventAuthorImpl author = new LogEventAuthorImpl("Me", 0);
raceLog.add(new RaceLogUseCompetitorsFromRaceLogEventImpl(MillisecondsTimePoint.now(), author, MillisecondsTimePoint.now(), UUID.randomUUID(), passId));
final Map<Competitor, RaceLogRegisterCompetitorEvent> competitorOnRaceLogRegistrationEvents = new HashMap<>();
for (Competitor c : compLists[0]) {
final RaceLogRegisterCompetitorEvent registerCompetitorEvent = new RaceLogRegisterCompetitorEventImpl(MillisecondsTimePoint.now(), author, passId, c);
@@ -164,26 +166,45 @@ public class CompetitorProviderCacheInvalidationTest extends AbstractLeaderboard
}
@Test
public void testSimpleCompetitorListOnOneRaceLogAndRegattaLogInFlexibleLeaderboard() {
public void testSimpleCompetitorListOnOneRaceLogAndRegattaLogInFlexibleLeaderboard() throws NotRevokableException {
flexibleLeaderboard.addRaceColumn("R1", /* medalRace */ false);
RegattaLog regattaLog = flexibleLeaderboard.getRegattaLog();
for (Competitor c : compLists[0]) {
regattaLog.add(new RegattaLogRegisterCompetitorEventImpl(MillisecondsTimePoint.now(), MillisecondsTimePoint.now(), new LogEventAuthorImpl("Me", 0), UUID.randomUUID(), c));
}
RaceLog raceLog = flexibleLeaderboard.getRacelog("R1", LeaderboardNameConstants.DEFAULT_FLEET_NAME);
for (Competitor c : compLists[1]) {
raceLog.add(new RaceLogRegisterCompetitorEventImpl(MillisecondsTimePoint.now(), new LogEventAuthorImpl("Me", 0), 1, c));
final LogEventAuthorImpl author = new LogEventAuthorImpl("Me", 0);
int passId = 1;
final RaceLogUseCompetitorsFromRaceLogEventImpl usesCompetitorsFromRaceLogEvent = new RaceLogUseCompetitorsFromRaceLogEventImpl(MillisecondsTimePoint.now(), author, MillisecondsTimePoint.now(), UUID.randomUUID(), passId);
raceLog.add(usesCompetitorsFromRaceLogEvent);
for (Competitor c : compLists[1]) {
raceLog.add(new RaceLogRegisterCompetitorEventImpl(MillisecondsTimePoint.now(), new LogEventAuthorImpl("Me", 0), 1, c));
}
Set<Competitor> expected = new HashSet<>(compLists[0]);
expected.addAll(compLists[1]);
//expected are only the competitors in the RaceLog, because only one RaceColumn is
//registered, which has the competitors registered in the RaceLog.
assertRegattaAndRaceCompetitors(new HashSet<>(compLists[1]));
// Now we revoke that the race log provides the competitors for R1; the competitors should then
// snap back to those competitors taken from the regatta log for both, the rentire leaderboard
// as well as for the race column
raceLog.revokeEvent(author, usesCompetitorsFromRaceLogEvent);
assertRegattaAndRaceCompetitors(new HashSet<>(compLists[0]));
// And now re-introduce per-race competitors and validate again that the cache adjusts properly:
raceLog.add(new RaceLogUseCompetitorsFromRaceLogEventImpl(MillisecondsTimePoint.now(), author, MillisecondsTimePoint.now(), UUID.randomUUID(), passId));
assertRegattaAndRaceCompetitors(new HashSet<>(compLists[1]));
}
private void assertRegattaAndRaceCompetitors(Set<Competitor> expected) {
Set<Competitor> actual = new HashSet<>();
Util.addAll(competitorProviderFlexibleLeaderboard.getAllCompetitors(), actual);
assertEquals(expected, actual);
Set<Competitor> actualForRace = new HashSet<>();
//For the race only the competitors registered on RaceLog as RaceLogUseCompetitorsFromRaceLogEvent is present
Set<Competitor> expectedForRace = new HashSet<>(expected);
Util.addAll(competitorProviderFlexibleLeaderboard.getAllCompetitors(
flexibleLeaderboard.getRaceColumnByName("R1"),
flexibleLeaderboard.getFleet(LeaderboardNameConstants.DEFAULT_FLEET_NAME)), actualForRace);
assertEquals(expected, actualForRace);
assertEquals(expectedForRace, actualForRace);
}
@Test
@@ -251,6 +272,9 @@ public class CompetitorProviderCacheInvalidationTest extends AbstractLeaderboard
@Test
public void testSimpleCompetitorListOnOneRaceLogInRegattaLeaderboard() {
RaceLog raceLog = regattaLeaderboard.getRacelog("R1", "Yellow");
final LogEventAuthorImpl author = new LogEventAuthorImpl("Me", 0);
int passId = 1;
raceLog.add(new RaceLogUseCompetitorsFromRaceLogEventImpl(MillisecondsTimePoint.now(), author, MillisecondsTimePoint.now(), UUID.randomUUID(), passId));
for (Competitor c : compLists[0]) {
raceLog.add(new RaceLogRegisterCompetitorEventImpl(MillisecondsTimePoint.now(), new LogEventAuthorImpl("Me", 0), 1, c));
}
@@ -307,6 +331,7 @@ public class CompetitorProviderCacheInvalidationTest extends AbstractLeaderboard
}
final RaceLog raceLog = regattaLeaderboard.getRacelog("R1", "Yellow");
final int passId = 1;
raceLog.add(new RaceLogUseCompetitorsFromRaceLogEventImpl(MillisecondsTimePoint.now(), author, MillisecondsTimePoint.now(), UUID.randomUUID(), passId));
final Map<Competitor, RaceLogRegisterCompetitorEvent> competitorOnRaceLogRegistrationEvents = new HashMap<>();
for (Competitor c : compLists[passId]) {
final RaceLogRegisterCompetitorEvent registerCompetitorEvent = new RaceLogRegisterCompetitorEventImpl(MillisecondsTimePoint.now(), author, passId, c);
@@ -325,14 +350,15 @@ public class CompetitorProviderCacheInvalidationTest extends AbstractLeaderboard
Util.addAll(regattaLeaderboard.getCompetitors(), actualWithoutSuppressed);
assertEquals(expectedWithoutSuppressed, actualWithoutSuppressed);
Set<Competitor> actualForRaceYellow = new HashSet<>();
Set<Competitor> expectedFoRaceYellow = new HashSet<>(compLists[passId]);
Util.addAll(competitorProviderRegattaLeaderboard.getAllCompetitors(
regattaLeaderboard.getRaceColumnByName("R1"), regattaLeaderboard.getFleet("Yellow")), actualForRaceYellow);
assertEquals(expected, actualForRaceYellow);
assertEquals(expectedFoRaceYellow, actualForRaceYellow);
actualForRaceYellow = new HashSet<>(); // try another time; cache should of course yield an equal result (although
// we're not asserting here that the result actually comes from the cache)
Util.addAll(competitorProviderRegattaLeaderboard.getAllCompetitors(
regattaLeaderboard.getRaceColumnByName("R1"), regattaLeaderboard.getFleet("Yellow")), actualForRaceYellow);
assertEquals(expected, actualForRaceYellow);
assertEquals(expectedFoRaceYellow, actualForRaceYellow);
// But now it gets interesting: we're revoking a competitor registration on the race log and assert
// that the competitor is gone from the list:
final Competitor competitorToRevokeFromRaceLog = compLists[passId].get(2);
@@ -341,9 +367,9 @@ public class CompetitorProviderCacheInvalidationTest extends AbstractLeaderboard
// we're not asserting here that the result actually comes from the cache)
Util.addAll(competitorProviderRegattaLeaderboard.getAllCompetitors(
regattaLeaderboard.getRaceColumnByName("R1"), regattaLeaderboard.getFleet("Yellow")), actualForRaceYellow);
expected.remove(competitorToRevokeFromRaceLog);
assertEquals(expected.size(), actualForRaceYellow.size());
assertEquals(expected, actualForRaceYellow);
expectedFoRaceYellow.remove(competitorToRevokeFromRaceLog);
assertEquals(expectedFoRaceYellow.size(), actualForRaceYellow.size());
assertEquals(expectedFoRaceYellow, actualForRaceYellow);
}
}
@@ -0,0 +1,160 @@
package com.sap.sailing.domain.test;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertSame;
import static org.junit.Assert.assertTrue;
import java.io.File;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import java.text.ParseException;
import java.util.ArrayList;
import java.util.List;
import java.util.NavigableSet;
import java.util.UUID;
import org.junit.Before;
import org.junit.Test;
import com.sap.sailing.domain.abstractlog.AbstractLogEventAuthor;
import com.sap.sailing.domain.abstractlog.impl.LogEventAuthorImpl;
import com.sap.sailing.domain.abstractlog.race.CompetitorResult;
import com.sap.sailing.domain.abstractlog.race.CompetitorResults;
import com.sap.sailing.domain.abstractlog.race.RaceLog;
import com.sap.sailing.domain.abstractlog.race.RaceLogFinishPositioningConfirmedEvent;
import com.sap.sailing.domain.abstractlog.race.impl.CompetitorResultImpl;
import com.sap.sailing.domain.abstractlog.race.impl.CompetitorResultsImpl;
import com.sap.sailing.domain.abstractlog.race.impl.RaceLogFinishPositioningConfirmedEventImpl;
import com.sap.sailing.domain.abstractlog.race.impl.RaceLogPassChangeEventImpl;
import com.sap.sailing.domain.base.Competitor;
import com.sap.sailing.domain.base.RaceColumn;
import com.sap.sailing.domain.base.impl.CourseAreaImpl;
import com.sap.sailing.domain.common.NoWindException;
import com.sap.sailing.domain.common.WindSourceType;
import com.sap.sailing.domain.common.impl.DegreeBearingImpl;
import com.sap.sailing.domain.common.impl.KnotSpeedWithBearingImpl;
import com.sap.sailing.domain.common.impl.WindImpl;
import com.sap.sailing.domain.common.impl.WindSourceImpl;
import com.sap.sailing.domain.leaderboard.FlexibleLeaderboard;
import com.sap.sailing.domain.leaderboard.impl.FlexibleLeaderboardImpl;
import com.sap.sailing.domain.leaderboard.impl.LowPoint;
import com.sap.sailing.domain.leaderboard.impl.ThresholdBasedResultDiscardingRuleImpl;
import com.sap.sailing.domain.tracking.MarkPassing;
import com.sap.sailing.domain.tractracadapter.ReceiverType;
import com.sap.sse.common.Duration;
import com.sap.sse.common.TimePoint;
import com.sap.sse.common.Util;
import com.sap.sse.common.Util.Pair;
import com.sap.sse.common.impl.MillisecondsTimePoint;
import com.tractrac.model.lib.api.event.CreateModelException;
import com.tractrac.subscription.lib.api.SubscriberInitializationException;
/**
* Tests the implementation for bug3420: when a {@link RaceLogFinishPositioningConfirmedEvent} is found in a race log
* that has a valid {@link CompetitorResult#getFinishingTime()} defined for a competitor, a wrapper mark passing is
* expected to be generated with that time point for the finish waypoint. When the event is invalidated, e.g., by
* detaching the race log or by starting a new pass or by sending a newer {@link RaceLogFinishPositioningConfirmedEvent}
* or one that has higher priority, the finish mark passings need to be updated accordingly. This can mean that entirely
* artificial mark passings need to be removed entirely; mark passings that only replaced an original mark passing by
* one with a modified finish time need to be reverted back to the original mark passing.
*
* @author Axel Uhl (D043530)
*
*/
public class MarkPassingUpdateFromRaceLogFinishPositioingListTest extends AbstractManeuverDetectionTestCase {
private FlexibleLeaderboard leaderboard;
private RaceLog raceLog;
private final AbstractLogEventAuthor author;
public MarkPassingUpdateFromRaceLogFinishPositioingListTest() throws MalformedURLException, URISyntaxException {
super();
author = new LogEventAuthorImpl("Me", 0);
}
@Override
protected String getExpectedEventName() {
return "ESS Qingdao 2014";
}
@Before
public void setUp() throws URISyntaxException, IOException, InterruptedException, ParseException, SubscriberInitializationException, CreateModelException {
super.setUp();
URI storedUri = new URI("file:///"+new File("resources/event_20140429_ESSQingdao-Race_4.mtb").getCanonicalPath().replace('\\', '/'));
super.setUp(
new URL("file:///" + new File("resources/event_20140429_ESSQingdao-Race_4.txt").getCanonicalPath()),
/* liveUri */null, /* storedUri */storedUri, new ReceiverType[] { ReceiverType.MARKPASSINGS,
ReceiverType.MARKPOSITIONS, ReceiverType.RACECOURSE, ReceiverType.RAWPOSITIONS });
getTrackedRace().recordWind(
new WindImpl(/* position */null, new MillisecondsTimePoint(dateFormat.parse("05/01/2014-09:02:00")),
new KnotSpeedWithBearingImpl(10, new DegreeBearingImpl(269))),
new WindSourceImpl(WindSourceType.WEB));
leaderboard = new FlexibleLeaderboardImpl("Test", new ThresholdBasedResultDiscardingRuleImpl(new int[0]), new LowPoint(), new CourseAreaImpl("Here", UUID.randomUUID()));
final RaceColumn raceColumn = leaderboard.addRace(getTrackedRace(), "R", /* medalRace */ false);
raceLog = raceColumn.getRaceLog(raceColumn.getFleets().iterator().next());
}
/**
* Tests the Race 4 for competitor "Alinghi" at a time where the maneuver detection test is likely to compute
* a penalty although between the jibe and the tack there is a mark passing
*/
@Test
public void testOriginalFinishMarkPassingTime() throws ParseException, NoWindException {
int passId = 0;
Competitor alinghi = getCompetitorByName("Alinghi");
final MarkPassing alinghiOriginalFinish = getTrackedRace().getMarkPassing(alinghi, getTrackedRace().getRace().getCourse().getLastWaypoint());
final TimePoint alinghiOriginalFinishingTime = alinghiOriginalFinish.getTimePoint();
assertNotNull(alinghiOriginalFinish.getTimePoint());
final TimePoint now = MillisecondsTimePoint.now();
final CompetitorResults alinghiFinishesNow = createCompetitorResults(new Util.Pair<>(alinghi, now));
raceLog.add(new RaceLogFinishPositioningConfirmedEventImpl(now, author, passId, alinghiFinishesNow));
final MarkPassing alinghiCorrectedFinishMarkPassing = getTrackedRace().getMarkPassing(alinghi, getTrackedRace().getRace().getCourse().getLastWaypoint());
assertEquals(now, alinghiCorrectedFinishMarkPassing.getTimePoint());
raceLog.add(new RaceLogPassChangeEventImpl(now.plus(Duration.ONE_SECOND), author, ++passId)); // this should invalidate the previously edited result
assertEquals(alinghiOriginalFinishingTime, getTrackedRace().getMarkPassing(alinghi, getTrackedRace().getRace().getCourse().getLastWaypoint()).getTimePoint());
List<MarkPassing> withoutLast = new ArrayList<>();
final NavigableSet<MarkPassing> alinghiOriginalMarkPassings = getTrackedRace().getMarkPassings(alinghi);
getTrackedRace().lockForRead(alinghiOriginalMarkPassings);
try {
withoutLast.addAll(alinghiOriginalMarkPassings);
} finally {
getTrackedRace().unlockAfterRead(alinghiOriginalMarkPassings);
}
withoutLast.remove(withoutLast.size()-1);
getTrackedRace().updateMarkPassings(alinghi, withoutLast);
assertNull(getTrackedRace().getMarkPassing(alinghi, getTrackedRace().getRace().getCourse().getLastWaypoint()));
raceLog.add(new RaceLogFinishPositioningConfirmedEventImpl(now, author, passId, alinghiFinishesNow));
final MarkPassing alinghiSyntheticFinish = getTrackedRace().getMarkPassing(alinghi, getTrackedRace().getRace().getCourse().getLastWaypoint());
assertEquals(now, alinghiSyntheticFinish.getTimePoint());
assertNull(alinghiSyntheticFinish.getOriginal());
// advancing to the next pass is expected to remove the synthetic mark passing again
raceLog.add(new RaceLogPassChangeEventImpl(now.plus(Duration.ONE_HOUR), author, ++passId));
assertNull(getTrackedRace().getMarkPassing(alinghi, getTrackedRace().getRace().getCourse().getLastWaypoint()));
raceLog.add(new RaceLogFinishPositioningConfirmedEventImpl(now, author, passId, alinghiFinishesNow));
final MarkPassing alinghiSyntheticFinish2 = getTrackedRace().getMarkPassing(alinghi, getTrackedRace().getRace().getCourse().getLastWaypoint());
assertEquals(now, alinghiSyntheticFinish2.getTimePoint());
assertNull(alinghiSyntheticFinish2.getOriginal());
List<MarkPassing> withLastAgain = new ArrayList<>(withoutLast);
withLastAgain.add(alinghiOriginalFinish);
getTrackedRace().updateMarkPassings(alinghi, withLastAgain);
final MarkPassing alinghiNoLongerSynthetic = getTrackedRace().getMarkPassing(alinghi, getTrackedRace().getRace().getCourse().getLastWaypoint());
assertSame(alinghiOriginalFinish, alinghiNoLongerSynthetic.getOriginal());
assertTrue(alinghiNoLongerSynthetic.getOriginal() != alinghiNoLongerSynthetic);
}
@SafeVarargs
private final CompetitorResults createCompetitorResults(Pair<Competitor, TimePoint>... finishingTimes) {
final CompetitorResults results = new CompetitorResultsImpl();
int rank = 1;
for (Pair<Competitor, TimePoint> finishingTime : finishingTimes) {
results.add(new CompetitorResultImpl(finishingTime.getA().getId(), finishingTime.getA().getName(), rank++, /* maxPointsReason */
null, /* score */null, finishingTime.getB(), /* comment */null));
}
return results;
}
}
@@ -487,6 +487,27 @@ public class MockedTrackedRace implements DynamicTrackedRace {
public Iterable<? extends RaceColumn> getRaceColumns() {
return null;
}
@Override
public Iterable<Competitor> getCompetitorsRegisteredInRegattaLog() {
return null;
}
@Override
public void registerCompetitor(Competitor competitor) {
}
@Override
public void registerCompetitors(Iterable<Competitor> competitor) {
}
@Override
public void deregisterCompetitor(Competitor competitor) {
}
@Override
public void deregisterCompetitors(Iterable<Competitor> competitor) {
}
};
}
@@ -905,10 +926,6 @@ public class MockedTrackedRace implements DynamicTrackedRace {
return null;
}
@Override
public void waitForLoadingFromGPSFixStoreToFinishRunning(RaceLog forRaceLog) throws InterruptedException {
}
@Override
public void addRaceAbortedListener(RaceAbortedListener listener) {
}
@@ -1008,4 +1025,8 @@ public class MockedTrackedRace implements DynamicTrackedRace {
public IsManagedByCache<SharedDomainFactory> resolve(SharedDomainFactory domainFactory) {
return this;
}
@Override
public void updateMarkPassingsAfterRaceLogChanges() {
}
}
@@ -554,10 +554,6 @@ public class MockedTrackedRaceWithStartTimeAndRanks implements TrackedRace {
return null;
}
@Override
public void waitForLoadingFromGPSFixStoreToFinishRunning(RaceLog forRaceLog) throws InterruptedException {
}
@Override
public void addRaceAbortedListener(RaceAbortedListener listener) {
}
@@ -3,6 +3,8 @@ package com.sap.sailing.domain.base;
import com.sap.sailing.domain.abstractlog.race.RaceLog;
import com.sap.sailing.domain.abstractlog.regatta.RegattaLog;
import com.sap.sailing.domain.common.RaceIdentifier;
import com.sap.sailing.domain.common.abstractlog.NotRevokableException;
import com.sap.sailing.domain.common.racelog.tracking.CompetitorRegistrationOnRaceLogDisabledException;
import com.sap.sailing.domain.leaderboard.Leaderboard;
import com.sap.sailing.domain.leaderboard.MetaLeaderboard;
import com.sap.sailing.domain.racelog.RaceLogIdentifier;
@@ -46,6 +48,15 @@ public interface RaceColumn extends Named {
*/
RaceLog getRaceLog(Fleet fleet);
/**
* Gets the regatta log associated with the regatta-like structure (either a regatta if this is a
* {@link RaceColumnInSeries} or a flexible leaderboard). Note that the result may be <code>null</code> particularly
* for columns in a {@link MetaLeaderboard}.
*
* @return the regatta log or <code>null</code> in case this column belongs to a {@link MetaLeaderboard}
*/
RegattaLog getRegattaLog();
/**
* @return the fleets for each of which this column has a single race and therefore optionally a {@link TrackedRace}, in
* ascending order; best fleets first
@@ -232,9 +243,9 @@ public interface RaceColumn extends Named {
/**
* Provides the combined set of competitors from all {@link #getTrackedRace(Fleet) tracked races attached to this
* column} or, in case a fleet does not have a tracked race attached, the competitors registered through the
* respective {@link RaceLog} {@link #getRaceLog(Fleet) attached to this column for that fleet}. Note that this does
* not include competitors registered through any {@link RegattaLog} on the structure owning (directly or
* transitively) this column.
* respective {@link RaceLog} {@link #getRaceLog(Fleet)} attached to this column for that fleet (if this is
* {@link #enableCompetitorRegistrationOnRaceLog(Fleet) enabled) or registered through the {@link #getRegattaLog()
* regatta log}.
*/
Iterable<Competitor> getAllCompetitors();
@@ -242,4 +253,96 @@ public interface RaceColumn extends Named {
* Same as {@link #getAllCompetitors()}, but restricted to the single race identified by the <code>fleet</code> parameter.
*/
Iterable<Competitor> getAllCompetitors(Fleet fleet);
/**
* Provides the combined set of marks from all {@link #getTrackedRace(Fleet) tracked races attached to this
* column} or, in case a fleet does not have a tracked race attached, the marks registered through the
* {@link #getRegattaLog() regatta log} for the regatta-like object to which this column belongs (flexible
* leaderboard or regatta).
*/
Iterable<Mark> getAllMarks();
/**
* Same as {@link #getAllMarks()}, but restricted to the single race identified by the <code>fleet</code> parameter.
*/
Iterable<Mark> getMarks(Fleet fleet);
/**
* Returns the competitor set registered in the race column's race log associated to the passed fleet. If competitor
* registration in RaceLog is {@link #disableCompetitorRegistrationOnRaceLog(Fleet) disabled} or in case of a
* MetaLeaderboardColumn an empty set is returned.
*
* @return competitors in RaceLog if registration {@link #enableCompetitorRegistrationOnRaceLog(Fleet) enabled} or
* empty set in case registration is {@link #disableCompetitorRegistrationOnRaceLog(Fleet) disabled} or this
* column belongs to a {@link MetaLeaderboard}
*/
Iterable<Competitor> getCompetitorsRegisteredInRacelog(Fleet fleet);
/**
* Checks whether competitor registration on RaceLog is enabled.
*
* @return boolean if competitor registration on the RaceLog is enabled, false in case this column belongs to a
* {@link MetaLeaderboard}
*
* @see #enableCompetitorRegistrationOnRaceLog(Fleet)
* @see #disableCompetitorRegistrationOnRaceLog(Fleet)
*/
boolean isCompetitorRegistrationInRacelogEnabled(Fleet fleet);
/**
* Activates competitor registration on the race column's race log associated to the passed fleet. As a result,
* competitor registrations that were added to the race log before this was disabled by
* {@link #disableCompetitorRegistrationOnRaceLog(Fleet)} will again be honored.<p>
*
* Performs nothing in case this column belongs to a {@link MetaLeaderboard}.
*/
void enableCompetitorRegistrationOnRaceLog(Fleet fleet);
/**
* Disables competitor registration on the race column's race log associated to the passed fleet. Performs nothing
* in case this column belongs to a {@link MetaLeaderboard}. If there are already competitor registrations on the
* race log, those will not be removed from the log but they will be ignored, and the regatta log's competitor
* registrations will be used instead. Re-{@link #enableCompetitorRegistrationOnRaceLog(Fleet) enabling} competitor
* registrations in the race log will cause such existing registrations to be honored again.
* <p>
*
* Performs nothing in case this column belongs to a {@link MetaLeaderboard}.
*/
void disableCompetitorRegistrationOnRaceLog(Fleet fleet) throws NotRevokableException;
/**
* Registers a competitor on the the race column's race log associated to the passed fleet.
*
* @throws CompetitorRegistrationOnRaceLogDisabledException
* thrown if competitor registration is {@link #disableCompetitorRegistrationOnRaceLog(Fleet) disabled}
* on racelog as well as if RaceColumn belongs to a {@link MetaLeaderboard}
*/
void registerCompetitor(Competitor competitor, Fleet fleet) throws CompetitorRegistrationOnRaceLogDisabledException;
/**
* Registers competitors on the the race column's race log associated to the passed fleet.
*
* @throws CompetitorRegistrationOnRaceLogDisabledException
* thrown if competitor registration is disabled on racelog as well as if RaceColumn belongs to a
* {@link MetaLeaderboard}
*/
void registerCompetitors(Iterable<Competitor> competitor, Fleet fleet) throws CompetitorRegistrationOnRaceLogDisabledException;
/**
* Deregisters a competitor on the the race column's race log associated to the passed fleet.
*
* @throws CompetitorRegistrationOnRaceLogDisabledException
* thrown if competitor registration is disabled on racelog as well as if RaceColumn belongs to a
* {@link MetaLeaderboard}
*/
void deregisterCompetitor(Competitor competitors, Fleet fleet) throws CompetitorRegistrationOnRaceLogDisabledException;
/**
* Deregisters competitors on the the race column's race log associated to the passed fleet.
*
* @throws CompetitorRegistrationOnRaceLogDisabledException
* thrown if competitor registration is disabled on racelog as well as if RaceColumn belongs to a
* {@link MetaLeaderboard}
*/
void deregisterCompetitors(Iterable<Competitor> currentlyRegisteredCompetitors, Fleet fleet) throws CompetitorRegistrationOnRaceLogDisabledException;
}
@@ -2,36 +2,61 @@ package com.sap.sailing.domain.base.impl;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.UUID;
import java.util.logging.Level;
import java.util.logging.Logger;
import com.sap.sailing.domain.abstractlog.AbstractLogEventAuthor;
import com.sap.sailing.domain.abstractlog.impl.AllEventsOfTypeFinder;
import com.sap.sailing.domain.abstractlog.impl.LogEventAuthorImpl;
import com.sap.sailing.domain.abstractlog.race.RaceLog;
import com.sap.sailing.domain.abstractlog.shared.analyzing.RegisteredCompetitorsAnalyzer;
import com.sap.sailing.domain.abstractlog.race.RaceLogEvent;
import com.sap.sailing.domain.abstractlog.race.analyzing.impl.LastPublishedCourseDesignFinder;
import com.sap.sailing.domain.abstractlog.race.tracking.RaceLogUseCompetitorsFromRaceLogEvent;
import com.sap.sailing.domain.abstractlog.race.tracking.analyzing.impl.RegisteredCompetitorsAnalyzer;
import com.sap.sailing.domain.abstractlog.race.tracking.impl.RaceLogRegisterCompetitorEventImpl;
import com.sap.sailing.domain.abstractlog.race.tracking.impl.RaceLogUseCompetitorsFromRaceLogEventImpl;
import com.sap.sailing.domain.abstractlog.regatta.RegattaLog;
import com.sap.sailing.domain.abstractlog.regatta.tracking.analyzing.impl.RegattaLogDefinedMarkAnalyzer;
import com.sap.sailing.domain.abstractlog.shared.events.RegisterCompetitorEvent;
import com.sap.sailing.domain.base.Competitor;
import com.sap.sailing.domain.base.CourseBase;
import com.sap.sailing.domain.base.Fleet;
import com.sap.sailing.domain.base.Mark;
import com.sap.sailing.domain.base.RaceColumn;
import com.sap.sailing.domain.base.Waypoint;
import com.sap.sailing.domain.common.RaceIdentifier;
import com.sap.sailing.domain.common.abstractlog.NotRevokableException;
import com.sap.sailing.domain.common.racelog.tracking.CompetitorRegistrationOnRaceLogDisabledException;
import com.sap.sailing.domain.racelog.RaceLogIdentifier;
import com.sap.sailing.domain.racelog.RaceLogStore;
import com.sap.sailing.domain.racelog.impl.RaceLogIdentifierImpl;
import com.sap.sailing.domain.regattalike.RegattaLikeIdentifier;
import com.sap.sailing.domain.tracking.TrackedRace;
import com.sap.sse.common.TimePoint;
import com.sap.sse.common.Util;
import com.sap.sse.common.impl.MillisecondsTimePoint;
public abstract class AbstractRaceColumn extends SimpleAbstractRaceColumn implements RaceColumn {
private static final long serialVersionUID = -7801617988982540470L;
private static final Logger logger = Logger.getLogger(AbstractRaceColumn.class.getName());
private final AbstractLogEventAuthor raceLogEventAuthorForRaceColumn = new LogEventAuthorImpl(
AbstractRaceColumn.class.getName(), 0);
private TrackedRaces trackedRaces;
private Map<Fleet, RaceIdentifier> raceIdentifiers;
private Map<Fleet, RaceLog> raceLogs;
private transient RaceLogStore raceLogStore;
private RegattaLikeIdentifier regattaLikeParent;
@@ -46,7 +71,7 @@ public abstract class AbstractRaceColumn extends SimpleAbstractRaceColumn implem
this.raceLogStore = raceLogStore;
this.regattaLikeParent = regattaLikeParent;
for (final Fleet fleet : getFleets()) {
reloadRaceLog(fleet);
reloadRaceLog(fleet);
}
}
@@ -56,7 +81,7 @@ public abstract class AbstractRaceColumn extends SimpleAbstractRaceColumn implem
return raceLogs.get(fleet);
}
}
@Override
public RaceLogIdentifier getRaceLogIdentifier(Fleet fleet) {
return new RaceLogIdentifierImpl(regattaLikeParent, getName(), fleet);
@@ -114,13 +139,13 @@ public abstract class AbstractRaceColumn extends SimpleAbstractRaceColumn implem
getRaceColumnListeners().notifyListenersAboutTrackedRaceUnlinked(this, fleet, previouslyLinkedRace);
}
}
@Override
public void removeRaceIdentifier(Fleet fleet) {
releaseTrackedRace(fleet);
this.raceIdentifiers.remove(fleet);
}
@Override
public Fleet getFleetOfCompetitor(Competitor competitor) {
for (final Fleet fleet : getFleets()) {
@@ -155,7 +180,7 @@ public abstract class AbstractRaceColumn extends SimpleAbstractRaceColumn implem
}
return null;
}
@Override
public String toString() {
return getName();
@@ -163,9 +188,9 @@ public abstract class AbstractRaceColumn extends SimpleAbstractRaceColumn implem
@Override
public void reloadRaceLog(Fleet fleet) {
synchronized(raceLogs) {
synchronized (raceLogs) {
RaceLogIdentifier identifier = getRaceLogIdentifier(fleet);
RaceLog newOrLoadedRaceLog = raceLogStore.getRaceLog(identifier, /*ignoreCache*/ true);
RaceLog newOrLoadedRaceLog = raceLogStore.getRaceLog(identifier, /* ignoreCache */true);
RaceLog raceLogAvailable = raceLogs.get(fleet);
if (raceLogAvailable == null) {
RaceColumnRaceLogReplicator listener = new RaceColumnRaceLogReplicator(this, identifier);
@@ -205,7 +230,7 @@ public abstract class AbstractRaceColumn extends SimpleAbstractRaceColumn implem
if (trackedRace != null) {
trackedRace.attachRaceLog(raceLog);
}
}, /* prio */ 0);
}, /* prio */0);
// because this will add the race log to the tracked race's attachedRaceLogs collection again, and
// the new DynamicTrackedRaceLogListener that the readObject(...) method had constructed for the
// tracked race will be added as a listener to the race log whose listeners collection otherwise would
@@ -218,22 +243,11 @@ public abstract class AbstractRaceColumn extends SimpleAbstractRaceColumn implem
trackedRaces.setMasterDataExportOngoingThreadFlag(flagValue);
}
@Override
public Iterable<Competitor> getAllCompetitors() {
final Set<Competitor> result = new HashSet<>();
Set<Competitor> result = new HashSet<>();
for (Fleet fleet : getFleets()) {
TrackedRace trackedRace = getTrackedRace(fleet);
if (trackedRace != null) {
Util.addAll(trackedRace.getRace().getCompetitors(), result);
} else {
// if no tracked race is found, use competitors from race log; this assumes that if a tracked
// race exists, its competitors set takes precedence over what's in the race log. Usually,
// the tracked race will have the same competitors as those in the race log, or more because
// those from the regatta log are added to the tracked race as well.
Set<Competitor> viaRaceLog = new RegisteredCompetitorsAnalyzer<>(getRaceLog(fleet)).analyze();
result.addAll(viaRaceLog);
}
Util.addAll(getAllCompetitors(fleet), result);
}
return result;
}
@@ -241,17 +255,139 @@ public abstract class AbstractRaceColumn extends SimpleAbstractRaceColumn implem
@Override
public Iterable<Competitor> getAllCompetitors(final Fleet fleet) {
final Iterable<Competitor> result;
final TrackedRace trackedRace = getTrackedRace(fleet);
TrackedRace trackedRace = getTrackedRace(fleet);
if (trackedRace != null) {
result = trackedRace.getRace().getCompetitors();
} else {
// if no tracked race is found, use competitors from race log; this assumes that if a tracked
// if no tracked race is found, use competitors from race/regatta log depending on whether
// the mapping event is present or not; this assumes that if a tracked
// race exists, its competitors set takes precedence over what's in the race log. Usually,
// the tracked race will have the same competitors as those in the race log, or more because
// those from the regatta log are added to the tracked race as well.
Set<Competitor> viaRaceLog = new RegisteredCompetitorsAnalyzer<>(getRaceLog(fleet)).analyze();
Set<Competitor> viaRaceLog = new RegisteredCompetitorsAnalyzer(getRaceLog(fleet), getRegattaLog()).analyze();
result = viaRaceLog;
}
return result;
}
}
@Override
public void registerCompetitor(Competitor competitor, Fleet fleet) throws CompetitorRegistrationOnRaceLogDisabledException {
registerCompetitors(Collections.singleton(competitor), fleet);
}
@Override
public void registerCompetitors(Iterable<Competitor> competitors, Fleet fleet)
throws CompetitorRegistrationOnRaceLogDisabledException {
if (!isCompetitorRegistrationInRacelogEnabled(fleet)) {
throw new CompetitorRegistrationOnRaceLogDisabledException("Competitor registration not allowed for fleet "+fleet+" in column "+this);
}
TimePoint now = MillisecondsTimePoint.now();
RaceLog raceLog = getRaceLog(fleet);
int passId = raceLog.getCurrentPassId();
for (Competitor competitor : competitors) {
raceLog.add(new RaceLogRegisterCompetitorEventImpl(now, now, raceLogEventAuthorForRaceColumn,
UUID.randomUUID(), passId, competitor));
}
}
@Override
public void deregisterCompetitor(Competitor competitor, Fleet fleet)
throws CompetitorRegistrationOnRaceLogDisabledException {
deregisterCompetitors(Collections.singleton(competitor), fleet);
}
@Override
public void deregisterCompetitors(Iterable<Competitor> competitors, Fleet fleet)
throws CompetitorRegistrationOnRaceLogDisabledException {
if (!isCompetitorRegistrationInRacelogEnabled(fleet)) {
throw new CompetitorRegistrationOnRaceLogDisabledException("Competitor registration not allowed for fleet "+fleet+" in column "+this);
}
HashSet<Competitor> competitorSet = new HashSet<Competitor>();
Util.addAll(competitors, competitorSet);
RaceLog raceLog = getRaceLog(fleet);
for (RaceLogEvent event : raceLog.getUnrevokedEventsDescending()) {
if (event instanceof RegisterCompetitorEvent) {
RegisterCompetitorEvent<?> registerEvent = (RegisterCompetitorEvent<?>) event;
if (competitorSet.contains(registerEvent.getCompetitor())) {
try {
raceLog.revokeEvent(raceLogEventAuthorForRaceColumn, event,
"unregistering competitor because no longer selected for registration");
} catch (NotRevokableException e) {
logger.log(Level.WARNING, "could not unregister competitor by adding RevokeEvent", e);
}
}
}
}
}
@Override
public Iterable<Mark> getAllMarks() {
final Set<Mark> result = new HashSet<>();
// if the marks from the regatta log are to be used because a slot has no TrackedRace attached,
// those regatta log marks only need to be added to the result once
boolean regattaLogMarksAlreadyAdded = false;
for (Fleet fleet : getFleets()) {
TrackedRace trackedRace = getTrackedRace(fleet);
if (trackedRace != null) {
for (Waypoint waypoint : trackedRace.getRace().getCourse().getWaypoints()) {
Util.addAll(waypoint.getMarks(), result);
}
} else if (!regattaLogMarksAlreadyAdded) {
// if no tracked race is found, use marks from regatta log
RegattaLog regattaLog = getRegattaLog();
Collection<Mark> viaRegattaLog = new RegattaLogDefinedMarkAnalyzer(regattaLog).analyze();
result.addAll(viaRegattaLog);
regattaLogMarksAlreadyAdded = true;
}
}
return result;
}
@Override
public Iterable<Mark> getMarks(Fleet fleet) {
final Set<Mark> result = new HashSet<>();
final TrackedRace trackedRace = getTrackedRace(fleet);
if (trackedRace != null) {
for (Waypoint waypoint : trackedRace.getRace().getCourse().getWaypoints()) {
Util.addAll(waypoint.getMarks(), result);
}
} else {
// if no tracked race is found, use marks from race course if present in racelog
// if not the marks defined in the regatta log
LastPublishedCourseDesignFinder courseDesginFinder = new LastPublishedCourseDesignFinder(getRaceLog(fleet));
final CourseBase courseBase = courseDesginFinder.analyze();
if (courseBase != null) {
// TODO why do we collect the marks from the course definition here but not in getAllMarks()?
courseBase.getWaypoints().forEach((waypoint) -> Util.addAll(waypoint.getMarks(), result));
} else {
Util.addAll(new RegattaLogDefinedMarkAnalyzer(getRegattaLog()).analyze(), result);
}
}
return result;
}
@Override
public void enableCompetitorRegistrationOnRaceLog(Fleet fleet) {
TimePoint now = MillisecondsTimePoint.now();
RaceLog raceLog = getRaceLog(fleet);
int passId = raceLog.getCurrentPassId();
raceLog.add(new RaceLogUseCompetitorsFromRaceLogEventImpl(now, raceLogEventAuthorForRaceColumn, now, UUID.randomUUID(), passId));
}
@Override
public void disableCompetitorRegistrationOnRaceLog(Fleet fleet) throws NotRevokableException {
RaceLog raceLog = getRaceLog(fleet);
List<RaceLogEvent> events = new AllEventsOfTypeFinder<>(raceLog, true, RaceLogUseCompetitorsFromRaceLogEvent.class).analyze();
for (RaceLogEvent event : events) {
raceLog.lockForRead();
try {
event = raceLog.getEventById(event.getId());
} finally {
raceLog.unlockAfterRead();
}
if (event != null) {
raceLog.revokeEvent(raceLogEventAuthorForRaceColumn, event, "revoke triggered by GWT user action");
}
}
}
}
@@ -3,6 +3,7 @@ package com.sap.sailing.domain.base.impl;
import java.util.Iterator;
import com.sap.sailing.domain.abstractlog.regatta.RegattaLog;
import com.sap.sailing.domain.base.Fleet;
import com.sap.sailing.domain.base.RaceColumnInSeries;
import com.sap.sailing.domain.base.RaceDefinition;
@@ -14,7 +15,7 @@ import com.sap.sailing.domain.tracking.TrackedRegatta;
import com.sap.sailing.domain.tracking.TrackedRegattaRegistry;
/**
* Obtains flees and medal information from the {@link Series} to which it is connected at construction time.
* Obtains fleets and medal information from the {@link Series} to which it is connected at construction time.
*
* @author Axel Uhl (D043530)
*
@@ -131,4 +132,10 @@ public class RaceColumnInSeriesImpl extends AbstractRaceColumn implements RaceCo
}
return result;
}
@Override
public RegattaLog getRegattaLog() {
Regatta regatta = getRegatta();
return regatta.getRegattaLog();
}
}
@@ -2,15 +2,15 @@ package com.sap.sailing.domain.base.impl;
import java.io.Serializable;
import com.sap.sailing.domain.abstractlog.race.RaceLogEndOfTrackingEvent;
import com.sap.sailing.domain.abstractlog.race.RaceLogFixedMarkPassingEvent;
import com.sap.sailing.domain.abstractlog.race.RaceLogCourseAreaChangedEvent;
import com.sap.sailing.domain.abstractlog.race.RaceLogCourseDesignChangedEvent;
import com.sap.sailing.domain.abstractlog.race.RaceLogDependentStartTimeEvent;
import com.sap.sailing.domain.abstractlog.race.RaceLogEndOfTrackingEvent;
import com.sap.sailing.domain.abstractlog.race.RaceLogEvent;
import com.sap.sailing.domain.abstractlog.race.RaceLogEventVisitor;
import com.sap.sailing.domain.abstractlog.race.RaceLogFinishPositioningConfirmedEvent;
import com.sap.sailing.domain.abstractlog.race.RaceLogFinishPositioningListChangedEvent;
import com.sap.sailing.domain.abstractlog.race.RaceLogFixedMarkPassingEvent;
import com.sap.sailing.domain.abstractlog.race.RaceLogFlagEvent;
import com.sap.sailing.domain.abstractlog.race.RaceLogGateLineOpeningTimeEvent;
import com.sap.sailing.domain.abstractlog.race.RaceLogPassChangeEvent;
@@ -21,16 +21,13 @@ import com.sap.sailing.domain.abstractlog.race.RaceLogRevokeEvent;
import com.sap.sailing.domain.abstractlog.race.RaceLogStartOfTrackingEvent;
import com.sap.sailing.domain.abstractlog.race.RaceLogStartProcedureChangedEvent;
import com.sap.sailing.domain.abstractlog.race.RaceLogStartTimeEvent;
import com.sap.sailing.domain.abstractlog.race.RaceLogWindFixEvent;
import com.sap.sailing.domain.abstractlog.race.RaceLogSuppressedMarkPassingsEvent;
import com.sap.sailing.domain.abstractlog.race.RaceLogWindFixEvent;
import com.sap.sailing.domain.abstractlog.race.scoring.RaceLogAdditionalScoringInformationEvent;
import com.sap.sailing.domain.abstractlog.race.tracking.RaceLogCloseOpenEndedDeviceMappingEvent;
import com.sap.sailing.domain.abstractlog.race.tracking.RaceLogDefineMarkEvent;
import com.sap.sailing.domain.abstractlog.race.tracking.RaceLogDenoteForTrackingEvent;
import com.sap.sailing.domain.abstractlog.race.tracking.RaceLogDeviceCompetitorMappingEvent;
import com.sap.sailing.domain.abstractlog.race.tracking.RaceLogDeviceMarkMappingEvent;
import com.sap.sailing.domain.abstractlog.race.tracking.RaceLogRegisterCompetitorEvent;
import com.sap.sailing.domain.abstractlog.race.tracking.RaceLogStartTrackingEvent;
import com.sap.sailing.domain.abstractlog.race.tracking.RaceLogUseCompetitorsFromRaceLogEvent;
import com.sap.sailing.domain.base.RaceColumn;
import com.sap.sailing.domain.racelog.RaceLogIdentifier;
@@ -117,16 +114,6 @@ public class RaceColumnRaceLogReplicator implements RaceLogEventVisitor, Seriali
notifyOnAdd(event);
}
@Override
public void visit(RaceLogDeviceCompetitorMappingEvent event) {
notifyOnAdd(event);
}
@Override
public void visit(RaceLogDeviceMarkMappingEvent event) {
notifyOnAdd(event);
}
@Override
public void visit(RaceLogDenoteForTrackingEvent event) {
notifyOnAdd(event);
@@ -146,16 +133,6 @@ public class RaceColumnRaceLogReplicator implements RaceLogEventVisitor, Seriali
public void visit(RaceLogRegisterCompetitorEvent event) {
notifyOnAdd(event);
}
@Override
public void visit(RaceLogDefineMarkEvent event) {
notifyOnAdd(event);
}
@Override
public void visit(RaceLogCloseOpenEndedDeviceMappingEvent event) {
notifyOnAdd(event);
}
@Override
public void visit(RaceLogFixedMarkPassingEvent event) {
@@ -186,4 +163,9 @@ public class RaceColumnRaceLogReplicator implements RaceLogEventVisitor, Seriali
public void visit(RaceLogEndOfTrackingEvent event) {
notifyOnAdd(event);
}
@Override
public void visit(RaceLogUseCompetitorsFromRaceLogEvent event) {
notifyOnAdd(event);
}
}
@@ -12,13 +12,21 @@ import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;
import java.util.logging.Level;
import java.util.logging.Logger;
import com.sap.sailing.domain.abstractlog.AbstractLogEventAuthor;
import com.sap.sailing.domain.abstractlog.impl.LogEventAuthorImpl;
import com.sap.sailing.domain.abstractlog.race.RaceLog;
import com.sap.sailing.domain.abstractlog.race.RaceLogEvent;
import com.sap.sailing.domain.abstractlog.regatta.RegattaLog;
import com.sap.sailing.domain.abstractlog.regatta.RegattaLogEvent;
import com.sap.sailing.domain.abstractlog.regatta.RegattaLogEventVisitor;
import com.sap.sailing.domain.abstractlog.regatta.events.impl.RegattaLogRegisterCompetitorEventImpl;
import com.sap.sailing.domain.abstractlog.shared.analyzing.CompetitorDeregistrator;
import com.sap.sailing.domain.abstractlog.shared.analyzing.CompetitorsInLogAnalyzer;
import com.sap.sailing.domain.base.BoatClass;
import com.sap.sailing.domain.base.Competitor;
import com.sap.sailing.domain.base.CourseArea;
@@ -40,7 +48,9 @@ import com.sap.sailing.domain.common.RegattaName;
import com.sap.sailing.domain.common.RegattaNameAndRaceName;
import com.sap.sailing.domain.leaderboard.ResultDiscardingRule;
import com.sap.sailing.domain.leaderboard.ScoringScheme;
import com.sap.sailing.domain.leaderboard.impl.AbstractLeaderboardImpl;
import com.sap.sailing.domain.leaderboard.impl.CompetitorProviderFromRaceColumnsAndRegattaLike;
import com.sap.sailing.domain.leaderboard.impl.FlexibleLeaderboardImpl;
import com.sap.sailing.domain.racelog.RaceLogIdentifier;
import com.sap.sailing.domain.racelog.RaceLogStore;
import com.sap.sailing.domain.racelog.impl.EmptyRaceLogStore;
@@ -61,8 +71,18 @@ import com.sap.sailing.util.impl.RaceColumnListeners;
import com.sap.sse.common.Duration;
import com.sap.sse.common.TimePoint;
import com.sap.sse.common.Util;
import com.sap.sse.common.impl.MillisecondsTimePoint;
import com.sap.sse.common.impl.NamedImpl;
/**
* A regatta with series with race columns and fleets, a scoring scheme and various other data, many of which are relevant
* for scoring. A regatta has a single boat class. It implements the {@link IsRegattaLike} interface and for this uses a
* delegate pattern with the {@link BaseRegattaLikeImpl} which it shares with {@link FlexibleLeaderboardImpl}. That
* delegate provides the {@link RegattaLog} for this regatta.
*
* @author Axel Uhl (D043530)
*
*/
public class RegattaImpl extends NamedImpl implements Regatta, RaceColumnListener {
/**
@@ -93,48 +113,44 @@ public class RegattaImpl extends NamedImpl implements Regatta, RaceColumnListene
private transient RaceLogStore raceLogStore;
private final IsRegattaLike regattaLikeHelper;
private final RankingMetricConstructor rankingMetricConstructor;
private CourseArea defaultCourseArea;
private RegattaConfiguration configuration;
private RaceExecutionOrderCache raceExecutionOrderCache;
/**
* Regattas may be constructed as implicit default regattas in which case they won't need to be stored
* durably and don't contain valuable information worth being preserved; or they are constructed explicitly
* with series and race columns in which case this data needs to be protected. This flag indicates whether
* the data of this regatta needs to be maintained persistently.
* Regattas may be constructed as implicit default regattas in which case they won't need to be stored durably and
* don't contain valuable information worth being preserved; or they are constructed explicitly with series and race
* columns in which case this data needs to be protected. This flag indicates whether the data of this regatta needs
* to be maintained persistently.
*
* @see #isPersistent
*/
private final boolean persistent;
/**
* Defaults to <code>true</code>. See {@link Regatta#useStartTimeInference()}.
*/
private boolean useStartTimeInference;
private transient CompetitorProviderFromRaceColumnsAndRegattaLike competitorsProvider;
private AbstractLogEventAuthor regattaLogEventAuthorForRegatta = new LogEventAuthorImpl(
AbstractLeaderboardImpl.class.getName(), 0);;
/**
* Constructs a regatta with an empty {@link RaceLogStore}.
*/
public RegattaImpl(String name, BoatClass boatClass, TimePoint startDate, TimePoint endDate, Iterable<? extends Series> series, boolean persistent,
ScoringScheme scoringScheme, Serializable id, CourseArea courseArea) {
this(name, boatClass, startDate, endDate, series, persistent, scoringScheme, id, courseArea, OneDesignRankingMetric::new);
public RegattaImpl(String name, BoatClass boatClass, TimePoint startDate, TimePoint endDate,
Iterable<? extends Series> series, boolean persistent, ScoringScheme scoringScheme, Serializable id,
CourseArea courseArea, RankingMetricConstructor rankingMetricConstructor) {
this(EmptyRaceLogStore.INSTANCE, EmptyRegattaLogStore.INSTANCE, name, boatClass, startDate, endDate, series,
persistent, scoringScheme, id, courseArea, /* useStartTimeInference */true, rankingMetricConstructor);
}
/**
* Constructs a regatta with an empty {@link RaceLogStore}.
*/
public RegattaImpl(String name, BoatClass boatClass, TimePoint startDate, TimePoint endDate, Iterable<? extends Series> series, boolean persistent,
ScoringScheme scoringScheme, Serializable id, CourseArea courseArea, RankingMetricConstructor rankingMetricConstructor) {
this(EmptyRaceLogStore.INSTANCE, EmptyRegattaLogStore.INSTANCE, name, boatClass, startDate, endDate, series, persistent,
scoringScheme, id, courseArea, /* useStartTimeInference */ true, rankingMetricConstructor);
}
/**
* Constructs a regatta with a single default series with empty race column list, and a single default fleet which
* is not {@link #isPersistent() marked for persistence}.
*
* @param trackedRegattaRegistry
* used to find the {@link TrackedRegatta} for this column's series' {@link Series#getRegatta() regatta}
* in order to re-associate a {@link TrackedRace} passed to {@link #setTrackedRace(Fleet, TrackedRace)}
@@ -142,9 +158,9 @@ public class RegattaImpl extends NamedImpl implements Regatta, RaceColumnListene
* this column's series {@link Regatta}, respectively. If <code>null</code>, the re-association won't be
* carried out.
*/
public RegattaImpl(RaceLogStore raceLogStore, RegattaLogStore regattaLogStore, String name, BoatClass boatClass, TimePoint startDate, TimePoint endDate,
TrackedRegattaRegistry trackedRegattaRegistry, ScoringScheme scoringScheme, Serializable id,
CourseArea courseArea) {
public RegattaImpl(RaceLogStore raceLogStore, RegattaLogStore regattaLogStore, String name, BoatClass boatClass,
TimePoint startDate, TimePoint endDate, TrackedRegattaRegistry trackedRegattaRegistry,
ScoringScheme scoringScheme, Serializable id, CourseArea courseArea) {
this(raceLogStore, regattaLogStore, name, boatClass, startDate, endDate, trackedRegattaRegistry, scoringScheme,
id, courseArea, OneDesignRankingMetric::new);
}
@@ -162,12 +178,14 @@ public class RegattaImpl extends NamedImpl implements Regatta, RaceColumnListene
*/
public RegattaImpl(RaceLogStore raceLogStore, RegattaLogStore regattaLogStore, String name, BoatClass boatClass,
TimePoint startDate, TimePoint endDate, TrackedRegattaRegistry trackedRegattaRegistry,
ScoringScheme scoringScheme, Serializable id, CourseArea courseArea, RankingMetricConstructor rankingMetricConstructor) {
ScoringScheme scoringScheme, Serializable id, CourseArea courseArea,
RankingMetricConstructor rankingMetricConstructor) {
this(raceLogStore, regattaLogStore, name, boatClass, startDate, endDate, Collections
.singletonList(new SeriesImpl(LeaderboardNameConstants.DEFAULT_SERIES_NAME,
/* isMedal */false, Collections.singletonList(new FleetImpl(LeaderboardNameConstants.DEFAULT_FLEET_NAME)),
/* isMedal */false, Collections
.singletonList(new FleetImpl(LeaderboardNameConstants.DEFAULT_FLEET_NAME)),
/* race column names */new ArrayList<String>(), trackedRegattaRegistry)), /* persistent */false,
scoringScheme, id, courseArea, /* useStartTimeInference */ true, rankingMetricConstructor);
scoringScheme, id, courseArea, /* useStartTimeInference */true, rankingMetricConstructor);
}
/**
@@ -175,9 +193,10 @@ public class RegattaImpl extends NamedImpl implements Regatta, RaceColumnListene
* all {@link Series} in this iterable will have their {@link Series#setRegatta(Regatta) regatta set} to
* this new regatta.
*/
public <S extends Series> RegattaImpl(RaceLogStore raceLogStore, RegattaLogStore regattaLogStore,
String name, BoatClass boatClass, TimePoint startDate, TimePoint endDate, Iterable<S> series, boolean persistent, ScoringScheme scoringScheme,
Serializable id, CourseArea courseArea, boolean useStartTimeInference, RankingMetricConstructor rankingMetricConstructor) {
public <S extends Series> RegattaImpl(RaceLogStore raceLogStore, RegattaLogStore regattaLogStore, String name,
BoatClass boatClass, TimePoint startDate, TimePoint endDate, Iterable<S> series, boolean persistent,
ScoringScheme scoringScheme, Serializable id, CourseArea courseArea, boolean useStartTimeInference,
RankingMetricConstructor rankingMetricConstructor) {
super(name);
this.rankingMetricConstructor = rankingMetricConstructor;
this.useStartTimeInference = useStartTimeInference;
@@ -241,19 +260,19 @@ public class RegattaImpl extends NamedImpl implements Regatta, RaceColumnListene
}
public static String getDefaultName(String baseName, String boatClassName) {
return baseName+(boatClassName==null?"":" ("+boatClassName+")").replace('/', '_');
return baseName + (boatClassName == null ? "" : " (" + boatClassName + ")").replace('/', '_');
}
@Override
public boolean isPersistent() {
return persistent;
}
/**
* When de-serializing, a possibly remote {@link #raceLogStore} is ignored because it is transient. Instead, an
* {@link EmptyRaceLogStore} is used for the de-serialized instance. A new {@link RaceLogInformation} is assembled
* for this empty race log and applied to all columns.
* Make sure to call {@link #initializeSeriesAfterDeserialize()} after the object graph has been de-serialized.
* for this empty race log and applied to all columns. Make sure to call {@link #initializeSeriesAfterDeserialize()}
* after the object graph has been de-serialized.
*/
private void readObject(ObjectInputStream ois) throws ClassNotFoundException, IOException {
ois.defaultReadObject();
@@ -266,17 +285,16 @@ public class RegattaImpl extends NamedImpl implements Regatta, RaceColumnListene
raceLogStore = EmptyRaceLogStore.INSTANCE;
}
}
protected Object readResolve() throws ObjectStreamException {
raceExecutionOrderCache.triggerUpdate(); // now we're fully initialized and the cache can do its job
return this;
}
/**
* {@link RaceColumnListeners} may not be de-serialized (yet) when the regatta
* is de-serialized. To avoid re-registering empty objects most probably leading
* to null pointer exception one needs to initialize all listeners after
* all objects have been read.
* {@link RaceColumnListeners} may not be de-serialized (yet) when the regatta is de-serialized. To avoid
* re-registering empty objects most probably leading to null pointer exception one needs to initialize all
* listeners after all objects have been read.
*/
public void initializeSeriesAfterDeserialize() {
for (Series series : getSeries()) {
@@ -288,7 +306,7 @@ public class RegattaImpl extends NamedImpl implements Regatta, RaceColumnListene
} else {
logger.warning("Race Columns were null during deserialization. This should not happen.");
}
}
}
}
@Override
@@ -301,7 +319,7 @@ public class RegattaImpl extends NamedImpl implements Regatta, RaceColumnListene
}
return result;
}
@Override
public Series getSeriesByName(String name) {
for (Series s : getSeries()) {
@@ -316,12 +334,12 @@ public class RegattaImpl extends NamedImpl implements Regatta, RaceColumnListene
public Iterable<RaceDefinition> getAllRaces() {
return races.values();
}
@Override
public RegattaIdentifier getRegattaIdentifier() {
return new RegattaName(getName());
}
@Override
public RegattaAndRaceIdentifier getRaceIdentifier(RaceDefinition race) {
return new RegattaNameAndRaceName(getName(), race.getName());
@@ -331,12 +349,13 @@ public class RegattaImpl extends NamedImpl implements Regatta, RaceColumnListene
public RaceDefinition getRaceByName(String raceName) {
return races.get(raceName);
}
@Override
public void addRace(RaceDefinition race) {
logger.info("Adding race "+race.getName()+" to regatta "+getName()+" ("+hashCode()+")");
logger.info("Adding race " + race.getName() + " to regatta " + getName() + " (" + hashCode() + ")");
if (getBoatClass() != null && race.getBoatClass() != getBoatClass()) {
throw new IllegalArgumentException("Boat class "+race.getBoatClass()+" doesn't match regatta's boat class "+getBoatClass());
throw new IllegalArgumentException("Boat class " + race.getBoatClass()
+ " doesn't match regatta's boat class " + getBoatClass());
}
races.put(race.getName(), race);
synchronized (regattaListeners) {
@@ -345,10 +364,10 @@ public class RegattaImpl extends NamedImpl implements Regatta, RaceColumnListene
}
}
}
@Override
public void removeRace(RaceDefinition race) {
logger.info("Removing race "+race.getName()+" from regatta "+getName()+" ("+hashCode()+")");
logger.info("Removing race " + race.getName() + " from regatta " + getName() + " (" + hashCode() + ")");
races.remove(race.getName());
synchronized (regattaListeners) {
for (RegattaListener l : regattaListeners) {
@@ -400,25 +419,28 @@ public class RegattaImpl extends NamedImpl implements Regatta, RaceColumnListene
public void trackedRaceUnlinked(RaceColumn raceColumn, Fleet fleet, TrackedRace trackedRace) {
raceColumnListeners.notifyListenersAboutTrackedRaceUnlinked(raceColumn, fleet, trackedRace);
}
@Override
public void isMedalRaceChanged(RaceColumn raceColumn, boolean newIsMedalRace) {
raceColumnListeners.notifyListenersAboutIsMedalRaceChanged(raceColumn, newIsMedalRace);
}
@Override
public void isStartsWithZeroScoreChanged(RaceColumn raceColumn, boolean newIsStartsWithZeroScore) {
raceColumnListeners.notifyListenersAboutIsStartsWithZeroScoreChanged(raceColumn, newIsStartsWithZeroScore);
}
@Override
public void isFirstColumnIsNonDiscardableCarryForwardChanged(RaceColumn raceColumn, boolean firstColumnIsNonDiscardableCarryForward) {
raceColumnListeners.notifyListenersAboutIsFirstColumnIsNonDiscardableCarryForwardChanged(raceColumn, firstColumnIsNonDiscardableCarryForward);
public void isFirstColumnIsNonDiscardableCarryForwardChanged(RaceColumn raceColumn,
boolean firstColumnIsNonDiscardableCarryForward) {
raceColumnListeners.notifyListenersAboutIsFirstColumnIsNonDiscardableCarryForwardChanged(raceColumn,
firstColumnIsNonDiscardableCarryForward);
}
@Override
public void hasSplitFleetContiguousScoringChanged(RaceColumn raceColumn, boolean hasSplitFleetContiguousScoring) {
raceColumnListeners.notifyListenersAboutHasSplitFleetContiguousScoringChanged(raceColumn, hasSplitFleetContiguousScoring);
raceColumnListeners.notifyListenersAboutHasSplitFleetContiguousScoringChanged(raceColumn,
hasSplitFleetContiguousScoring);
}
@Override
@@ -457,7 +479,8 @@ public class RegattaImpl extends NamedImpl implements Regatta, RaceColumnListene
}
@Override
public void resultDiscardingRuleChanged(ResultDiscardingRule oldDiscardingRule, ResultDiscardingRule newDiscardingRule) {
public void resultDiscardingRuleChanged(ResultDiscardingRule oldDiscardingRule,
ResultDiscardingRule newDiscardingRule) {
raceColumnListeners.notifyListenersAboutResultDiscardingRuleChanged(oldDiscardingRule, newDiscardingRule);
}
@@ -480,7 +503,7 @@ public class RegattaImpl extends NamedImpl implements Regatta, RaceColumnListene
public void raceLogEventAdded(RaceColumn raceColumn, RaceLogIdentifier raceLogIdentifier, RaceLogEvent event) {
raceColumnListeners.notifyListenersAboutRaceLogEventAdded(raceColumn, raceLogIdentifier, event);
}
@Override
public ScoringScheme getScoringScheme() {
return scoringScheme;
@@ -515,17 +538,17 @@ public class RegattaImpl extends NamedImpl implements Regatta, RaceColumnListene
public void setDefaultCourseArea(CourseArea newCourseArea) {
this.defaultCourseArea = newCourseArea;
}
@Override
public void setUseStartTimeInference(boolean useStartTimeInference) {
this.useStartTimeInference = useStartTimeInference;
}
@Override
public RegattaConfiguration getRegattaConfiguration() {
return configuration;
}
@Override
public void setRegattaConfiguration(RegattaConfiguration configuration) {
this.configuration = configuration;
@@ -533,8 +556,8 @@ public class RegattaImpl extends NamedImpl implements Regatta, RaceColumnListene
/**
* @return whether this regatta defines its local per-series result discarding rules; if so, any leaderboard based
* on the regatta has to respect this and has to use a result discarding rule implementation that
* keeps discards local to each series rather than spreading them across the entire leaderboard.
* on the regatta has to respect this and has to use a result discarding rule implementation that keeps
* discards local to each series rather than spreading them across the entire leaderboard.
*/
@Override
public boolean definesSeriesDiscardThresholds() {
@@ -545,7 +568,7 @@ public class RegattaImpl extends NamedImpl implements Regatta, RaceColumnListene
}
return false;
}
public String toString() {
return getId() + " " + getName() + " " + getScoringScheme().getType().name();
}
@@ -594,7 +617,7 @@ public class RegattaImpl extends NamedImpl implements Regatta, RaceColumnListene
}
this.series = newSeriesList;
}
}
}
}
@Override
@@ -621,7 +644,7 @@ public class RegattaImpl extends NamedImpl implements Regatta, RaceColumnListene
public void removeListener(RegattaLikeListener listener) {
regattaLikeHelper.removeListener(listener);
}
@Override
public Double getTimeOnTimeFactor(Competitor competitor) {
return regattaLikeHelper.getTimeOnTimeFactor(competitor);
@@ -649,7 +672,7 @@ public class RegattaImpl extends NamedImpl implements Regatta, RaceColumnListene
public RaceExecutionOrderProvider getRaceExecutionOrderProvider() {
return raceExecutionOrderCache;
}
private class RaceExecutionOrderCache extends AbstractRaceExecutionOrderProvider {
private static final long serialVersionUID = 1658153438012186894L;
@@ -677,8 +700,8 @@ public class RegattaImpl extends NamedImpl implements Regatta, RaceColumnListene
}
} catch (ConcurrentModificationException e) {
// getSeries() returns a live collection, and Series.getRaceColumns() does so, too.
// In the unlikely event of a modification is applied to either of these structures while iterating, an exception
// will be thrown. We catch and log it here and try again.
// In the unlikely event of a modification is applied to either of these structures while
// iterating, an exception will be thrown. We catch and log it here and try again.
logger.log(Level.INFO,
"Got a ConcurrentModificationException while trying to update the RaceExecutionOrderCache", e);
concurrentlyModified = true;
@@ -726,4 +749,40 @@ public class RegattaImpl extends NamedImpl implements Regatta, RaceColumnListene
}
return result;
}
@Override
public Iterable<Competitor> getCompetitorsRegisteredInRegattaLog() {
RegattaLog regattaLog = getRegattaLog();
CompetitorsInLogAnalyzer<RegattaLog, RegattaLogEvent, RegattaLogEventVisitor> analyzer = new CompetitorsInLogAnalyzer<>(
regattaLog);
return analyzer.analyze();
}
@Override
public void registerCompetitor(Competitor competitor) {
registerCompetitors(Collections.singleton(competitor));
}
@Override
public void registerCompetitors(Iterable<Competitor> competitors) {
RegattaLog regattaLog = getRegattaLike().getRegattaLog();
TimePoint now = MillisecondsTimePoint.now();
for (Competitor competitor : competitors) {
regattaLog.add(new RegattaLogRegisterCompetitorEventImpl(now, now, regattaLogEventAuthorForRegatta,
UUID.randomUUID(), competitor));
}
}
@Override
public void deregisterCompetitor(Competitor competitor) {
deregisterCompetitors(Collections.singleton(competitor));
}
@Override
public void deregisterCompetitors(Iterable<Competitor> competitors) {
RegattaLog regattaLog = getRegattaLike().getRegattaLog();
CompetitorDeregistrator<RegattaLog, RegattaLogEvent, RegattaLogEventVisitor> deregisterer = new CompetitorDeregistrator<>(regattaLog, competitors, regattaLogEventAuthorForRegatta);
deregisterer.analyze();
}
}
@@ -1,5 +1,10 @@
package com.sap.sailing.domain.base.impl;
import java.util.Collections;
import com.sap.sailing.domain.abstractlog.race.RaceLog;
import com.sap.sailing.domain.abstractlog.race.analyzing.impl.RaceLogRegisteredCompetitorsAnalyzer;
import com.sap.sailing.domain.abstractlog.race.tracking.analyzing.impl.RaceLogUsesOwnCompetitorsAnalyzer;
import com.sap.sailing.domain.base.Competitor;
import com.sap.sailing.domain.base.Fleet;
import com.sap.sailing.domain.base.RaceColumn;
@@ -114,5 +119,26 @@ public abstract class SimpleAbstractRaceColumn implements RaceColumn {
public boolean hasSplitFleets() {
return Util.size(getFleets()) > 1;
}
@Override
public Iterable<Competitor> getCompetitorsRegisteredInRacelog(final Fleet fleet) {
RaceLog raceLog = getRaceLog(fleet);
if (raceLog == null) {
return Collections.emptySet();
} else {
RaceLogRegisteredCompetitorsAnalyzer analyzer = new RaceLogRegisteredCompetitorsAnalyzer(raceLog);
return analyzer.analyze();
}
}
@Override
public boolean isCompetitorRegistrationInRacelogEnabled(final Fleet fleet) {
RaceLog raceLog = getRaceLog(fleet);
if (raceLog == null) {
return false;
} else {
RaceLogUsesOwnCompetitorsAnalyzer analyzer = new RaceLogUsesOwnCompetitorsAnalyzer(raceLog);
return analyzer.analyze();
}
}
}
@@ -1,8 +1,10 @@
package com.sap.sailing.domain.leaderboard;
import com.sap.sailing.domain.base.RaceColumn;
import com.sap.sailing.domain.regattalike.IsRegattaLike;
public interface FlexibleRaceColumn extends RaceColumn {
void setName(String newName);
void setIsMedalRace(boolean isMedalRace);
void setRegattaLikeHelper(IsRegattaLike regattaLikeHelper);
}
@@ -5,8 +5,17 @@ import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import java.util.UUID;
import com.sap.sailing.domain.abstractlog.AbstractLogEventAuthor;
import com.sap.sailing.domain.abstractlog.impl.LogEventAuthorImpl;
import com.sap.sailing.domain.abstractlog.race.RaceLog;
import com.sap.sailing.domain.abstractlog.regatta.RegattaLog;
import com.sap.sailing.domain.abstractlog.regatta.RegattaLogEvent;
import com.sap.sailing.domain.abstractlog.regatta.RegattaLogEventVisitor;
import com.sap.sailing.domain.abstractlog.regatta.events.impl.RegattaLogRegisterCompetitorEventImpl;
import com.sap.sailing.domain.abstractlog.shared.analyzing.CompetitorDeregistrator;
import com.sap.sailing.domain.abstractlog.shared.analyzing.CompetitorsInLogAnalyzer;
import com.sap.sailing.domain.base.Competitor;
import com.sap.sailing.domain.base.Fleet;
import com.sap.sailing.domain.base.RaceColumn;
@@ -17,34 +26,41 @@ import com.sap.sailing.domain.leaderboard.ScoreCorrection;
import com.sap.sailing.domain.leaderboard.ThresholdBasedResultDiscardingRule;
import com.sap.sailing.domain.tracking.TrackedRace;
import com.sap.sse.common.TimePoint;
import com.sap.sse.common.impl.MillisecondsTimePoint;
/**
* Abstract leaderboard implementation that already knows about carried points, competitor display name re-keying,
* score corrections and result discarding rules. It manages a set of registered {@link RaceColumnListener}s and
* is itself one. All events received this way are forwarded to all {@link RaceColumnListener}s subscribed. This can
* be used to subscribe a concrete leaderboard implementation to the data structure providing the actual race columns
* in order to be notified whenever the set of {@link TrackedRace}s attached to the leaderboard changes.
* Abstract leaderboard implementation that already knows about carried points, competitor display name re-keying, score
* corrections and result discarding rules. It manages a set of registered {@link RaceColumnListener}s and is itself
* one. All events received this way are forwarded to all {@link RaceColumnListener}s subscribed. This can be used to
* subscribe a concrete leaderboard implementation to the data structure providing the actual race columns in order to
* be notified whenever the set of {@link TrackedRace}s attached to the leaderboard changes.
*
* @author Axel Uhl (D043530)
*
*/
public abstract class AbstractLeaderboardImpl extends AbstractSimpleLeaderboardImpl implements HasRaceColumnsAndRegattaLike {
public abstract class AbstractLeaderboardImpl extends AbstractSimpleLeaderboardImpl implements
HasRaceColumnsAndRegattaLike {
private static final long serialVersionUID = -328091952760083438L;
/**
* Cache for the combined competitors of this leaderboard; taken from the {@link TrackedRace#getRace() races of the
* tracked races} associated with this leaderboard. Updated when the set of tracked races changes.
*/
private transient CompetitorProviderFromRaceColumnsAndRegattaLike competitorsProvider;
private final AbstractLogEventAuthor regattaLogEventAuthorForAbstractLeaderboard = new LogEventAuthorImpl(
AbstractLeaderboardImpl.class.getName(), 0);
/**
* @param scoreComparator the comparator to use to compare basic scores, such as net points
* @param name must not be <code>null</code>
* @param scoreComparator
* the comparator to use to compare basic scores, such as net points
* @param name
* must not be <code>null</code>
*/
public AbstractLeaderboardImpl(ThresholdBasedResultDiscardingRule resultDiscardingRule) {
super(resultDiscardingRule);
}
@Override
public Fleet getFleet(String fleetName) {
for (RaceColumn raceColumn : getRaceColumns()) {
@@ -79,7 +95,7 @@ public abstract class AbstractLeaderboardImpl extends AbstractSimpleLeaderboardI
public Iterable<Competitor> getAllCompetitors() {
return getOrCreateCompetitorsProvider().getAllCompetitors();
}
@Override
public Iterable<Competitor> getAllCompetitors(RaceColumn raceColumn, Fleet fleet) {
return getOrCreateCompetitorsProvider().getAllCompetitors(raceColumn, fleet);
@@ -106,8 +122,8 @@ public abstract class AbstractLeaderboardImpl extends AbstractSimpleLeaderboardI
public int getTrackedRank(Competitor competitor, RaceColumn race, TimePoint timePoint) {
final TrackedRace trackedRace = race.getTrackedRace(competitor);
return trackedRace == null ? 0
: trackedRace.hasStarted(timePoint) ? improveByDisqualificationsOfBetterRankedCompetitors(race, trackedRace, timePoint, trackedRace
.getRank(competitor, timePoint)) : 0;
: trackedRace.hasStarted(timePoint) ? improveByDisqualificationsOfBetterRankedCompetitors(race,
trackedRace, timePoint, trackedRace.getRank(competitor, timePoint)) : 0;
}
/**
@@ -135,9 +151,11 @@ public abstract class AbstractLeaderboardImpl extends AbstractSimpleLeaderboardI
Iterator<Competitor> ci = competitorsFromBestToWorst.iterator();
while (betterCompetitorRank < rank && ci.hasNext()) {
Competitor betterTrackedCompetitor = ci.next();
MaxPointsReason maxPointsReasonForBetterCompetitor = getScoreCorrection().getMaxPointsReason(betterTrackedCompetitor, raceColumn, timePoint);
if (maxPointsReasonForBetterCompetitor != null && maxPointsReasonForBetterCompetitor != MaxPointsReason.NONE &&
maxPointsReasonForBetterCompetitor.isAdvanceCompetitorsTrackedWorse()) {
MaxPointsReason maxPointsReasonForBetterCompetitor = getScoreCorrection().getMaxPointsReason(
betterTrackedCompetitor, raceColumn, timePoint);
if (maxPointsReasonForBetterCompetitor != null
&& maxPointsReasonForBetterCompetitor != MaxPointsReason.NONE
&& maxPointsReasonForBetterCompetitor.isAdvanceCompetitorsTrackedWorse()) {
correctedRank--;
}
betterCompetitorRank++;
@@ -156,7 +174,8 @@ public abstract class AbstractLeaderboardImpl extends AbstractSimpleLeaderboardI
TrackedRace trackedRace = raceColumn.getTrackedRace(fleet);
if (trackedRace != null) {
if (startOfLatestRace == null
|| (trackedRace.getStartOfRace() != null && trackedRace.getStartOfRace().compareTo(startOfLatestRace) > 0)) {
|| (trackedRace.getStartOfRace() != null && trackedRace.getStartOfRace().compareTo(
startOfLatestRace) > 0)) {
delayToLiveInMillisForLatestRace = trackedRace.getDelayToLiveInMillis();
}
}
@@ -164,12 +183,47 @@ public abstract class AbstractLeaderboardImpl extends AbstractSimpleLeaderboardI
}
return delayToLiveInMillisForLatestRace;
}
@Override
public RaceLog getRacelog(String raceColumnName, String fleetName){
public RaceLog getRacelog(String raceColumnName, String fleetName) {
RaceColumn raceColumn = getRaceColumnByName(raceColumnName);
Fleet fleet = raceColumn.getFleetByName(fleetName);
return raceColumn.getRaceLog(fleet);
}
@Override
public Iterable<Competitor> getCompetitorsRegisteredInRegattaLog() {
RegattaLog regattaLog = getRegattaLike().getRegattaLog();
CompetitorsInLogAnalyzer<RegattaLog, RegattaLogEvent, RegattaLogEventVisitor> analyzer = new CompetitorsInLogAnalyzer<>(
regattaLog);
return analyzer.analyze();
}
@Override
public void registerCompetitor(Competitor competitor) {
registerCompetitors(Collections.singleton(competitor));
}
@Override
public void registerCompetitors(Iterable<Competitor> competitors) {
RegattaLog regattaLog = getRegattaLike().getRegattaLog();
TimePoint now = MillisecondsTimePoint.now();
for (Competitor competitor : competitors) {
regattaLog.add(new RegattaLogRegisterCompetitorEventImpl(now, now, regattaLogEventAuthorForAbstractLeaderboard,
UUID.randomUUID(), competitor));
}
}
@Override
public void deregisterCompetitor(Competitor competitor) {
deregisterCompetitors(Collections.singleton(competitor));
}
@Override
public void deregisterCompetitors(Iterable<Competitor> competitors) {
RegattaLog regattaLog = getRegattaLike().getRegattaLog();
CompetitorDeregistrator<RegattaLog, RegattaLogEvent, RegattaLogEventVisitor> deregisterer = new CompetitorDeregistrator<>(regattaLog, competitors, regattaLogEventAuthorForAbstractLeaderboard);
deregisterer.analyze();
}
}
@@ -11,12 +11,12 @@ import com.sap.sailing.domain.abstractlog.race.RaceLogEventVisitor;
import com.sap.sailing.domain.abstractlog.race.RaceLogRevokeEvent;
import com.sap.sailing.domain.abstractlog.race.impl.BaseRaceLogEventVisitor;
import com.sap.sailing.domain.abstractlog.race.tracking.RaceLogRegisterCompetitorEvent;
import com.sap.sailing.domain.abstractlog.race.tracking.RaceLogUseCompetitorsFromRaceLogEvent;
import com.sap.sailing.domain.abstractlog.regatta.RegattaLog;
import com.sap.sailing.domain.abstractlog.regatta.RegattaLogEventVisitor;
import com.sap.sailing.domain.abstractlog.regatta.events.RegattaLogRegisterCompetitorEvent;
import com.sap.sailing.domain.abstractlog.regatta.events.RegattaLogRevokeEvent;
import com.sap.sailing.domain.abstractlog.regatta.impl.BaseRegattaLogEventVisitor;
import com.sap.sailing.domain.abstractlog.shared.analyzing.RegisteredCompetitorsAnalyzer;
import com.sap.sailing.domain.base.Competitor;
import com.sap.sailing.domain.base.Fleet;
import com.sap.sailing.domain.base.RaceColumn;
@@ -29,30 +29,36 @@ import com.sap.sse.common.Util.Pair;
/**
* A caching provider of a competitor set, based on the tracked races and {@link RaceLog}s of the {@link RaceColumn}s of
* a {@link HasRaceColumnsAndRegattaLike} and the {@link RegattaLog} of the same object. After an answer has been provided,
* it is cached. The cache is invalidated when one of the following events occurs:
* a {@link HasRaceColumnsAndRegattaLike} and the {@link RegattaLog} of the same object. After an answer has been
* provided, it is cached. The cache is invalidated when one of the following events occurs:
* <ul>
* <li>a competitor is registered with or unregistered from a race log of any of the race columns or the regatta log</li>
* <li>a race column is added or removed</li>
* <li>a tracked race is linked to or unlinked from any of the race columns</li>
* <li>the racelog is marked as providing it's own competitors via the {@link RaceLogUseCompetitorsFromRaceLogEvent}</li>
* <li>the racelog is marked as no longer providing it's own competitors by revoking an event of type {@link RaceLogUseCompetitorsFromRaceLogEvent}</li>
* </ul>
*
* Note that objects of this type are not serializable. Classes using such objects shall not assign them to non-transient
* fields if they want to be serializable themselves.
*
* @author Axel Uhl (d043530)
*
*/
public class CompetitorProviderFromRaceColumnsAndRegattaLike {
private static final Logger logger = Logger.getLogger(CompetitorProviderFromRaceColumnsAndRegattaLike.class.getName());
private static final Logger logger = Logger.getLogger(CompetitorProviderFromRaceColumnsAndRegattaLike.class
.getName());
private final HasRaceColumnsAndRegattaLike provider;
private final RegattaLogEventVisitor regattaLogCompetitorsCacheInvalidationListener;
private final RaceLogEventVisitor raceLogCompetitorsCacheInvalidationListener;
private final RaceColumnListener raceColumnListener;
private Iterable<Competitor> allCompetitorsCache;
private final ConcurrentHashMap<Pair<RaceColumn, Fleet>, Iterable<Competitor>> allCompetitorsCacheByRace;
public CompetitorProviderFromRaceColumnsAndRegattaLike(HasRaceColumnsAndRegattaLike provider) {
@@ -75,11 +81,13 @@ public class CompetitorProviderFromRaceColumnsAndRegattaLike {
@Override
public void visit(RegattaLogRevokeEvent event) {
try {
if (RegattaLogRegisterCompetitorEvent.class.isAssignableFrom(Class.forName(event.getRevokedEventType()))) {
if (RegattaLogRegisterCompetitorEvent.class.isAssignableFrom(Class.forName(event
.getRevokedEventType()))) {
invalidateAllCompetitorsCaches();
}
} catch (ClassNotFoundException e) {
logger.log(Level.WARNING, "Problem occurred trying to resolve revoked event class "+event.getRevokedEventType(), e);
logger.log(Level.WARNING,
"Problem occurred trying to resolve revoked event class " + event.getRevokedEventType(), e);
}
}
};
@@ -89,14 +97,23 @@ public class CompetitorProviderFromRaceColumnsAndRegattaLike {
invalidateAllCompetitorsCaches();
}
@Override
public void visit(RaceLogUseCompetitorsFromRaceLogEvent event) {
invalidateAllCompetitorsCaches();
}
@Override
public void visit(RaceLogRevokeEvent event) {
try {
if (RaceLogRegisterCompetitorEvent.class.isAssignableFrom(Class.forName(event.getRevokedEventType()))) {
final Class<?> revokedEventClass = Class.forName(event.getRevokedEventType());
//
if (RaceLogRegisterCompetitorEvent.class.isAssignableFrom(revokedEventClass) ||
RaceLogUseCompetitorsFromRaceLogEvent.class.isAssignableFrom(revokedEventClass)) {
invalidateAllCompetitorsCaches();
}
} catch (ClassNotFoundException e) {
logger.log(Level.WARNING, "Problem occurred trying to resolve revoked event class "+event.getRevokedEventType(), e);
logger.log(Level.WARNING,
"Problem occurred trying to resolve revoked event class " + event.getRevokedEventType(), e);
}
}
};
@@ -104,7 +121,8 @@ public class CompetitorProviderFromRaceColumnsAndRegattaLike {
private static final long serialVersionUID = -8678230058730043052L;
@Override
public void defaultAction() {}
public void defaultAction() {
}
/**
* As the entire provider object is considered transient, its listeners are so, too.
@@ -135,7 +153,7 @@ public class CompetitorProviderFromRaceColumnsAndRegattaLike {
}
};
}
public Iterable<Competitor> getAllCompetitors() {
if (allCompetitorsCache == null) {
final Set<Competitor> result = new HashSet<>();
@@ -145,59 +163,59 @@ public class CompetitorProviderFromRaceColumnsAndRegattaLike {
rc.getRaceLog(fleet).addListener(raceLogCompetitorsCacheInvalidationListener);
}
}
// note: adding listeners is idempotent; at most one occurrence of this listener exists in the race/regatta log's
// listeners set
provider.addRaceColumnListener(raceColumnListener);
// consider {@link RegattaLog}
Set<Competitor> viaLog = getCompetitorsFromRegattaLogAndRegisterAsRegattaLogListener();
result.addAll(viaLog);
// consider {@link RegattaLog} competitor changes because the RaceColumns may have added the competitors from there
provider.getRegattaLike().getRegattaLog().addListener(regattaLogCompetitorsCacheInvalidationListener);
allCompetitorsCache = result;
}
return allCompetitorsCache;
}
/**
* Obtains competitors from the regatta log and adds those from the tracked race for the
* raceColumn/fleet combination or the race log, if no tracked race is attached for this
* combination. Does <em>not</em> eliminate suppressed competitors.
* Obtains competitors from the regatta log and adds those from the tracked race for the raceColumn/fleet
* combination or the race log, if no tracked race is attached for this combination. Does <em>not</em> eliminate
* suppressed competitors.
*/
public Iterable<Competitor> getAllCompetitors(final RaceColumn raceColumn, final Fleet fleet) {
Pair<RaceColumn, Fleet> key = new Pair<>(raceColumn, fleet);
Iterable<Competitor> result = allCompetitorsCacheByRace.get(key);
if (result == null) {
final Set<Competitor> resultSet = new HashSet<>();
final Set<Competitor> resultSet = new HashSet<>();
//raceColumn already considers trackedRace, RaceLog and RegattaLog
Util.addAll(raceColumn.getAllCompetitors(fleet), resultSet);
// note: adding listeners is idempotent; at most one occurrence of this listener exists in the race log's listeners set
// note: adding listeners is idempotent; at most one occurrence of this listener exists in the race/regatta log's
// listeners set
raceColumn.getRaceLog(fleet).addListener(raceLogCompetitorsCacheInvalidationListener);
provider.addRaceColumnListener(raceColumnListener);
// consider {@link RegattaLog}
Set<Competitor> viaLog = getCompetitorsFromRegattaLogAndRegisterAsRegattaLogListener();
resultSet.addAll(viaLog);
// consider {@link RegattaLog} competitor changes because the RaceColumns may have added the competitors from there
provider.getRegattaLike().getRegattaLog().addListener(regattaLogCompetitorsCacheInvalidationListener);
result = resultSet;
allCompetitorsCacheByRace.put(key, result);
}
return result;
}
private Set<Competitor> getCompetitorsFromRegattaLogAndRegisterAsRegattaLogListener() {
Set<Competitor> viaLog = new RegisteredCompetitorsAnalyzer<>(provider.getRegattaLike().getRegattaLog()).analyze();
// note: adding listeners is idempotent; at most one occurrence of this listener exists in the regatta log's listeners set
provider.getRegattaLike().getRegattaLog().addListener(regattaLogCompetitorsCacheInvalidationListener);
return viaLog;
}
private void invalidateAllCompetitorsCaches() {
allCompetitorsCache = null;
// note: adding listeners was idempotent; at most one occurrence of this listener exists in the regatta log's listeners set
// note: adding listeners was idempotent; at most one occurrence of this listener exists in the regatta log's
// listeners set
provider.getRegattaLike().getRegattaLog().removeListener(regattaLogCompetitorsCacheInvalidationListener);
for (final RaceColumn rc : provider.getRaceColumns()) {
for (final Fleet fleet : rc.getFleets()) {
// note: adding listeners was idempotent; at most one occurrence of this listener exists in the race log's listeners set
// note: adding listeners was idempotent; at most one occurrence of this listener exists in the race
// log's listeners set
rc.getRaceLog(fleet).removeListener(raceLogCompetitorsCacheInvalidationListener);
}
}
// note: adding listeners was idempotent; at most one occurrence of this listener exists in the race column listeners set
// note: adding listeners was idempotent; at most one occurrence of this listener exists in the race column
// listeners set
provider.removeRaceColumnListener(raceColumnListener);
allCompetitorsCacheByRace.clear(); // this is a little coarse-grained; but given the typical access patterns it should be good enough.
// The change frequency of competitors lists on individual races is much lower than the access frequency to this structure.
allCompetitorsCacheByRace.clear(); // this is a little coarse-grained; but given the typical access patterns it
// should be good enough.
// The change frequency of competitors lists on individual races is much lower than the access frequency to this
// structure.
}
}

Some files were not shown because too many files have changed in this diff Show More