diff --git a/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/server/DashboardDispatchRPCServletImpl.java b/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/server/DashboardDispatchRPCServletImpl.java index 845b1dcfb80..4e992218432 100644 --- a/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/server/DashboardDispatchRPCServletImpl.java +++ b/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/server/DashboardDispatchRPCServletImpl.java @@ -1,6 +1,5 @@ package com.sap.sailing.dashboards.gwt.server; -import java.util.UUID; import java.util.logging.Level; import java.util.logging.Logger; @@ -18,11 +17,11 @@ import com.sap.sailing.gwt.ui.server.ProxiedRemoteServiceServlet; import com.sap.sailing.server.RacingEventService; import com.sap.sse.gwt.dispatch.client.Action; import com.sap.sse.gwt.dispatch.client.Result; -import com.sap.sse.gwt.dispatch.client.ResultWrapper; import com.sap.sse.gwt.dispatch.client.exceptions.DispatchException; import com.sap.sse.gwt.dispatch.client.exceptions.ServerDispatchException; import com.sap.sse.gwt.dispatch.client.rpcimpl.DispatchRPC; import com.sap.sse.gwt.dispatch.client.rpcimpl.RequestWrapper; +import com.sap.sse.gwt.dispatch.client.rpcimpl.ResultWrapper; import com.sap.sse.util.ServiceTrackerFactory; public class DashboardDispatchRPCServletImpl extends ProxiedRemoteServiceServlet implements DispatchRPC { @@ -56,9 +55,9 @@ public class DashboardDispatchRPCServletImpl extends ProxiedRemoteServiceServlet logger.log(Level.WARNING, "Server exception", d); throw d; } catch (Throwable t) { - String serverExceptionUUID = UUID.randomUUID().toString(); - logger.log(Level.SEVERE, "Uncaught server exception id: " + serverExceptionUUID, t); - throw new ServerDispatchException(serverExceptionUUID, t); + ServerDispatchException dispatchException = new ServerDispatchException(t); + logger.log(Level.SEVERE, "Uncaught server exception id: " + dispatchException.getExceptionId(), t); + throw dispatchException; } finally { long duration = System.currentTimeMillis() - start; final Level logLevel; diff --git a/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/NotFoundException.java b/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/NotFoundException.java new file mode 100644 index 00000000000..1182a9de6c1 --- /dev/null +++ b/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/NotFoundException.java @@ -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); + } +} diff --git a/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/UnableToCloseDeviceMappingException.java b/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/UnableToCloseDeviceMappingException.java new file mode 100644 index 00000000000..879f1e05f96 --- /dev/null +++ b/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/UnableToCloseDeviceMappingException.java @@ -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); + } +} diff --git a/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/racelog/tracking/CompetitorRegistrationOnRaceLogDisabledException.java b/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/racelog/tracking/CompetitorRegistrationOnRaceLogDisabledException.java new file mode 100644 index 00000000000..22bf5a15b90 --- /dev/null +++ b/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/racelog/tracking/CompetitorRegistrationOnRaceLogDisabledException.java @@ -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); + } +} diff --git a/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/tracking/impl/CompactGPSFixMovingImpl.java b/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/tracking/impl/CompactGPSFixMovingImpl.java index 095bb7ac1ec..b48f26dcd05 100755 --- a/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/tracking/impl/CompactGPSFixMovingImpl.java +++ b/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/tracking/impl/CompactGPSFixMovingImpl.java @@ -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(); diff --git a/java/com.sap.sailing.domain.persistence/src/com/sap/sailing/domain/persistence/impl/DomainObjectFactoryImpl.java b/java/com.sap.sailing.domain.persistence/src/com/sap/sailing/domain/persistence/impl/DomainObjectFactoryImpl.java index d83d3620927..82bbc124272 100644 --- a/java/com.sap.sailing.domain.persistence/src/com/sap/sailing/domain/persistence/impl/DomainObjectFactoryImpl.java +++ b/java/com.sap.sailing.domain.persistence/src/com/sap/sailing/domain/persistence/impl/DomainObjectFactoryImpl.java @@ -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 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 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 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 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 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 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 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 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 positionedCompetitor = new Util.Triple(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 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 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 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 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(); diff --git a/java/com.sap.sailing.domain.persistence/src/com/sap/sailing/domain/persistence/impl/FieldNames.java b/java/com.sap.sailing.domain.persistence/src/com/sap/sailing/domain/persistence/impl/FieldNames.java old mode 100755 new mode 100644 index 4f9412e8a08..afdd80e130a --- a/java/com.sap.sailing.domain.persistence/src/com/sap/sailing/domain/persistence/impl/FieldNames.java +++ b/java/com.sap.sailing.domain.persistence/src/com/sap/sailing/domain/persistence/impl/FieldNames.java @@ -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, diff --git a/java/com.sap.sailing.domain.persistence/src/com/sap/sailing/domain/persistence/impl/MongoObjectFactoryImpl.java b/java/com.sap.sailing.domain.persistence/src/com/sap/sailing/domain/persistence/impl/MongoObjectFactoryImpl.java index 0bbc0721096..0e19ce1778c 100644 --- a/java/com.sap.sailing.domain.persistence/src/com/sap/sailing/domain/persistence/impl/MongoObjectFactoryImpl.java +++ b/java/com.sap.sailing.domain.persistence/src/com/sap/sailing/domain/persistence/impl/MongoObjectFactoryImpl.java @@ -1,1533 +1,1487 @@ -package com.sap.sailing.domain.persistence.impl; - -import java.io.Serializable; -import java.net.URL; -import java.util.List; -import java.util.Map.Entry; -import java.util.logging.Level; -import java.util.logging.Logger; - -import org.bson.types.ObjectId; -import org.json.simple.JSONObject; - -import com.mongodb.BasicDBList; -import com.mongodb.BasicDBObject; -import com.mongodb.BasicDBObjectBuilder; -import com.mongodb.DB; -import com.mongodb.DBCollection; -import com.mongodb.DBObject; -import com.mongodb.WriteConcern; -import com.mongodb.util.JSON; -import com.sap.sailing.domain.abstractlog.AbstractLogEventAuthor; -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.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; -import com.sap.sailing.domain.abstractlog.race.RaceLogPathfinderEvent; -import com.sap.sailing.domain.abstractlog.race.RaceLogProtestStartTimeEvent; -import com.sap.sailing.domain.abstractlog.race.RaceLogRaceStatusEvent; -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.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.regatta.RegattaLogEvent; -import com.sap.sailing.domain.abstractlog.regatta.events.RegattaLogCloseOpenEndedDeviceMappingEvent; -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; -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.shared.events.DeviceMappingEvent; -import com.sap.sailing.domain.base.Competitor; -import com.sap.sailing.domain.base.ControlPoint; -import com.sap.sailing.domain.base.ControlPointWithTwoMarks; -import com.sap.sailing.domain.base.CourseArea; -import com.sap.sailing.domain.base.CourseBase; -import com.sap.sailing.domain.base.Event; -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.RaceDefinition; -import com.sap.sailing.domain.base.Regatta; -import com.sap.sailing.domain.base.RemoteSailingServerReference; -import com.sap.sailing.domain.base.SailingServerConfiguration; -import com.sap.sailing.domain.base.Series; -import com.sap.sailing.domain.base.Venue; -import com.sap.sailing.domain.base.Waypoint; -import com.sap.sailing.domain.base.configuration.DeviceConfiguration; -import com.sap.sailing.domain.base.configuration.DeviceConfigurationMatcher; -import com.sap.sailing.domain.base.configuration.RegattaConfiguration; -import com.sap.sailing.domain.base.configuration.impl.DeviceConfigurationMatcherMulti; -import com.sap.sailing.domain.base.configuration.impl.DeviceConfigurationMatcherSingle; -import com.sap.sailing.domain.base.impl.FleetImpl; -import com.sap.sailing.domain.common.Bearing; -import com.sap.sailing.domain.common.MaxPointsReason; -import com.sap.sailing.domain.common.PassingInstruction; -import com.sap.sailing.domain.common.Positioned; -import com.sap.sailing.domain.common.RaceIdentifier; -import com.sap.sailing.domain.common.Speed; -import com.sap.sailing.domain.common.SpeedWithBearing; -import com.sap.sailing.domain.common.Wind; -import com.sap.sailing.domain.common.WindSource; -import com.sap.sailing.domain.common.racelog.tracking.TransformationException; -import com.sap.sailing.domain.leaderboard.FlexibleLeaderboard; -import com.sap.sailing.domain.leaderboard.Leaderboard; -import com.sap.sailing.domain.leaderboard.LeaderboardGroup; -import com.sap.sailing.domain.leaderboard.RegattaLeaderboard; -import com.sap.sailing.domain.leaderboard.ResultDiscardingRule; -import com.sap.sailing.domain.leaderboard.SettableScoreCorrection; -import com.sap.sailing.domain.leaderboard.ThresholdBasedResultDiscardingRule; -import com.sap.sailing.domain.persistence.MongoObjectFactory; -import com.sap.sailing.domain.persistence.racelog.tracking.DeviceIdentifierMongoHandler; -import com.sap.sailing.domain.persistence.racelog.tracking.impl.PlaceHolderDeviceIdentifierMongoHandler; -import com.sap.sailing.domain.racelog.RaceLogIdentifier; -import com.sap.sailing.domain.racelogtracking.DeviceIdentifier; -import com.sap.sailing.domain.regattalike.RegattaLikeIdentifier; -import com.sap.sailing.domain.tracking.TrackedRace; -import com.sap.sailing.domain.tracking.TrackedRegatta; -import com.sap.sailing.domain.tracking.WindTrack; -import com.sap.sailing.server.gateway.serialization.JsonSerializer; -import com.sap.sailing.server.gateway.serialization.impl.CompetitorJsonSerializer; -import com.sap.sailing.server.gateway.serialization.impl.DeviceConfigurationJsonSerializer; -import com.sap.sailing.server.gateway.serialization.impl.RegattaConfigurationJsonSerializer; -import com.sap.sse.common.Duration; -import com.sap.sse.common.NoCorrespondingServiceRegisteredException; -import com.sap.sse.common.TimePoint; -import com.sap.sse.common.TimeRange; -import com.sap.sse.common.Timed; -import com.sap.sse.common.TypeBasedServiceFinder; -import com.sap.sse.common.TypeBasedServiceFinderFactory; -import com.sap.sse.common.Util; -import com.sap.sse.common.impl.MillisecondsTimePoint; -import com.sap.sse.shared.media.ImageDescriptor; -import com.sap.sse.shared.media.VideoDescriptor; - -public class MongoObjectFactoryImpl implements MongoObjectFactory { - private static Logger logger = Logger.getLogger(MongoObjectFactoryImpl.class.getName()); - private final DB database; - private final CompetitorJsonSerializer competitorSerializer = CompetitorJsonSerializer.create(); - private final TypeBasedServiceFinder deviceIdentifierServiceFinder; - - /** - * Uses null for the device type service finder and hence will be unable to store device identifiers. - * Use this constructor only for testing purposes or in cases where there will happen absolutely no access to - * {@link DeviceIdentifier} objects. - */ - public MongoObjectFactoryImpl(DB database) { - this(database, /* deviceTypeServiceFinder */ null); - } - - public MongoObjectFactoryImpl(DB database, TypeBasedServiceFinderFactory serviceFinderFactory) { - this.database = database; - if (serviceFinderFactory != null) { - this.deviceIdentifierServiceFinder = serviceFinderFactory.createServiceFinder(DeviceIdentifierMongoHandler.class); - this.deviceIdentifierServiceFinder.setFallbackService(new PlaceHolderDeviceIdentifierMongoHandler()); - } else { - this.deviceIdentifierServiceFinder = null; - } - } - - @Override - public DB getDatabase() { - return database; - } - - public DBObject storeWind(Wind wind) { - DBObject result = new BasicDBObject(); - storePositioned(wind, result); - storeTimed(wind, result); - storeSpeedWithBearing(wind, result); - return result; - } - - public static void storeTimePoint(TimePoint timePoint, DBObject result, String fieldName) { - if (timePoint != null) { - result.put(fieldName, timePoint.asMillis()); - } - } - - public static void storeTimePoint(TimePoint timePoint, DBObject result, FieldNames field) { - storeTimePoint(timePoint, result, field.name()); - } - - public static void storeTimeRange(TimeRange timeRange, DBObject result, FieldNames field) { - if (timeRange != null) { - DBObject timeRangeObj = new BasicDBObject(); - storeTimePoint(timeRange.from(), timeRangeObj, FieldNames.FROM_MILLIS); - storeTimePoint(timeRange.to(), timeRangeObj, FieldNames.TO_MILLIS); - result.put(field.name(), timeRangeObj); - } - } - - public void storeTimed(Timed timed, DBObject result) { - if (timed.getTimePoint() != null) { - storeTimePoint(timed.getTimePoint(), result, FieldNames.TIME_AS_MILLIS); - } - } - - public void storeSpeedWithBearing(SpeedWithBearing speedWithBearing, DBObject result) { - storeSpeed(speedWithBearing, result); - storeBearing(speedWithBearing.getBearing(), result); - - } - - public void storeBearing(Bearing bearing, DBObject result) { - result.put(FieldNames.DEGREE_BEARING.name(), bearing.getDegrees()); - } - - public void storeSpeed(Speed speed, DBObject result) { - result.put(FieldNames.KNOT_SPEED.name(), speed.getKnots()); - } - - public void storePositioned(Positioned positioned, DBObject result) { - if (positioned.getPosition() != null) { - result.put(FieldNames.LAT_DEG.name(), positioned.getPosition().getLatDeg()); - result.put(FieldNames.LNG_DEG.name(), positioned.getPosition().getLngDeg()); - } - } - - @Override - public void addWindTrackDumper(TrackedRegatta trackedRegatta, TrackedRace trackedRace, WindSource windSource) { - WindTrack windTrack = trackedRace.getOrCreateWindTrack(windSource); - windTrack.addListener(new MongoWindListener(trackedRace, trackedRegatta.getRegatta().getName(), windSource, this, database)); - } - - public DBCollection getWindTrackCollection() { - DBCollection result = database.getCollection(CollectionNames.WIND_TRACKS.name()); - result.createIndex(new BasicDBObject(FieldNames.REGATTA_NAME.name(), null)); - return result; - } - - public DBCollection getGPSFixCollection() { - DBCollection gpsFixCollection = database.getCollection(CollectionNames.GPS_FIXES.name()); - DBObject index = new BasicDBObject(); - index.put(FieldNames.DEVICE_ID.name(), null); - index.put(FieldNames.TIME_AS_MILLIS.name(), null); - gpsFixCollection.createIndex(index); - return gpsFixCollection; - } - - public DBCollection getGPSFixMetadataCollection() { - DBCollection collection = database.getCollection(CollectionNames.GPS_FIXES_METADATA.name()); - DBObject index = new BasicDBObject(); - index.put(FieldNames.DEVICE_ID.name(), null); - collection.createIndex(index); - return collection; - } - - /** - * @param regattaName - * the regatta name is stored only for human readability purposes because a time stamp may be a bit unhandy for - * identifying where the wind fix was collected - */ - public DBObject storeWindTrackEntry(RaceDefinition race, String regattaName, WindSource windSource, Wind wind) { - BasicDBObject result = new BasicDBObject(); - result.put(FieldNames.RACE_ID.name(), race.getId()); - result.put(FieldNames.REGATTA_NAME.name(), regattaName); - result.put(FieldNames.WIND_SOURCE_NAME.name(), windSource.name()); - if (windSource.getId() != null) { - result.put(FieldNames.WIND_SOURCE_ID.name(), windSource.getId()); - } - result.put(FieldNames.WIND.name(), storeWind(wind)); - return result; - } - - private void storeRaceIdentifiers(RaceColumn raceColumn, DBObject dbObject) { - BasicDBObject raceIdentifiersPerFleet = new BasicDBObject(); - for (Fleet fleet : raceColumn.getFleets()) { - RaceIdentifier raceIdentifier = raceColumn.getRaceIdentifier(fleet); - if (raceIdentifier != null) { - DBObject raceIdentifierForFleet = new BasicDBObject(); - storeRaceIdentifier(raceIdentifierForFleet, raceIdentifier); - raceIdentifiersPerFleet.put(MongoUtils.escapeDollarAndDot(fleet.getName()), raceIdentifierForFleet); - } - } - dbObject.put(FieldNames.RACE_IDENTIFIERS.name(), raceIdentifiersPerFleet); - } - - private void storeRaceIdentifier(DBObject dbObject, RaceIdentifier raceIdentifier) { - if (raceIdentifier != null) { - dbObject.put(FieldNames.EVENT_NAME.name(), raceIdentifier.getRegattaName()); - dbObject.put(FieldNames.RACE_NAME.name(), raceIdentifier.getRaceName()); - } - } - - @Override - public void storeLeaderboard(Leaderboard leaderboard) { - DBCollection leaderboardCollection = database.getCollection(CollectionNames.LEADERBOARDS.name()); - try { - leaderboardCollection.createIndex(new BasicDBObject(FieldNames.LEADERBOARD_NAME.name(), 1)); - } catch (NullPointerException npe) { - // sometimes, for reasons yet to be clarified, ensuring an index on the name field causes an NPE - logger.log(Level.SEVERE, "storeLeaderboard", npe); - } - BasicDBObject query = new BasicDBObject(FieldNames.LEADERBOARD_NAME.name(), leaderboard.getName()); - BasicDBObject dbLeaderboard = new BasicDBObject(); - dbLeaderboard.put(FieldNames.LEADERBOARD_NAME.name(), leaderboard.getName()); - if (leaderboard.getDisplayName() != null) { - dbLeaderboard.put(FieldNames.LEADERBOARD_DISPLAY_NAME.name(), leaderboard.getDisplayName()); - } - BasicDBList dbSuppressedCompetitorIds = new BasicDBList(); - for (Competitor suppressedCompetitor : leaderboard.getSuppressedCompetitors()) { - dbSuppressedCompetitorIds.add(suppressedCompetitor.getId()); - } - dbLeaderboard.put(FieldNames.LEADERBOARD_SUPPRESSED_COMPETITOR_IDS.name(), dbSuppressedCompetitorIds); - if (leaderboard instanceof FlexibleLeaderboard) { - storeFlexibleLeaderboard((FlexibleLeaderboard) leaderboard, dbLeaderboard); - } else if (leaderboard instanceof RegattaLeaderboard) { - storeRegattaLeaderboard((RegattaLeaderboard) leaderboard, dbLeaderboard); - } else { - // at least store the scoring scheme - dbLeaderboard.put(FieldNames.SCORING_SCHEME_TYPE.name(), leaderboard.getScoringScheme().getType().name()); - } - if (leaderboard.getDefaultCourseArea() != null) { - dbLeaderboard.put(FieldNames.COURSE_AREA_ID.name(), leaderboard.getDefaultCourseArea().getId().toString()); - } else { - dbLeaderboard.put(FieldNames.COURSE_AREA_ID.name(), null); - } - storeColumnFactors(leaderboard, dbLeaderboard); - storeLeaderboardCorrectionsAndDiscards(leaderboard, dbLeaderboard); - leaderboardCollection.update(query, dbLeaderboard, /* upsrt */ true, /* multi */ false, WriteConcern.SAFE); - } - - private void storeColumnFactors(Leaderboard leaderboard, BasicDBObject dbLeaderboard) { - DBObject raceColumnFactors = new BasicDBObject(); - for (RaceColumn raceColumn : leaderboard.getRaceColumns()) { - Double explicitFactor = raceColumn.getExplicitFactor(); - if (explicitFactor != null) { - raceColumnFactors.put(MongoUtils.escapeDollarAndDot(raceColumn.getName()), explicitFactor); - } - } - dbLeaderboard.put(FieldNames.LEADERBOARD_COLUMN_FACTORS.name(), raceColumnFactors); - } - - private void storeRegattaLeaderboard(RegattaLeaderboard leaderboard, DBObject dbLeaderboard) { - dbLeaderboard.put(FieldNames.REGATTA_NAME.name(), leaderboard.getRegatta().getName()); - } - - private void storeFlexibleLeaderboard(FlexibleLeaderboard leaderboard, BasicDBObject dbLeaderboard) { - BasicDBList dbRaceColumns = new BasicDBList(); - dbLeaderboard.put(FieldNames.SCORING_SCHEME_TYPE.name(), leaderboard.getScoringScheme().getType().name()); - dbLeaderboard.put(FieldNames.LEADERBOARD_COLUMNS.name(), dbRaceColumns); - for (RaceColumn raceColumn : leaderboard.getRaceColumns()) { - BasicDBObject dbRaceColumn = storeRaceColumn(raceColumn); - dbRaceColumns.add(dbRaceColumn); - } - } - - private void storeLeaderboardCorrectionsAndDiscards(Leaderboard leaderboard, BasicDBObject dbLeaderboard) { - if (leaderboard.hasCarriedPoints()) { - BasicDBList dbCarriedPoints = new BasicDBList(); - dbLeaderboard.put(FieldNames.LEADERBOARD_CARRIED_POINTS_BY_ID.name(), dbCarriedPoints); - for (Entry competitorWithCarriedPoints : leaderboard - .getCompetitorsForWhichThereAreCarriedPoints().entrySet()) { - double carriedPoints = competitorWithCarriedPoints.getValue(); - Competitor competitor = competitorWithCarriedPoints.getKey(); - DBObject dbCarriedPointsForCompetitor = new BasicDBObject(); - dbCarriedPointsForCompetitor.put(FieldNames.COMPETITOR_ID.name(), competitor.getId()); - dbCarriedPointsForCompetitor.put(FieldNames.LEADERBOARD_CARRIED_POINTS.name(), carriedPoints); - dbCarriedPoints.add(dbCarriedPointsForCompetitor); - } - } - BasicDBObject dbScoreCorrections = new BasicDBObject(); - storeScoreCorrections(leaderboard, dbScoreCorrections); - dbLeaderboard.put(FieldNames.LEADERBOARD_SCORE_CORRECTIONS.name(), dbScoreCorrections); - final ResultDiscardingRule resultDiscardingRule = leaderboard.getResultDiscardingRule(); - storeResultDiscardingRule(dbLeaderboard, resultDiscardingRule, FieldNames.LEADERBOARD_DISCARDING_THRESHOLDS); - BasicDBList competitorDisplayNames = new BasicDBList(); - for (Competitor competitor : leaderboard.getCompetitors()) { - String displayNameForCompetitor = leaderboard.getDisplayName(competitor); - if (displayNameForCompetitor != null) { - DBObject dbDisplayName = new BasicDBObject(); - dbDisplayName.put(FieldNames.COMPETITOR_ID.name(), competitor.getId()); - dbDisplayName.put(FieldNames.COMPETITOR_DISPLAY_NAME.name(), displayNameForCompetitor); - competitorDisplayNames.add(dbDisplayName); - } - } - dbLeaderboard.put(FieldNames.LEADERBOARD_COMPETITOR_DISPLAY_NAMES.name(), competitorDisplayNames); - } - - /** - * Stores the result discarding rule to dbObject's field identified by field if the result discarding - * rule is not null and is of type {@link ThresholdBasedResultDiscardingRule}. Otherwise, it is assumed that the - * result discarding rule is otherwise implicitly obtained, e.g., from a definition of a regatta with its series, stored elsewhere. - */ - private void storeResultDiscardingRule(DBObject dbObject, - final ResultDiscardingRule resultDiscardingRule, FieldNames field) { - if (resultDiscardingRule != null && resultDiscardingRule instanceof ThresholdBasedResultDiscardingRule) { - BasicDBList dbResultDiscardingThresholds = new BasicDBList(); - for (int threshold : ((ThresholdBasedResultDiscardingRule) resultDiscardingRule).getDiscardIndexResultsStartingWithHowManyRaces()) { - dbResultDiscardingThresholds.add(threshold); - } - dbObject.put(field.name(), dbResultDiscardingThresholds); - } - } - - private BasicDBObject storeRaceColumn(RaceColumn raceColumn) { - BasicDBObject dbRaceColumn = new BasicDBObject(); - dbRaceColumn.put(FieldNames.LEADERBOARD_COLUMN_NAME.name(), raceColumn.getName()); - dbRaceColumn.put(FieldNames.LEADERBOARD_IS_MEDAL_RACE_COLUMN.name(), raceColumn.isMedalRace()); - storeRaceIdentifiers(raceColumn, dbRaceColumn); - return dbRaceColumn; - } - - private void storeScoreCorrections(Leaderboard leaderboard, BasicDBObject dbScoreCorrections) { - TimePoint now = MillisecondsTimePoint.now(); - SettableScoreCorrection scoreCorrection = leaderboard.getScoreCorrection(); - for (RaceColumn raceColumn : scoreCorrection.getRaceColumnsThatHaveCorrections()) { - BasicDBList dbCorrectionForRace = new BasicDBList(); - for (Competitor competitor : scoreCorrection.getCompetitorsThatHaveCorrectionsIn(raceColumn)) { - // TODO bug 655: make score corrections time dependent - if (scoreCorrection.isScoreCorrected(competitor, raceColumn, now)) { - BasicDBObject dbCorrectionForCompetitor = new BasicDBObject(); - dbCorrectionForCompetitor.put(FieldNames.COMPETITOR_ID.name(), competitor.getId()); - MaxPointsReason maxPointsReason = scoreCorrection.getMaxPointsReason(competitor, raceColumn, now); - if (maxPointsReason != MaxPointsReason.NONE) { - dbCorrectionForCompetitor.put(FieldNames.LEADERBOARD_SCORE_CORRECTION_MAX_POINTS_REASON.name(), - maxPointsReason.name()); - } - Double explicitScoreCorrection = scoreCorrection - .getExplicitScoreCorrection(competitor, raceColumn); - if (explicitScoreCorrection != null) { - dbCorrectionForCompetitor.put(FieldNames.LEADERBOARD_CORRECTED_SCORE.name(), - explicitScoreCorrection); - } - dbCorrectionForRace.add(dbCorrectionForCompetitor); - } - } - if (!dbCorrectionForRace.isEmpty()) { - // using the column name as the key for the score corrections requires re-writing the score corrections - // of a meta-leaderboard if the name of one of its leaderboards changes - dbScoreCorrections.put(MongoUtils.escapeDollarAndDot(raceColumn.getName()), dbCorrectionForRace); - } - } - final TimePoint timePointOfLastCorrectionsValidity = scoreCorrection.getTimePointOfLastCorrectionsValidity(); - if (timePointOfLastCorrectionsValidity != null) { - dbScoreCorrections.put(FieldNames.LEADERBOARD_SCORE_CORRECTION_TIMESTAMP.name(), timePointOfLastCorrectionsValidity.asMillis()); - } - if (scoreCorrection.getComment() != null) { - dbScoreCorrections.put(FieldNames.LEADERBOARD_SCORE_CORRECTION_COMMENT.name(), scoreCorrection.getComment()); - } - } - - @Override - public void removeLeaderboard(String leaderboardName) { - DBCollection leaderboardCollection = database.getCollection(CollectionNames.LEADERBOARDS.name()); - BasicDBObject query = new BasicDBObject(FieldNames.LEADERBOARD_NAME.name(), leaderboardName); - leaderboardCollection.remove(query); - } - - @Override - public void renameLeaderboard(String oldName, String newName) { - DBCollection leaderboardCollection = database.getCollection(CollectionNames.LEADERBOARDS.name()); - BasicDBObject query = new BasicDBObject(FieldNames.LEADERBOARD_NAME.name(), oldName); - BasicDBObject renameUpdate = new BasicDBObject("$set", new BasicDBObject(FieldNames.LEADERBOARD_NAME.name(), newName)); - leaderboardCollection.update(query, renameUpdate, /* upsert */ true, /* multi */ false, WriteConcern.SAFE); - } - - @Override - public void storeLeaderboardGroup(LeaderboardGroup leaderboardGroup) { - DBCollection leaderboardGroupCollection = database.getCollection(CollectionNames.LEADERBOARD_GROUPS.name()); - DBCollection leaderboardCollection = database.getCollection(CollectionNames.LEADERBOARDS.name()); - - try { - leaderboardGroupCollection.createIndex(new BasicDBObject(FieldNames.LEADERBOARD_GROUP_NAME.name(), 1)); - } catch (NullPointerException npe) { - // sometimes, for reasons yet to be clarified, ensuring an index on the name field causes an NPE - logger.log(Level.SEVERE, "storeLeaderboardGroup", npe); - } - BasicDBObject query = new BasicDBObject(FieldNames.LEADERBOARD_GROUP_NAME.name(), leaderboardGroup.getName()); - BasicDBObject dbLeaderboardGroup = new BasicDBObject(); - dbLeaderboardGroup.put(FieldNames.LEADERBOARD_GROUP_UUID.name(), leaderboardGroup.getId()); - dbLeaderboardGroup.put(FieldNames.LEADERBOARD_GROUP_NAME.name(), leaderboardGroup.getName()); - dbLeaderboardGroup.put(FieldNames.LEADERBOARD_GROUP_DESCRIPTION.name(), leaderboardGroup.getDescription()); - dbLeaderboardGroup.put(FieldNames.LEADERBOARD_GROUP_DISPLAY_NAME.name(), leaderboardGroup.getDisplayName()); - dbLeaderboardGroup.put(FieldNames.LEADERBOARD_GROUP_DISPLAY_IN_REVERSE_ORDER.name(), leaderboardGroup.isDisplayGroupsInReverseOrder()); - final Leaderboard overallLeaderboard = leaderboardGroup.getOverallLeaderboard(); - if (overallLeaderboard != null) { - BasicDBObject overallLeaderboardQuery = new BasicDBObject(FieldNames.LEADERBOARD_NAME.name(), overallLeaderboard.getName()); - DBObject dbOverallLeaderboard = leaderboardCollection.findOne(overallLeaderboardQuery); - if (dbOverallLeaderboard == null) { - storeLeaderboard(overallLeaderboard); - dbOverallLeaderboard = leaderboardCollection.findOne(overallLeaderboardQuery); - } - ObjectId dbOverallLeaderboardId = (ObjectId) dbOverallLeaderboard.get("_id"); - dbLeaderboardGroup.put(FieldNames.LEADERBOARD_GROUP_OVERALL_LEADERBOARD.name(), dbOverallLeaderboardId); - } - BasicDBList dbLeaderboardIds = new BasicDBList(); - for (Leaderboard leaderboard : leaderboardGroup.getLeaderboards()) { - BasicDBObject leaderboardQuery = new BasicDBObject(FieldNames.LEADERBOARD_NAME.name(), leaderboard.getName()); - DBObject dbLeaderboard = leaderboardCollection.findOne(leaderboardQuery); - if (dbLeaderboard == null) { - storeLeaderboard(leaderboard); - dbLeaderboard = leaderboardCollection.findOne(leaderboardQuery); - } - ObjectId dbLeaderboardId = (ObjectId) dbLeaderboard.get("_id"); - dbLeaderboardIds.add(dbLeaderboardId); - } - dbLeaderboardGroup.put(FieldNames.LEADERBOARD_GROUP_LEADERBOARDS.name(), dbLeaderboardIds); - leaderboardGroupCollection.update(query, dbLeaderboardGroup, true, false, WriteConcern.SAFE); - } - - @Override - public void removeLeaderboardGroup(String groupName) { - DBCollection leaderboardGroupCollection = database.getCollection(CollectionNames.LEADERBOARD_GROUPS.name()); - BasicDBObject query = new BasicDBObject(FieldNames.LEADERBOARD_GROUP_NAME.name(), groupName); - leaderboardGroupCollection.remove(query); - } - - @Override - public void renameLeaderboardGroup(String oldName, String newName) { - DBCollection leaderboardGroupCollection = database.getCollection(CollectionNames.LEADERBOARD_GROUPS.name()); - BasicDBObject query = new BasicDBObject(FieldNames.LEADERBOARD_GROUP_NAME.name(), oldName); - BasicDBObject update = new BasicDBObject("$set", new BasicDBObject(FieldNames.LEADERBOARD_GROUP_NAME.name(), newName)); - leaderboardGroupCollection.update(query, update, /* upsert */ true, /* multi */ false, WriteConcern.SAFE); - } - - @Override - public void storeServerConfiguration(SailingServerConfiguration serverConfiguration) { - DBCollection serverCollection = database.getCollection(CollectionNames.SERVER_CONFIGURATION.name()); - DBObject newServerConfig = new BasicDBObject(); - newServerConfig.put(FieldNames.SERVER_IS_STANDALONE.name(), serverConfiguration.isStandaloneServer()); - DBObject currentServerConfig = serverCollection.findOne(); - if(currentServerConfig != null) { - serverCollection.update(currentServerConfig, newServerConfig, /* upsrt */ true, /* multi */ false, WriteConcern.SAFE); - } else { - serverCollection.save(newServerConfig); - } - } - - @Override - public void storeSailingServer(RemoteSailingServerReference server) { - DBCollection serverCollection = database.getCollection(CollectionNames.SAILING_SERVERS.name()); - serverCollection.createIndex(new BasicDBObject(FieldNames.SERVER_NAME.name(), 1)); - DBObject query = new BasicDBObject(); - query.put(FieldNames.SERVER_NAME.name(), server.getName()); - DBObject serverDBObject = new BasicDBObject(); - serverDBObject.put(FieldNames.SERVER_NAME.name(), server.getName()); - serverDBObject.put(FieldNames.SERVER_URL.name(), server.getURL().toExternalForm()); - serverCollection.update(query, serverDBObject, /* upsrt */ true, /* multi */ false, WriteConcern.SAFE); - } - - @Override - public void removeSailingServer(String name) { - DBCollection serverCollection = database.getCollection(CollectionNames.SAILING_SERVERS.name()); - BasicDBObject query = new BasicDBObject(FieldNames.SERVER_NAME.name(), name); - serverCollection.remove(query); - } - - /** - * StoreEvent() uses some deprecated methods of event to keep backward compatibility. - */ - @SuppressWarnings("deprecation") - @Override - public void storeEvent(Event event) { - DBCollection eventCollection = database.getCollection(CollectionNames.EVENTS.name()); - eventCollection.createIndex(new BasicDBObject(FieldNames.EVENT_ID.name(), 1)); - DBObject query = new BasicDBObject(); - query.put(FieldNames.EVENT_ID.name(), event.getId()); - DBObject eventDBObject = new BasicDBObject(); - eventDBObject.put(FieldNames.EVENT_NAME.name(), event.getName()); - eventDBObject.put(FieldNames.EVENT_DESCRIPTION.name(), event.getDescription()); - eventDBObject.put(FieldNames.EVENT_ID.name(), event.getId()); - eventDBObject.put(FieldNames.EVENT_LOGO_IMAGE_URL.name(), event.getLogoImageURL() != null ? event.getLogoImageURL().toString() : null); - eventDBObject.put(FieldNames.EVENT_OFFICIAL_WEBSITE_URL.name(), event.getOfficialWebsiteURL() != null ? event.getOfficialWebsiteURL().toString() : null); - eventDBObject.put(FieldNames.EVENT_SAILORS_INFO_WEBSITE_URL.name(), event.getSailorsInfoWebsiteURL() != null ? event.getSailorsInfoWebsiteURL().toString() : null); - storeTimePoint(event.getStartDate(), eventDBObject, FieldNames.EVENT_START_DATE); - storeTimePoint(event.getEndDate(), eventDBObject, FieldNames.EVENT_END_DATE); - eventDBObject.put(FieldNames.EVENT_IS_PUBLIC.name(), event.isPublic()); - DBObject venueDBObject = getVenueAsDBObject(event.getVenue()); - eventDBObject.put(FieldNames.VENUE.name(), venueDBObject); - BasicDBList imageURLs = new BasicDBList(); - for (URL imageURL : event.getImageURLs()) { - imageURLs.add(imageURL.toString()); - } - eventDBObject.put(FieldNames.EVENT_IMAGE_URLS.name(), imageURLs); - BasicDBList videoURLs = new BasicDBList(); - for (URL videoURL : event.getVideoURLs()) { - videoURLs.add(videoURL.toString()); - } - eventDBObject.put(FieldNames.EVENT_VIDEO_URLS.name(), videoURLs); - BasicDBList sponsorImageURLs = new BasicDBList(); - for (URL sponsorImageURL : event.getSponsorImageURLs()) { - sponsorImageURLs.add(sponsorImageURL.toString()); - } - eventDBObject.put(FieldNames.EVENT_SPONSOR_IMAGE_URLS.name(), sponsorImageURLs); - BasicDBList images = new BasicDBList(); - for (ImageDescriptor image : event.getImages()) { - DBObject imageObject = createImageObject(image); - images.add(imageObject); - } - eventDBObject.put(FieldNames.EVENT_IMAGES.name(), images); - BasicDBList videos = new BasicDBList(); - for (VideoDescriptor video: event.getVideos()) { - DBObject videoObject = createVideoObject(video); - videos.add(videoObject); - } - eventDBObject.put(FieldNames.EVENT_VIDEOS.name(), videos); - eventCollection.update(query, eventDBObject, /* upsrt */ true, /* multi */ false, WriteConcern.SAFE); - // now store the links to the leaderboard groups - DBCollection linksCollection = database.getCollection(CollectionNames.LEADERBOARD_GROUP_LINKS_FOR_EVENTS.name()); - linksCollection.createIndex(new BasicDBObject(FieldNames.EVENT_ID.name(), 1)); - BasicDBList lgUUIDs = new BasicDBList(); - for (LeaderboardGroup lg : event.getLeaderboardGroups()) { - lgUUIDs.add(lg.getId()); - } - DBObject dbLinks = new BasicDBObject(); - dbLinks.put(FieldNames.EVENT_ID.name(), event.getId()); - dbLinks.put(FieldNames.LEADERBOARD_GROUP_UUID.name(), lgUUIDs); - linksCollection.update(query, dbLinks, /* upsrt */ true, /* multi */ false, WriteConcern.SAFE); - } - - @Override - public void renameEvent(Serializable id, String newName) { - DBCollection eventCollection = database.getCollection(CollectionNames.EVENTS.name()); - BasicDBObject query = new BasicDBObject(FieldNames.EVENT_ID.name(), id); - BasicDBObject renameUpdate = new BasicDBObject("$set", new BasicDBObject(FieldNames.EVENT_NAME.name(), newName)); - eventCollection.update(query, renameUpdate, /* upsert */ true, /* multi */ false, WriteConcern.SAFE); - } - - @Override - public void removeEvent(Serializable id) { - DBCollection eventsCollection = database.getCollection(CollectionNames.EVENTS.name()); - BasicDBObject query = new BasicDBObject(FieldNames.EVENT_ID.name(), id); - eventsCollection.remove(query); - } - - private DBObject getVenueAsDBObject(Venue venue) { - DBObject result = new BasicDBObject(); - result.put(FieldNames.VENUE_NAME.name(), venue.getName()); - BasicDBList courseAreaList = new BasicDBList(); - result.put(FieldNames.COURSE_AREAS.name(), courseAreaList); - for (CourseArea courseArea : venue.getCourseAreas()) { - DBObject dbCourseArea = new BasicDBObject(); - courseAreaList.add(dbCourseArea); - dbCourseArea.put(FieldNames.COURSE_AREA_NAME.name(), courseArea.getName()); - dbCourseArea.put(FieldNames.COURSE_AREA_ID.name(), courseArea.getId()); - } - return result; - } - - @Override - public void storeRegatta(Regatta regatta) { - DBCollection regattasCollection = database.getCollection(CollectionNames.REGATTAS.name()); - regattasCollection.createIndex(new BasicDBObject(FieldNames.REGATTA_NAME.name(), 1)); - regattasCollection.createIndex(new BasicDBObject(FieldNames.REGATTA_ID.name(), 1)); - DBObject dbRegatta = new BasicDBObject(); - DBObject query = new BasicDBObject(FieldNames.REGATTA_NAME.name(), regatta.getName()); - dbRegatta.put(FieldNames.REGATTA_NAME.name(), regatta.getName()); - dbRegatta.put(FieldNames.REGATTA_ID.name(), regatta.getId()); - storeTimePoint(regatta.getStartDate(), dbRegatta, FieldNames.REGATTA_START_DATE); - storeTimePoint(regatta.getEndDate(), dbRegatta, FieldNames.REGATTA_END_DATE); - dbRegatta.put(FieldNames.SCORING_SCHEME_TYPE.name(), regatta.getScoringScheme().getType().name()); - if (regatta.getBoatClass() != null) { - dbRegatta.put(FieldNames.BOAT_CLASS_NAME.name(), regatta.getBoatClass().getName()); - dbRegatta.put(FieldNames.BOAT_CLASS_TYPICALLY_STARTS_UPWIND.name(), regatta.getBoatClass().typicallyStartsUpwind()); - } - dbRegatta.put(FieldNames.REGATTA_SERIES.name(), storeSeries(regatta.getSeries())); - - if (regatta.getDefaultCourseArea() != null) { - dbRegatta.put(FieldNames.COURSE_AREA_ID.name(), regatta.getDefaultCourseArea().getId().toString()); - } else { - dbRegatta.put(FieldNames.COURSE_AREA_ID.name(), null); - } - if (regatta.getRegattaConfiguration() != null) { - JsonSerializer serializer = RegattaConfigurationJsonSerializer.create(); - JSONObject json = serializer.serialize(regatta.getRegattaConfiguration()); - DBObject configurationObject = (DBObject) JSON.parse(json.toString()); - dbRegatta.put(FieldNames.REGATTA_REGATTA_CONFIGURATION.name(), configurationObject); - } - dbRegatta.put(FieldNames.REGATTA_USE_START_TIME_INFERENCE.name(), regatta.useStartTimeInference()); - dbRegatta.put(FieldNames.REGATTA_RANKING_METRIC.name(), storeRankingMetric(regatta)); - regattasCollection.update(query, dbRegatta, /* upsrt */ true, /* multi */ false, WriteConcern.SAFE); - } - - private DBObject storeRankingMetric(Regatta regatta) { - DBObject rankingMetricJson = new BasicDBObject(); - final String rankingMetricTypeName = regatta.getRankingMetricType().name(); - rankingMetricJson.put(FieldNames.REGATTA_RANKING_METRIC_TYPE.name(), rankingMetricTypeName); - return rankingMetricJson; - } - - @Override - public void removeRegatta(Regatta regatta) { - DBCollection regattasCollection = database.getCollection(CollectionNames.REGATTAS.name()); - DBObject query = new BasicDBObject(FieldNames.REGATTA_NAME.name(), regatta.getName()); - regattasCollection.remove(query); - } - - private BasicDBList storeSeries(Iterable series) { - BasicDBList dbSeries = new BasicDBList(); - for (Series s : series) { - dbSeries.add(storeSeries(s)); - } - return dbSeries; - } - - private DBObject storeSeries(Series s) { - DBObject dbSeries = new BasicDBObject(); - dbSeries.put(FieldNames.SERIES_NAME.name(), s.getName()); - dbSeries.put(FieldNames.SERIES_IS_MEDAL.name(), s.isMedal()); - dbSeries.put(FieldNames.SERIES_HAS_SPLIT_FLEET_CONTIGUOUS_SCORING.name(), s.hasSplitFleetContiguousScoring()); - dbSeries.put(FieldNames.SERIES_STARTS_WITH_ZERO_SCORE.name(), s.isStartsWithZeroScore()); - dbSeries.put(FieldNames.SERIES_STARTS_WITH_NON_DISCARDABLE_CARRY_FORWARD.name(), s.isFirstColumnIsNonDiscardableCarryForward()); - BasicDBList dbFleets = new BasicDBList(); - for (Fleet fleet : s.getFleets()) { - dbFleets.add(storeFleet(fleet)); - } - dbSeries.put(FieldNames.SERIES_FLEETS.name(), dbFleets); - BasicDBList dbRaceColumns = new BasicDBList(); - for (RaceColumn raceColumn : s.getRaceColumns()) { - dbRaceColumns.add(storeRaceColumn(raceColumn)); - } - dbSeries.put(FieldNames.SERIES_RACE_COLUMNS.name(), dbRaceColumns); - if (s.getResultDiscardingRule() != null) { - storeResultDiscardingRule(dbSeries, s.getResultDiscardingRule(), FieldNames.SERIES_DISCARDING_THRESHOLDS); - } - return dbSeries; - } - - private DBObject storeFleet(Fleet fleet) { - DBObject dbFleet = new BasicDBObject(FieldNames.FLEET_NAME.name(), fleet.getName()); - if (fleet instanceof FleetImpl) { - dbFleet.put(FieldNames.FLEET_ORDERING.name(), ((FleetImpl) fleet).getOrdering()); - if(fleet.getColor() != null) { - com.sap.sse.common.Util.Triple colorAsRGB = fleet.getColor().getAsRGB(); - // we save the color as a integer value representing the RGB values - int colorAsInt = (256 * 256 * colorAsRGB.getC()) + colorAsRGB.getB() * 256 + colorAsRGB.getA(); - dbFleet.put(FieldNames.FLEET_COLOR.name(), colorAsInt); - } else { - dbFleet.put(FieldNames.FLEET_COLOR.name(), null); - } - } - return dbFleet; - } - - @Override - public void storeRegattaForRaceID(String raceIDAsString, Regatta regatta) { - DBCollection regattaForRaceIDCollection = database.getCollection(CollectionNames.REGATTA_FOR_RACE_ID.name()); - DBObject query = new BasicDBObject(FieldNames.RACE_ID_AS_STRING.name(), raceIDAsString); - DBObject entry = new BasicDBObject(FieldNames.RACE_ID_AS_STRING.name(), raceIDAsString); - entry.put(FieldNames.REGATTA_NAME.name(), regatta.getName()); - regattaForRaceIDCollection.update(query, entry, /* upsrt */ true, /* multi */ false, WriteConcern.SAFE); - } - - @Override - public void removeRegattaForRaceID(String raceIDAsString, Regatta regatta) { - DBCollection regattaForRaceIDCollection = database.getCollection(CollectionNames.REGATTA_FOR_RACE_ID.name()); - DBObject query = new BasicDBObject(FieldNames.RACE_ID_AS_STRING.name(), raceIDAsString); - regattaForRaceIDCollection.remove(query); - } - - public DBCollection getRaceLogCollection() { - DBCollection result = database.getCollection(CollectionNames.RACE_LOGS.name()); - result.createIndex(new BasicDBObject(FieldNames.RACE_LOG_IDENTIFIER.name(), null)); - return result; - } - - private void storeRaceLogEventAuthor(DBObject dbObject, AbstractLogEventAuthor author) { - if (author != null) { - dbObject.put(FieldNames.RACE_LOG_EVENT_AUTHOR_NAME.name(), author.getName()); - dbObject.put(FieldNames.RACE_LOG_EVENT_AUTHOR_PRIORITY.name(), author.getPriority()); - } - } - - public DBObject storeRaceLogEntry(RaceLogIdentifier raceLogIdentifier, RaceLogFlagEvent flagEvent) { - BasicDBObject result = new BasicDBObject(); - storeRaceLogIdentifier(raceLogIdentifier, result); - result.put(FieldNames.RACE_LOG_EVENT.name(), storeRaceLogFlagEvent(flagEvent)); - return result; - } - - private void storeRaceLogIdentifier(RaceLogIdentifier raceLogIdentifier, DBObject result) { - result.put(FieldNames.RACE_LOG_IDENTIFIER.name(), TripleSerializer.serialize(raceLogIdentifier.getIdentifier())); - } - - public DBObject storeRaceLogEntry(RaceLogIdentifier raceLogIdentifier, RaceLogStartTimeEvent startTimeEvent) { - BasicDBObject result = new BasicDBObject(); - storeRaceLogIdentifier(raceLogIdentifier, result); - result.put(FieldNames.RACE_LOG_EVENT.name(), storeRaceLogStartTimeEvent(startTimeEvent)); - return result; - } - - public DBObject storeRaceLogEntry(RaceLogIdentifier raceLogIdentifier, RaceLogPassChangeEvent passChangeEvent) { - BasicDBObject result = new BasicDBObject(); - storeRaceLogIdentifier(raceLogIdentifier, result); - result.put(FieldNames.RACE_LOG_EVENT.name(), storeRaceLogPassChangeEvent(passChangeEvent)); - return result; - } - - public DBObject storeRaceLogEntry(RaceLogIdentifier raceLogIdentifier, RaceLogRaceStatusEvent raceStatusEvent) { - BasicDBObject result = new BasicDBObject(); - storeRaceLogIdentifier(raceLogIdentifier, result); - result.put(FieldNames.RACE_LOG_EVENT.name(), storeRaceLogRaceStatusEvent(raceStatusEvent)); - return result; - } - - public DBObject storeRaceLogEntry(RaceLogIdentifier raceLogIdentifier, RaceLogCourseAreaChangedEvent courseAreaChangedEvent) { - BasicDBObject result = new BasicDBObject(); - storeRaceLogIdentifier(raceLogIdentifier, result); - result.put(FieldNames.RACE_LOG_EVENT.name(), storeRaceLogCourseAreaChangedEvent(courseAreaChangedEvent)); - return result; - } - - public DBObject storeRaceLogEntry(RaceLogIdentifier raceLogIdentifier, RaceLogCourseDesignChangedEvent courseDesignChangedEvent) { - BasicDBObject result = new BasicDBObject(); - storeRaceLogIdentifier(raceLogIdentifier, result); - result.put(FieldNames.RACE_LOG_EVENT.name(), storeRaceLogCourseDesignChangedEvent(courseDesignChangedEvent)); - return result; - } - - public DBObject storeRaceLogEntry(RaceLogIdentifier raceLogIdentifier, RaceLogFinishPositioningListChangedEvent finishPositioningListChangedEvent) { - BasicDBObject result = new BasicDBObject(); - storeRaceLogIdentifier(raceLogIdentifier, result); - result.put(FieldNames.RACE_LOG_EVENT.name(), storeRaceLogFinishPositioningListChangedEvent(finishPositioningListChangedEvent)); - return result; - } - - public DBObject storeRaceLogEntry(RaceLogIdentifier raceLogIdentifier, RaceLogFinishPositioningConfirmedEvent finishPositioningConfirmedEvent) { - BasicDBObject result = new BasicDBObject(); - storeRaceLogIdentifier(raceLogIdentifier, result); - result.put(FieldNames.RACE_LOG_EVENT.name(), storeRaceLogFinishPositioningConfirmedEvent(finishPositioningConfirmedEvent)); - return result; - } - - public DBObject storeRaceLogEntry(RaceLogIdentifier raceLogIdentifier, RaceLogPathfinderEvent pathfinderEvent) { - BasicDBObject result = new BasicDBObject(); - storeRaceLogIdentifier(raceLogIdentifier, result); - result.put(FieldNames.RACE_LOG_EVENT.name(), storeRaceLogPathfinderEvent(pathfinderEvent)); - return result; - } - - public DBObject storeRaceLogEntry(RaceLogIdentifier raceLogIdentifier, RaceLogGateLineOpeningTimeEvent gateLineOpeningTimeEvent) { - BasicDBObject result = new BasicDBObject(); - storeRaceLogIdentifier(raceLogIdentifier, result); - result.put(FieldNames.RACE_LOG_EVENT.name(), storeRaceLogGateLineOpeningTimeEvent(gateLineOpeningTimeEvent)); - return result; - } - - public DBObject storeRaceLogEntry(RaceLogIdentifier raceLogIdentifier, RaceLogStartProcedureChangedEvent event) { - DBObject result = new BasicDBObject(); - storeRaceLogIdentifier(raceLogIdentifier, result); - result.put(FieldNames.RACE_LOG_EVENT.name(), storeRaceLogStartProcedureChangedEvent(event)); - return result; - } - - public DBObject storeRaceLogEntry(RaceLogIdentifier raceLogIdentifier, RaceLogProtestStartTimeEvent event) { - DBObject result = new BasicDBObject(); - storeRaceLogIdentifier(raceLogIdentifier, result); - result.put(FieldNames.RACE_LOG_EVENT.name(), storeRaceLogProtestStartTimeEvent(event)); - return result; - } - - public DBObject storeRaceLogEntry(RaceLogIdentifier raceLogIdentifier, RaceLogWindFixEvent event) { - DBObject result = new BasicDBObject(); - storeRaceLogIdentifier(raceLogIdentifier, result); - result.put(FieldNames.RACE_LOG_EVENT.name(), storeRaceLogWindFix(event)); - return result; - } - - public DBObject storeRaceLogEntry(RaceLogIdentifier raceLogIdentifier, RaceLogDeviceCompetitorMappingEvent event) { - BasicDBObject result = new BasicDBObject(); - storeRaceLogIdentifier(raceLogIdentifier, result); - result.put(FieldNames.RACE_LOG_EVENT.name(), storeRaceLogDeviceCompetitorMappingEvent(event)); - return result; - } - - public DBObject storeRaceLogEntry(RaceLogIdentifier raceLogIdentifier, RaceLogDeviceMarkMappingEvent event) { - BasicDBObject result = new BasicDBObject(); - storeRaceLogIdentifier(raceLogIdentifier, result); - result.put(FieldNames.RACE_LOG_EVENT.name(), storeRaceLogDeviceMarkMappingEvent(event)); - return result; - } - - public DBObject storeRaceLogEntry(RaceLogIdentifier raceLogIdentifier, RaceLogDenoteForTrackingEvent event) { - BasicDBObject result = new BasicDBObject(); - storeRaceLogIdentifier(raceLogIdentifier, result); - result.put(FieldNames.RACE_LOG_EVENT.name(), storeRaceLogDenoteForTrackingEvent(event)); - return result; - } - - public DBObject storeRaceLogEntry(RaceLogIdentifier raceLogIdentifier, RaceLogStartTrackingEvent event) { - BasicDBObject result = new BasicDBObject(); - storeRaceLogIdentifier(raceLogIdentifier, result); - result.put(FieldNames.RACE_LOG_EVENT.name(), storeRaceLogStartTrackingEvent(event)); - return result; - } - - public DBObject storeRaceLogEntry(RaceLogIdentifier raceLogIdentifier, RaceLogRevokeEvent event) { - BasicDBObject result = new BasicDBObject(); - storeRaceLogIdentifier(raceLogIdentifier, result); - result.put(FieldNames.RACE_LOG_EVENT.name(), storeRaceLogRevokeEvent(event)); - return result; - } - - public DBObject storeRaceLogEntry(RaceLogIdentifier raceLogIdentifier, RaceLogRegisterCompetitorEvent event) { - BasicDBObject result = new BasicDBObject(); - storeRaceLogIdentifier(raceLogIdentifier, result); - result.put(FieldNames.RACE_LOG_EVENT.name(), storeRaceLogRegisterCompetitorEvent(event)); - return result; - } - - public DBObject storeRaceLogEntry(RaceLogIdentifier raceLogIdentifier, RaceLogDefineMarkEvent event) { - BasicDBObject result = new BasicDBObject(); - storeRaceLogIdentifier(raceLogIdentifier, result); - result.put(FieldNames.RACE_LOG_EVENT.name(), storeRaceLogDefineMarkEvent(event)); - return result; - } - - public DBObject storeRaceLogEntry(RaceLogIdentifier raceLogIdentifier, RaceLogCloseOpenEndedDeviceMappingEvent event) { - BasicDBObject result = new BasicDBObject(); - storeRaceLogIdentifier(raceLogIdentifier, result); - result.put(FieldNames.RACE_LOG_EVENT.name(), storeRaceLogCloseOpenEndedDeviceMappingEvent(event)); - return result; - } - - public DBObject storeRaceLogEntry(RaceLogIdentifier raceLogIdentifier, RaceLogEndOfTrackingEvent event) { - BasicDBObject result = new BasicDBObject(); - storeRaceLogIdentifier(raceLogIdentifier, result); - result.put(FieldNames.RACE_LOG_EVENT.name(), storeRaceLogEndOfTrackingEvent(event)); - return result; - } - - public DBObject storeRaceLogEntry(RaceLogIdentifier raceLogIdentifier, RaceLogStartOfTrackingEvent event) { - BasicDBObject result = new BasicDBObject(); - storeRaceLogIdentifier(raceLogIdentifier, result); - result.put(FieldNames.RACE_LOG_EVENT.name(), storeRaceLogStartOfTrackingEvent(event)); - return result; - } - - public DBObject storeRaceLogEntry(RaceLogIdentifier raceLogIdentifier, RaceLogAdditionalScoringInformationEvent event) { - BasicDBObject result = new BasicDBObject(); - storeRaceLogIdentifier(raceLogIdentifier, result); - result.put(FieldNames.RACE_LOG_EVENT.name(), storeAdditionalScoringInformation(event)); - return result; - } - - private Object storeAdditionalScoringInformation(RaceLogAdditionalScoringInformationEvent event) { - DBObject result = new BasicDBObject(); - storeRaceLogEventProperties(event, result); - result.put(FieldNames.RACE_LOG_EVENT_CLASS.name(), RaceLogAdditionalScoringInformationEvent.class.getSimpleName()); - result.put(FieldNames.RACE_LOG_ADDITIONAL_SCORING_INFORMATION_TYPE.name(), event.getType().name()); - return result; - } - - public DBObject storeRaceLogEntry(RaceLogIdentifier raceLogIdentifier, RaceLogFixedMarkPassingEvent event) { - BasicDBObject result = new BasicDBObject(); - storeRaceLogIdentifier(raceLogIdentifier, result); - result.put(FieldNames.RACE_LOG_EVENT.name(), storeRaceLogFixedMarkPassingEvent(event)); - return result; - } - - public DBObject storeRaceLogEntry(RaceLogIdentifier raceLogIdentifier, RaceLogSuppressedMarkPassingsEvent event) { - BasicDBObject result = new BasicDBObject(); - storeRaceLogIdentifier(raceLogIdentifier, result); - result.put(FieldNames.RACE_LOG_EVENT.name(), storeRaceLogSuppressedMarkPassingsEvent(event)); - return result; - } - - private Object storeRaceLogWindFix(RaceLogWindFixEvent event) { - DBObject result = new BasicDBObject(); - storeRaceLogEventProperties(event, result); - result.put(FieldNames.RACE_LOG_EVENT_CLASS.name(), RaceLogWindFixEvent.class.getSimpleName()); - result.put(FieldNames.WIND.name(), storeWind(event.getWindFix())); - result.put(FieldNames.IS_MAGNETIC.name(), event.isMagnetic()); - return result; - } - - private Object storeRaceLogProtestStartTimeEvent(RaceLogProtestStartTimeEvent event) { - DBObject result = new BasicDBObject(); - storeRaceLogEventProperties(event, result); - result.put(FieldNames.RACE_LOG_EVENT_CLASS.name(), RaceLogProtestStartTimeEvent.class.getSimpleName()); - storeTimePoint(event.getProtestStartTime(), result, FieldNames.RACE_LOG_PROTEST_START_TIME); - return result; - } - - private Object storeRaceLogEndOfTrackingEvent(RaceLogEndOfTrackingEvent event) { - DBObject result = new BasicDBObject(); - storeRaceLogEventProperties(event, result); - result.put(FieldNames.RACE_LOG_EVENT_CLASS.name(), RaceLogEndOfTrackingEvent.class.getSimpleName()); - return result; - } - - private Object storeRaceLogStartOfTrackingEvent(RaceLogStartOfTrackingEvent event) { - DBObject result = new BasicDBObject(); - storeRaceLogEventProperties(event, result); - result.put(FieldNames.RACE_LOG_EVENT_CLASS.name(), RaceLogStartOfTrackingEvent.class.getSimpleName()); - return result; - } - - private Object storeRaceLogStartProcedureChangedEvent(RaceLogStartProcedureChangedEvent event) { - DBObject result = new BasicDBObject(); - storeRaceLogEventProperties(event, result); - result.put(FieldNames.RACE_LOG_EVENT_CLASS.name(), RaceLogStartProcedureChangedEvent.class.getSimpleName()); - result.put(FieldNames.RACE_LOG_START_PROCEDURE_TYPE.name(), event.getStartProcedureType().name()); - return result; - } - - private Object storeRaceLogPathfinderEvent(RaceLogPathfinderEvent pathfinderEvent) { - DBObject result = new BasicDBObject(); - storeRaceLogEventProperties(pathfinderEvent, result); - result.put(FieldNames.RACE_LOG_EVENT_CLASS.name(), RaceLogPathfinderEvent.class.getSimpleName()); - result.put(FieldNames.RACE_LOG_PATHFINDER_ID.name(), pathfinderEvent.getPathfinderId()); - return result; - } - - private void storeDeviceMappingEvent(DeviceMappingEvent event, DBObject result, FieldNames fromField, FieldNames toField) { - try { - result.put(FieldNames.DEVICE_ID.name(), storeDeviceId(deviceIdentifierServiceFinder, event.getDevice())); - } catch (TransformationException | NoCorrespondingServiceRegisteredException e) { - logger.log(Level.WARNING, "Could not store device identifier for mappng event", e); - } - if (event.getFrom() != null) { - storeTimePoint(event.getFrom(), result, fromField); - } - if (event.getTo() != null) { - storeTimePoint(event.getTo(), result, toField); - } - } - - private Object storeRaceLogDeviceCompetitorMappingEvent(RaceLogDeviceCompetitorMappingEvent event) { - DBObject result = new BasicDBObject(); - storeRaceLogEventProperties(event, result); - result.put(FieldNames.RACE_LOG_EVENT_CLASS.name(), RaceLogDeviceCompetitorMappingEvent.class.getSimpleName()); - storeDeviceMappingEvent(event, result, FieldNames.RACE_LOG_FROM, FieldNames.RACE_LOG_TO); - result.put(FieldNames.COMPETITOR_ID.name(), event.getMappedTo().getId()); - return result; - } - - private Object storeRaceLogDeviceMarkMappingEvent(RaceLogDeviceMarkMappingEvent event) { - DBObject result = new BasicDBObject(); - storeRaceLogEventProperties(event, result); - result.put(FieldNames.RACE_LOG_EVENT_CLASS.name(), RaceLogDeviceMarkMappingEvent.class.getSimpleName()); - storeDeviceMappingEvent(event, result, FieldNames.RACE_LOG_FROM, FieldNames.RACE_LOG_TO); - result.put(FieldNames.MARK.name(), storeMark(event.getMappedTo())); - return result; - } - - private Object storeRaceLogDenoteForTrackingEvent(RaceLogDenoteForTrackingEvent event) { - DBObject result = new BasicDBObject(); - storeRaceLogEventProperties(event, result); - result.put(FieldNames.RACE_LOG_EVENT_CLASS.name(), RaceLogDenoteForTrackingEvent.class.getSimpleName()); - result.put(FieldNames.RACE_NAME.name(), event.getRaceName()); - result.put(FieldNames.BOAT_CLASS_NAME.name(), event.getBoatClass().getName()); - result.put(FieldNames.RACE_ID.name(), event.getRaceId()); - return result; - } - - private Object storeRaceLogStartTrackingEvent(RaceLogStartTrackingEvent event) { - DBObject result = new BasicDBObject(); - storeRaceLogEventProperties(event, result); - result.put(FieldNames.RACE_LOG_EVENT_CLASS.name(), RaceLogStartTrackingEvent.class.getSimpleName()); - return result; - } - - private Object storeRaceLogRevokeEvent(RaceLogRevokeEvent event) { - DBObject result = new BasicDBObject(); - storeRaceLogEventProperties(event, result); - result.put(FieldNames.RACE_LOG_EVENT_CLASS.name(), RaceLogRevokeEvent.class.getSimpleName()); - result.put(FieldNames.RACE_LOG_REVOKED_EVENT_ID.name(), event.getRevokedEventId()); - result.put(FieldNames.RACE_LOG_REVOKED_EVENT_TYPE.name(), event.getRevokedEventType()); - result.put(FieldNames.RACE_LOG_REVOKED_EVENT_SHORT_INFO.name(), event.getRevokedEventShortInfo()); - result.put(FieldNames.RACE_LOG_REVOKED_REASON.name(), event.getReason()); - return result; - } - - private Object storeRaceLogRegisterCompetitorEvent(RaceLogRegisterCompetitorEvent event) { - DBObject result = new BasicDBObject(); - storeRaceLogEventProperties(event, result); - result.put(FieldNames.RACE_LOG_EVENT_CLASS.name(), RaceLogRegisterCompetitorEvent.class.getSimpleName()); - result.put(FieldNames.RACE_LOG_COMPETITOR_ID.name(), event.getCompetitor().getId()); - return result; - } - - private Object storeRaceLogDefineMarkEvent(RaceLogDefineMarkEvent event) { - DBObject result = new BasicDBObject(); - storeRaceLogEventProperties(event, result); - result.put(FieldNames.RACE_LOG_EVENT_CLASS.name(), RaceLogDefineMarkEvent.class.getSimpleName()); - result.put(FieldNames.RACE_LOG_MARK.name(), storeMark(event.getMark())); - return result; - } - - private Object storeRaceLogCloseOpenEndedDeviceMappingEvent(RaceLogCloseOpenEndedDeviceMappingEvent event) { - DBObject result = new BasicDBObject(); - storeRaceLogEventProperties(event, result); - result.put(FieldNames.RACE_LOG_EVENT_CLASS.name(), RaceLogCloseOpenEndedDeviceMappingEvent.class.getSimpleName()); - result.put(FieldNames.RACE_LOG_DEVICE_MAPPING_EVENT_ID.name(), event.getDeviceMappingEventId()); - storeTimePoint(event.getClosingTimePoint(), result, FieldNames.RACE_LOG_CLOSING_TIMEPOINT); - return result; - } - - private Object storeRaceLogFixedMarkPassingEvent(RaceLogFixedMarkPassingEvent event) { - DBObject result = new BasicDBObject(); - storeRaceLogEventProperties(event, result); - result.put(FieldNames.RACE_LOG_EVENT_CLASS.name(), RaceLogFixedMarkPassingEvent.class.getSimpleName()); - result.put(FieldNames.INDEX_OF_PASSED_WAYPOINT.name(), event.getZeroBasedIndexOfPassedWaypoint()); - result.put(FieldNames.TIMEPOINT_OF_FIXED_MARKPASSING.name(), event.getTimePointOfFixedPassing().asMillis()); - return result; - } - - private Object storeRaceLogSuppressedMarkPassingsEvent(RaceLogSuppressedMarkPassingsEvent event) { - DBObject result = new BasicDBObject(); - storeRaceLogEventProperties(event, result); - result.put(FieldNames.RACE_LOG_EVENT_CLASS.name(), RaceLogSuppressedMarkPassingsEvent.class.getSimpleName()); - result.put(FieldNames.INDEX_OF_FIRST_SUPPRESSED_WAYPOINT.name(), event.getZeroBasedIndexOfFirstSuppressedWaypoint()); - return result; - } - - public DBObject storeRaceLogFlagEvent(RaceLogFlagEvent flagEvent) { - DBObject result = new BasicDBObject(); - storeRaceLogEventProperties(flagEvent, result); - result.put(FieldNames.RACE_LOG_EVENT_CLASS.name(), RaceLogFlagEvent.class.getSimpleName()); - result.put(FieldNames.RACE_LOG_EVENT_FLAG_UPPER.name(), flagEvent.getUpperFlag().name()); - result.put(FieldNames.RACE_LOG_EVENT_FLAG_LOWER.name(), flagEvent.getLowerFlag().name()); - result.put(FieldNames.RACE_LOG_EVENT_FLAG_DISPLAYED.name(), String.valueOf(flagEvent.isDisplayed())); - return result; - } - - private DBObject storeRaceLogStartTimeEvent(RaceLogStartTimeEvent startTimeEvent) { - DBObject result = new BasicDBObject(); - storeRaceLogEventProperties(startTimeEvent, result); - result.put(FieldNames.RACE_LOG_EVENT_CLASS.name(), RaceLogStartTimeEvent.class.getSimpleName()); - storeTimePoint(startTimeEvent.getStartTime(), result, FieldNames.RACE_LOG_EVENT_START_TIME); - result.put(FieldNames.RACE_LOG_EVENT_NEXT_STATUS.name(), startTimeEvent.getNextStatus().name()); - return result; - } - - private void storeRaceLogEventProperties(RaceLogEvent event, DBObject result) { - // for compatibility reasons we reuse the field name of Timed - storeTimePoint(event.getLogicalTimePoint(), result, FieldNames.TIME_AS_MILLIS); - storeTimePoint(event.getCreatedAt(), result, FieldNames.RACE_LOG_EVENT_CREATED_AT); - result.put(FieldNames.RACE_LOG_EVENT_ID.name(), event.getId()); - result.put(FieldNames.RACE_LOG_EVENT_PASS_ID.name(), event.getPassId()); - result.put(FieldNames.RACE_LOG_EVENT_INVOLVED_BOATS.name(), storeInvolvedBoatsForRaceLogEvent(event.getInvolvedBoats())); - storeRaceLogEventAuthor(result, event.getAuthor()); - } - - - private BasicDBList storeInvolvedBoatsForRaceLogEvent(List competitors) { - BasicDBList dbInvolvedCompetitorIds = new BasicDBList(); - for (Competitor competitor : competitors) { - dbInvolvedCompetitorIds.add(competitor.getId()); - } - return dbInvolvedCompetitorIds; - } - - private DBObject storeRaceLogPassChangeEvent(RaceLogPassChangeEvent passChangeEvent) { - DBObject result = new BasicDBObject(); - storeRaceLogEventProperties(passChangeEvent, result); - result.put(FieldNames.RACE_LOG_EVENT_CLASS.name(), RaceLogPassChangeEvent.class.getSimpleName()); - return result; - } - - private DBObject storeRaceLogDependentStartTimeEvent(RaceLogDependentStartTimeEvent dependentStartTimeEvent) { - DBObject result = new BasicDBObject(); - storeRaceLogEventProperties(dependentStartTimeEvent, result); - result.put(FieldNames.RACE_LOG_EVENT_CLASS.name(), RaceLogDependentStartTimeEvent.class.getSimpleName()); - result.put(FieldNames.RACE_LOG_DEPDENDENT_ON_REGATTALIKE.name(), dependentStartTimeEvent.getDependentOnRaceIdentifier().getRegattaLikeParentName()); - result.put(FieldNames.RACE_LOG_DEPDENDENT_ON_RACECOLUMN.name(), dependentStartTimeEvent.getDependentOnRaceIdentifier().getRaceColumnName()); - result.put(FieldNames.RACE_LOG_DEPDENDENT_ON_FLEET.name(), dependentStartTimeEvent.getDependentOnRaceIdentifier().getFleetName()); - storeDuration(dependentStartTimeEvent.getStartTimeDifference(), result, FieldNames.RACE_LOG_START_TIME_DIFFERENCE_IN_MS); - result.put(FieldNames.RACE_LOG_EVENT_NEXT_STATUS.name(), dependentStartTimeEvent.getNextStatus().name()); - return result; - } - - private void storeDuration(Duration duration, DBObject result, FieldNames fieldName) { - if (duration != null) { - result.put(fieldName.name(), duration.asMillis()); - } - } - - private DBObject storeRaceLogRaceStatusEvent(RaceLogRaceStatusEvent raceStatusEvent) { - DBObject result = new BasicDBObject(); - storeRaceLogEventProperties(raceStatusEvent, result); - result.put(FieldNames.RACE_LOG_EVENT_CLASS.name(), RaceLogRaceStatusEvent.class.getSimpleName()); - result.put(FieldNames.RACE_LOG_EVENT_NEXT_STATUS.name(), raceStatusEvent.getNextStatus().name()); - return result; - } - - private DBObject storeRaceLogCourseAreaChangedEvent(RaceLogCourseAreaChangedEvent courseAreaChangedEvent) { - DBObject result = new BasicDBObject(); - storeRaceLogEventProperties(courseAreaChangedEvent, result); - result.put(FieldNames.RACE_LOG_EVENT_CLASS.name(), RaceLogCourseAreaChangedEvent.class.getSimpleName()); - result.put(FieldNames.COURSE_AREA_ID.name(), courseAreaChangedEvent.getCourseAreaId()); - return result; - } - - private DBObject storeRaceLogCourseDesignChangedEvent(RaceLogCourseDesignChangedEvent courseDesignChangedEvent) { - DBObject result = new BasicDBObject(); - storeRaceLogEventProperties(courseDesignChangedEvent, result); - result.put(FieldNames.RACE_LOG_EVENT_CLASS.name(), RaceLogCourseDesignChangedEvent.class.getSimpleName()); - result.put(FieldNames.RACE_LOG_COURSE_DESIGN_NAME.name(), courseDesignChangedEvent.getCourseDesign().getName()); - result.put(FieldNames.RACE_LOG_COURSE_DESIGN.name(), storeCourseBase(courseDesignChangedEvent.getCourseDesign())); - return result; - } - - private Object storeRaceLogFinishPositioningListChangedEvent(RaceLogFinishPositioningListChangedEvent finishPositioningListChangedEvent) { - DBObject result = new BasicDBObject(); - storeRaceLogEventProperties(finishPositioningListChangedEvent, result); - result.put(FieldNames.RACE_LOG_EVENT_CLASS.name(), RaceLogFinishPositioningListChangedEvent.class.getSimpleName()); - result.put(FieldNames.RACE_LOG_POSITIONED_COMPETITORS.name(), storePositionedCompetitors(finishPositioningListChangedEvent.getPositionedCompetitorsIDsNamesMaxPointsReasons())); - - return result; - } - - private Object storeRaceLogFinishPositioningConfirmedEvent(RaceLogFinishPositioningConfirmedEvent finishPositioningConfirmedEvent) { - DBObject result = new BasicDBObject(); - storeRaceLogEventProperties(finishPositioningConfirmedEvent, result); - result.put(FieldNames.RACE_LOG_EVENT_CLASS.name(), RaceLogFinishPositioningConfirmedEvent.class.getSimpleName()); - result.put(FieldNames.RACE_LOG_POSITIONED_COMPETITORS.name(), storePositionedCompetitors(finishPositioningConfirmedEvent.getPositionedCompetitorsIDsNamesMaxPointsReasons())); - - return result; - } - - private Object storeRaceLogGateLineOpeningTimeEvent(RaceLogGateLineOpeningTimeEvent gateLineOpeningTimeEvent){ - DBObject result = new BasicDBObject(); - storeRaceLogEventProperties(gateLineOpeningTimeEvent, result); - result.put(FieldNames.RACE_LOG_EVENT_CLASS.name(), RaceLogGateLineOpeningTimeEvent.class.getSimpleName()); - result.put(FieldNames.RACE_LOG_GATE_LINE_OPENING_TIME.name(), gateLineOpeningTimeEvent.getGateLineOpeningTimes().getGateLaunchStopTime()); - result.put(FieldNames.RACE_LOG_GOLF_DOWN_TIME.name(), gateLineOpeningTimeEvent.getGateLineOpeningTimes().getGolfDownTime()); - return result; - } - - private BasicDBList storePositionedCompetitors(List> positionedCompetitors) { - BasicDBList dbList = new BasicDBList(); - if (positionedCompetitors != null) { - for (com.sap.sse.common.Util.Triple competitorPair : positionedCompetitors) { - dbList.add(storePositionedCompetitor(competitorPair)); - } - } - return dbList; - } - - private DBObject storePositionedCompetitor(com.sap.sse.common.Util.Triple competitorTriple) { - DBObject result = new BasicDBObject(); - result.put(FieldNames.COMPETITOR_ID.name(), competitorTriple.getA()); - result.put(FieldNames.COMPETITOR_DISPLAY_NAME.name(), competitorTriple.getB()); - result.put(FieldNames.LEADERBOARD_SCORE_CORRECTION_MAX_POINTS_REASON.name(), competitorTriple.getC().name()); - - return result; - } - - private BasicDBList storeCourseBase(CourseBase courseData) { - BasicDBList dbList = new BasicDBList(); - - for (Waypoint waypoint : courseData.getWaypoints()) { - dbList.add(storeWaypoint(waypoint)); - } - return dbList; - } - - private DBObject storeWaypoint(Waypoint waypoint) { - DBObject result = new BasicDBObject(); - result.put(FieldNames.WAYPOINT_PASSINGINSTRUCTIONS.name(), getPassingInstructions(waypoint.getPassingInstructions())); - result.put(FieldNames.CONTROLPOINT.name(), storeControlPoint(waypoint.getControlPoint())); - return result; - } - - private DBObject storeControlPoint(ControlPoint controlPoint) { - DBObject result = new BasicDBObject(); - if (controlPoint instanceof Mark) { - result.put(FieldNames.CONTROLPOINT_CLASS.name(), Mark.class.getSimpleName()); - result.put(FieldNames.CONTROLPOINT_VALUE.name(), storeMark((Mark) controlPoint)); - } else if (controlPoint instanceof ControlPointWithTwoMarks) { - result.put(FieldNames.CONTROLPOINT_CLASS.name(), ControlPointWithTwoMarks.class.getSimpleName()); - result.put(FieldNames.CONTROLPOINT_VALUE.name(), storeControlPointWithTwoMarks((ControlPointWithTwoMarks) controlPoint)); - } - return result; - } - - private DBObject storeControlPointWithTwoMarks(ControlPointWithTwoMarks cpwtm) { - DBObject result = new BasicDBObject(); - result.put(FieldNames.CONTROLPOINTWITHTWOMARKS_ID.name(), cpwtm.getId()); - result.put(FieldNames.CONTROLPOINTWITHTWOMARKS_NAME.name(), cpwtm.getName()); - result.put(FieldNames.CONTROLPOINTWITHTWOMARKS_LEFT.name(), storeMark(cpwtm.getLeft())); - result.put(FieldNames.CONTROLPOINTWITHTWOMARKS_RIGHT.name(), storeMark(cpwtm.getRight())); - return result; - } - - private DBObject storeMark(Mark mark) { - DBObject result = new BasicDBObject(); - result.put(FieldNames.MARK_ID.name(), mark.getId()); - result.put(FieldNames.MARK_COLOR.name(), mark.getColor()); - result.put(FieldNames.MARK_NAME.name(), mark.getName()); - result.put(FieldNames.MARK_PATTERN.name(), mark.getPattern()); - result.put(FieldNames.MARK_SHAPE.name(), mark.getShape()); - result.put(FieldNames.MARK_TYPE.name(), mark.getType() == null ? null : mark.getType().name()); - return result; - } - - private String getPassingInstructions(PassingInstruction passingInstructions) { - final String passing; - if (passingInstructions != null) { - passing = passingInstructions.name(); - } else { - passing = null; - } - return passing; - } - @Override - public void storeCompetitor(Competitor competitor) { - DBCollection collection = database.getCollection(CollectionNames.COMPETITORS.name()); - JSONObject json = competitorSerializer.serialize(competitor); - DBObject query = (DBObject) JSON.parse(CompetitorJsonSerializer.getCompetitorIdQuery(competitor).toString()); - DBObject entry = (DBObject) JSON.parse(json.toString()); - collection.update(query, entry, /* upsrt */true, /* multi */false, WriteConcern.SAFE); - } - - @Override - public void removeAllCompetitors() { - logger.info("Removing all persistent competitor info"); - DBCollection collection = database.getCollection(CollectionNames.COMPETITORS.name()); - collection.drop(); - } - - @Override - public void removeCompetitor(Competitor competitor) { - logger.info("Removing persistent competitor info for competitor "+competitor.getName()+" with ID "+competitor.getId()); - DBCollection collection = database.getCollection(CollectionNames.COMPETITORS.name()); - DBObject query = (DBObject) JSON.parse(CompetitorJsonSerializer.getCompetitorIdQuery(competitor).toString()); - collection.remove(query, WriteConcern.SAFE); - } - - @Override - public void storeDeviceConfiguration(DeviceConfigurationMatcher matcher, DeviceConfiguration configuration) { - DBCollection configurationsCollections = database.getCollection(CollectionNames.CONFIGURATIONS.name()); - - DBObject query = new BasicDBObject(); - query.put(FieldNames.CONFIGURATION_MATCHER_ID.name(), matcher.getMatcherIdentifier()); - - DBObject entryObject = new BasicDBObject(); - entryObject.put(FieldNames.CONFIGURATION_MATCHER_ID.name(), matcher.getMatcherIdentifier()); - entryObject.put(FieldNames.CONFIGURATION_MATCHER.name(), createDeviceConfigurationMatcherObject(matcher)); - entryObject.put(FieldNames.CONFIGURATION_CONFIG.name(), createDeviceConfigurationObject(configuration)); - - configurationsCollections.update(query, entryObject, /* upsrt */ true, /* multi */ false, WriteConcern.SAFE); - } - - private DBObject createDeviceConfigurationMatcherObject(DeviceConfigurationMatcher matcher) { - DBObject matcherObject = new BasicDBObject(); - matcherObject.put(FieldNames.CONFIGURATION_MATCHER_TYPE.name(), matcher.getMatcherType().name()); - if (matcher instanceof DeviceConfigurationMatcherSingle) { - BasicDBList client = new BasicDBList(); - client.add(((DeviceConfigurationMatcherSingle)matcher).getClientIdentifier()); - matcherObject.put(FieldNames.CONFIGURATION_MATCHER_CLIENTS.name(), client); - } else if (matcher instanceof DeviceConfigurationMatcherMulti) { - BasicDBList clients = new BasicDBList(); - Util.addAll(((DeviceConfigurationMatcherMulti)matcher).getClientIdentifiers(), clients); - matcherObject.put(FieldNames.CONFIGURATION_MATCHER_CLIENTS.name(), clients); - } - return matcherObject; - } - - private DBObject createDeviceConfigurationObject(DeviceConfiguration configuration) { - JsonSerializer serializer = DeviceConfigurationJsonSerializer.create(); - JSONObject json = serializer.serialize(configuration); - DBObject entry = (DBObject) JSON.parse(json.toString()); - return entry; - } - - @Override - public void removeDeviceConfiguration(DeviceConfigurationMatcher matcher) { - DBCollection configurationsCollections = database.getCollection(CollectionNames.CONFIGURATIONS.name()); - DBObject query = new BasicDBObject(); - query.put(FieldNames.CONFIGURATION_MATCHER_ID.name(), matcher.getMatcherIdentifier()); - configurationsCollections.remove(query); - } - - public static DBObject storeDeviceId( - TypeBasedServiceFinder deviceIdentifierServiceFinder, DeviceIdentifier device) - throws TransformationException, NoCorrespondingServiceRegisteredException { - String type = device.getIdentifierType(); - DeviceIdentifierMongoHandler handler = deviceIdentifierServiceFinder.findService(type); - com.sap.sse.common.Util.Pair pair = handler.serialize(device); - type = pair.getA(); - Object deviceTypeSpecificId = pair.getB(); - return new BasicDBObjectBuilder() - .add(FieldNames.DEVICE_TYPE.name(), type) - .add(FieldNames.DEVICE_TYPE_SPECIFIC_ID.name(), deviceTypeSpecificId) - .add(FieldNames.DEVICE_STRING_REPRESENTATION.name(), device.getStringRepresentation()).get(); - } - - void storeRaceLogEventEvent(DBObject eventEntry) { - getRaceLogCollection().insert(eventEntry); - } - - @Override - public void removeRaceLog(RaceLogIdentifier identifier) { - DBObject query = new BasicDBObject(); - storeRaceLogIdentifier(identifier, query); - getRaceLogCollection().remove(query); - } - - @Override - public void removeRegattaLog(RegattaLikeIdentifier identifier) { - DBObject query = new BasicDBObject(); - addRegattaLikeIdentifier(identifier, query); - getRegattaLogCollection().remove(query); - } - - @Override - public void storeResultUrl(String resultProviderName, URL url) { - DBCollection resultUrlsCollection = database.getCollection(CollectionNames.RESULT_URLS.name()); - DBObject query = new BasicDBObject(FieldNames.RESULT_PROVIDERNAME.name(), resultProviderName); - DBObject entry = new BasicDBObject(FieldNames.RESULT_PROVIDERNAME.name(), resultProviderName); - entry.put(FieldNames.RESULT_URL.name(), url.toString()); - resultUrlsCollection.update(query, entry, /* upsrt */true, /* multi */false, WriteConcern.SAFE); - } - - @Override - public void removeResultUrl(String resultProviderName, URL url) { - DBCollection resultUrlsCollection = database.getCollection(CollectionNames.RESULT_URLS.name()); - DBObject query = new BasicDBObjectBuilder().add(FieldNames.RESULT_PROVIDERNAME.name(), resultProviderName) - .add(FieldNames.RESULT_URL.name(), url.toString()).get(); - resultUrlsCollection.remove(query); - } - - public DBCollection getRegattaLogCollection() { - DBCollection result = database.getCollection(CollectionNames.REGATTA_LOGS.name()); - DBObject index = new BasicDBObject(FieldNames.REGATTA_LOG_IDENTIFIER_TYPE.name(), null); - index.put(FieldNames.REGATTA_LOG_IDENTIFIER_NAME.name(), null); - result.createIndex(index); - return result; - } - - private DBObject createBasicRegattaLogEventDBObject(RegattaLogEvent event) { - DBObject result = new BasicDBObject(); - storeTimed(event, result); - storeTimePoint(event.getCreatedAt(), result, FieldNames.REGATTA_LOG_EVENT_CREATED_AT); - result.put(FieldNames.REGATTA_LOG_EVENT_ID.name(), event.getId()); - result.put(FieldNames.REGATTA_LOG_EVENT_AUTHOR_NAME.name(), event.getAuthor().getName()); - result.put(FieldNames.REGATTA_LOG_EVENT_AUTHOR_PRIORITY.name(), event.getAuthor().getPriority()); - return result; - } - - private void addRegattaLikeIdentifier(RegattaLikeIdentifier regattaLikeId, DBObject toObject) { - toObject.put(FieldNames.REGATTA_LOG_IDENTIFIER_TYPE.name(), regattaLikeId.getIdentifierType()); - toObject.put(FieldNames.REGATTA_LOG_IDENTIFIER_NAME.name(), regattaLikeId.getName()); - } - - private void storeRegattaLogEvent(RegattaLikeIdentifier regattaLikeId, DBObject innerObject) { - DBObject result = new BasicDBObject(FieldNames.REGATTA_LOG_EVENT.name(), innerObject); - addRegattaLikeIdentifier(regattaLikeId, result); - getRegattaLogCollection().insert(result); - } - - public void storeRegattaLogEvent(RegattaLikeIdentifier regattaLikeId, RegattaLogDeviceCompetitorMappingEvent event) { - DBObject result = createBasicRegattaLogEventDBObject(event); - result.put(FieldNames.REGATTA_LOG_EVENT_CLASS.name(), RegattaLogDeviceCompetitorMappingEvent.class.getSimpleName()); - storeDeviceMappingEvent(event, result, FieldNames.REGATTA_LOG_FROM, FieldNames.REGATTA_LOG_TO); - result.put(FieldNames.COMPETITOR_ID.name(), event.getMappedTo().getId()); - storeRegattaLogEvent(regattaLikeId, result); - } - - public void storeRegattaLogEvent(RegattaLikeIdentifier regattaLikeId, RegattaLogDeviceMarkMappingEvent event) { - DBObject result = createBasicRegattaLogEventDBObject(event); - result.put(FieldNames.REGATTA_LOG_EVENT_CLASS.name(), RegattaLogDeviceMarkMappingEvent.class.getSimpleName()); - storeDeviceMappingEvent(event, result, FieldNames.REGATTA_LOG_FROM, FieldNames.REGATTA_LOG_TO); - result.put(FieldNames.MARK.name(), storeMark(event.getMappedTo())); - storeRegattaLogEvent(regattaLikeId, result); - } - - public void storeRegattaLogEvent(RegattaLikeIdentifier regattaLikeId, RegattaLogRevokeEvent event) { - DBObject result = createBasicRegattaLogEventDBObject(event); - result.put(FieldNames.REGATTA_LOG_EVENT_CLASS.name(), RegattaLogRevokeEvent.class.getSimpleName()); - result.put(FieldNames.REGATTA_LOG_REVOKED_EVENT_ID.name(), event.getRevokedEventId()); - result.put(FieldNames.REGATTA_LOG_REVOKED_EVENT_TYPE.name(), event.getRevokedEventType()); - result.put(FieldNames.REGATTA_LOG_REVOKED_EVENT_SHORT_INFO.name(), event.getRevokedEventShortInfo()); - result.put(FieldNames.REGATTA_LOG_REVOKED_REASON.name(), event.getReason()); - storeRegattaLogEvent(regattaLikeId, result); - } - - public void storeRegattaLogEvent(RegattaLikeIdentifier regattaLikeId, RegattaLogRegisterCompetitorEvent event) { - DBObject result = createBasicRegattaLogEventDBObject(event); - result.put(FieldNames.REGATTA_LOG_EVENT_CLASS.name(), RegattaLogRegisterCompetitorEvent.class.getSimpleName()); - result.put(FieldNames.REGATTA_LOG_COMPETITOR_ID.name(), event.getCompetitor().getId()); - storeRegattaLogEvent(regattaLikeId, result); - } - - public void storeRegattaLogEvent(RegattaLikeIdentifier regattaLikeId, RegattaLogCloseOpenEndedDeviceMappingEvent event) { - DBObject result = createBasicRegattaLogEventDBObject(event); - result.put(FieldNames.REGATTA_LOG_EVENT_CLASS.name(), RegattaLogCloseOpenEndedDeviceMappingEvent.class.getSimpleName()); - result.put(FieldNames.REGATTA_LOG_DEVICE_MAPPING_EVENT_ID.name(), event.getDeviceMappingEventId()); - storeTimePoint(event.getClosingTimePoint(), result, FieldNames.REGATTA_LOG_CLOSING_TIMEPOINT); - storeRegattaLogEvent(regattaLikeId, result); - } - - public void storeRegattaLogEvent(RegattaLikeIdentifier regattaLikeId, RegattaLogSetCompetitorTimeOnTimeFactorEvent event) { - DBObject result = createBasicRegattaLogEventDBObject(event); - result.put(FieldNames.REGATTA_LOG_EVENT_CLASS.name(), RegattaLogCloseOpenEndedDeviceMappingEvent.class.getSimpleName()); - result.put(FieldNames.REGATTA_LOG_COMPETITOR_ID.name(), event.getCompetitor().getId()); - result.put(FieldNames.REGATTA_LOG_TIME_ON_TIME_FACTOR.name(), event.getTimeOnTimeFactor()); - } - - public DBObject storeRaceLogEntry(RaceLogIdentifier raceLogIdentifier, RaceLogDependentStartTimeEvent event) { - BasicDBObject result = new BasicDBObject(); - storeRaceLogIdentifier(raceLogIdentifier, result); - result.put(FieldNames.RACE_LOG_EVENT.name(), storeRaceLogDependentStartTimeEvent(event)); - return result; - } - - public void storeRegattaLogEvent(RegattaLikeIdentifier regattaLikeId, RegattaLogSetCompetitorTimeOnDistanceAllowancePerNauticalMileEvent event) { - DBObject result = createBasicRegattaLogEventDBObject(event); - result.put(FieldNames.REGATTA_LOG_EVENT_CLASS.name(), RegattaLogCloseOpenEndedDeviceMappingEvent.class.getSimpleName()); - result.put(FieldNames.REGATTA_LOG_COMPETITOR_ID.name(), event.getCompetitor().getId()); - result.put(FieldNames.REGATTA_LOG_TIME_ON_DISTANCE_SECONDS_ALLOWANCE_PER_NAUTICAL_MILE.name(), event.getTimeOnDistanceAllowancePerNauticalMile().asSeconds()); - storeRegattaLogEvent(regattaLikeId, result); - } - - private DBObject createImageObject(ImageDescriptor image) { - DBObject result = new BasicDBObject(); - result.put(FieldNames.IMAGE_URL.name(), image.getURL().toString()); - result.put(FieldNames.IMAGE_LOCALE.name(), image.getLocale() != null ? image.getLocale().toLanguageTag() : null); - result.put(FieldNames.IMAGE_TITLE.name(), image.getTitle()); - result.put(FieldNames.IMAGE_SUBTITLE.name(), image.getSubtitle()); - result.put(FieldNames.IMAGE_COPYRIGHT.name(), image.getCopyright()); - result.put(FieldNames.IMAGE_WIDTH_IN_PX.name(), image.getWidthInPx()); - result.put(FieldNames.IMAGE_HEIGHT_IN_PX.name(), image.getHeightInPx()); - storeTimePoint(image.getCreatedAtDate(), result, FieldNames.IMAGE_CREATEDATDATE); - BasicDBList tags = new BasicDBList(); - for (String tag : image.getTags()) { - tags.add(tag); - } - result.put(FieldNames.IMAGE_TAGS.name(), tags); - return result; - } - - private DBObject createVideoObject(VideoDescriptor video) { - DBObject result = new BasicDBObject(); - result.put(FieldNames.VIDEO_URL.name(), video.getURL().toString()); - result.put(FieldNames.VIDEO_LOCALE.name(), video.getLocale() != null ? video.getLocale().toLanguageTag() : null); - result.put(FieldNames.VIDEO_THUMBNAIL_URL.name(), video.getThumbnailURL() != null ? video.getThumbnailURL().toString() : null); - result.put(FieldNames.VIDEO_TITLE.name(), video.getTitle()); - result.put(FieldNames.VIDEO_SUBTITLE.name(), video.getSubtitle()); - result.put(FieldNames.VIDEO_MIMETYPE.name(), video.getMimeType() != null ? video.getMimeType().name() : null); - result.put(FieldNames.VIDEO_COPYRIGHT.name(), video.getCopyright()); - result.put(FieldNames.VIDEO_LENGTH_IN_SECONDS.name(), video.getLengthInSeconds()); - storeTimePoint(video.getCreatedAtDate(), result, FieldNames.VIDEO_CREATEDATDATE); - BasicDBList tags = new BasicDBList(); - for (String tag : video.getTags()) { - tags.add(tag); - } - result.put(FieldNames.VIDEO_TAGS.name(), tags); - return result; - } -} +package com.sap.sailing.domain.persistence.impl; + +import java.io.Serializable; +import java.net.URL; +import java.util.List; +import java.util.Map.Entry; +import java.util.logging.Level; +import java.util.logging.Logger; + +import org.bson.types.ObjectId; +import org.json.simple.JSONObject; + +import com.mongodb.BasicDBList; +import com.mongodb.BasicDBObject; +import com.mongodb.BasicDBObjectBuilder; +import com.mongodb.DB; +import com.mongodb.DBCollection; +import com.mongodb.DBObject; +import com.mongodb.WriteConcern; +import com.mongodb.util.JSON; +import com.sap.sailing.domain.abstractlog.AbstractLogEventAuthor; +import com.sap.sailing.domain.abstractlog.race.CompetitorResult; +import com.sap.sailing.domain.abstractlog.race.CompetitorResults; +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.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; +import com.sap.sailing.domain.abstractlog.race.RaceLogPathfinderEvent; +import com.sap.sailing.domain.abstractlog.race.RaceLogProtestStartTimeEvent; +import com.sap.sailing.domain.abstractlog.race.RaceLogRaceStatusEvent; +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.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.RaceLogDenoteForTrackingEvent; +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.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.RegattaLogDeviceMappingEvent; +import com.sap.sailing.domain.abstractlog.regatta.events.RegattaLogDeviceMarkMappingEvent; +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.events.RegattaLogSetCompetitorTimeOnDistanceAllowancePerNauticalMileEvent; +import com.sap.sailing.domain.abstractlog.regatta.events.RegattaLogSetCompetitorTimeOnTimeFactorEvent; +import com.sap.sailing.domain.base.Competitor; +import com.sap.sailing.domain.base.ControlPoint; +import com.sap.sailing.domain.base.ControlPointWithTwoMarks; +import com.sap.sailing.domain.base.CourseArea; +import com.sap.sailing.domain.base.CourseBase; +import com.sap.sailing.domain.base.Event; +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.RaceDefinition; +import com.sap.sailing.domain.base.Regatta; +import com.sap.sailing.domain.base.RemoteSailingServerReference; +import com.sap.sailing.domain.base.SailingServerConfiguration; +import com.sap.sailing.domain.base.Series; +import com.sap.sailing.domain.base.Venue; +import com.sap.sailing.domain.base.Waypoint; +import com.sap.sailing.domain.base.configuration.DeviceConfiguration; +import com.sap.sailing.domain.base.configuration.DeviceConfigurationMatcher; +import com.sap.sailing.domain.base.configuration.RegattaConfiguration; +import com.sap.sailing.domain.base.configuration.impl.DeviceConfigurationMatcherMulti; +import com.sap.sailing.domain.base.configuration.impl.DeviceConfigurationMatcherSingle; +import com.sap.sailing.domain.base.impl.FleetImpl; +import com.sap.sailing.domain.common.Bearing; +import com.sap.sailing.domain.common.MaxPointsReason; +import com.sap.sailing.domain.common.PassingInstruction; +import com.sap.sailing.domain.common.Positioned; +import com.sap.sailing.domain.common.RaceIdentifier; +import com.sap.sailing.domain.common.Speed; +import com.sap.sailing.domain.common.SpeedWithBearing; +import com.sap.sailing.domain.common.Wind; +import com.sap.sailing.domain.common.WindSource; +import com.sap.sailing.domain.common.racelog.tracking.TransformationException; +import com.sap.sailing.domain.leaderboard.FlexibleLeaderboard; +import com.sap.sailing.domain.leaderboard.Leaderboard; +import com.sap.sailing.domain.leaderboard.LeaderboardGroup; +import com.sap.sailing.domain.leaderboard.RegattaLeaderboard; +import com.sap.sailing.domain.leaderboard.ResultDiscardingRule; +import com.sap.sailing.domain.leaderboard.SettableScoreCorrection; +import com.sap.sailing.domain.leaderboard.ThresholdBasedResultDiscardingRule; +import com.sap.sailing.domain.persistence.MongoObjectFactory; +import com.sap.sailing.domain.persistence.racelog.tracking.DeviceIdentifierMongoHandler; +import com.sap.sailing.domain.persistence.racelog.tracking.impl.PlaceHolderDeviceIdentifierMongoHandler; +import com.sap.sailing.domain.racelog.RaceLogIdentifier; +import com.sap.sailing.domain.racelogtracking.DeviceIdentifier; +import com.sap.sailing.domain.regattalike.RegattaLikeIdentifier; +import com.sap.sailing.domain.tracking.TrackedRace; +import com.sap.sailing.domain.tracking.TrackedRegatta; +import com.sap.sailing.domain.tracking.WindTrack; +import com.sap.sailing.server.gateway.serialization.JsonSerializer; +import com.sap.sailing.server.gateway.serialization.impl.CompetitorJsonSerializer; +import com.sap.sailing.server.gateway.serialization.impl.DeviceConfigurationJsonSerializer; +import com.sap.sailing.server.gateway.serialization.impl.RegattaConfigurationJsonSerializer; +import com.sap.sse.common.Duration; +import com.sap.sse.common.NoCorrespondingServiceRegisteredException; +import com.sap.sse.common.TimePoint; +import com.sap.sse.common.TimeRange; +import com.sap.sse.common.Timed; +import com.sap.sse.common.TypeBasedServiceFinder; +import com.sap.sse.common.TypeBasedServiceFinderFactory; +import com.sap.sse.common.Util; +import com.sap.sse.common.impl.MillisecondsTimePoint; +import com.sap.sse.shared.media.ImageDescriptor; +import com.sap.sse.shared.media.VideoDescriptor; + +public class MongoObjectFactoryImpl implements MongoObjectFactory { + private static Logger logger = Logger.getLogger(MongoObjectFactoryImpl.class.getName()); + private final DB database; + private final CompetitorJsonSerializer competitorSerializer = CompetitorJsonSerializer.create(); + private final TypeBasedServiceFinder deviceIdentifierServiceFinder; + + /** + * Uses null for the device type service finder and hence will be unable to store device identifiers. + * Use this constructor only for testing purposes or in cases where there will happen absolutely no access to + * {@link DeviceIdentifier} objects. + */ + public MongoObjectFactoryImpl(DB database) { + this(database, /* deviceTypeServiceFinder */ null); + } + + public MongoObjectFactoryImpl(DB database, TypeBasedServiceFinderFactory serviceFinderFactory) { + this.database = database; + if (serviceFinderFactory != null) { + this.deviceIdentifierServiceFinder = serviceFinderFactory.createServiceFinder(DeviceIdentifierMongoHandler.class); + this.deviceIdentifierServiceFinder.setFallbackService(new PlaceHolderDeviceIdentifierMongoHandler()); + } else { + this.deviceIdentifierServiceFinder = null; + } + } + + @Override + public DB getDatabase() { + return database; + } + + public DBObject storeWind(Wind wind) { + DBObject result = new BasicDBObject(); + storePositioned(wind, result); + storeTimed(wind, result); + storeSpeedWithBearing(wind, result); + return result; + } + + public static void storeTimePoint(TimePoint timePoint, DBObject result, String fieldName) { + if (timePoint != null) { + result.put(fieldName, timePoint.asMillis()); + } + } + + public static void storeTimePoint(TimePoint timePoint, DBObject result, FieldNames field) { + storeTimePoint(timePoint, result, field.name()); + } + + public static void storeTimeRange(TimeRange timeRange, DBObject result, FieldNames field) { + if (timeRange != null) { + DBObject timeRangeObj = new BasicDBObject(); + storeTimePoint(timeRange.from(), timeRangeObj, FieldNames.FROM_MILLIS); + storeTimePoint(timeRange.to(), timeRangeObj, FieldNames.TO_MILLIS); + result.put(field.name(), timeRangeObj); + } + } + + public void storeTimed(Timed timed, DBObject result) { + if (timed.getTimePoint() != null) { + storeTimePoint(timed.getTimePoint(), result, FieldNames.TIME_AS_MILLIS); + } + } + + public void storeSpeedWithBearing(SpeedWithBearing speedWithBearing, DBObject result) { + storeSpeed(speedWithBearing, result); + storeBearing(speedWithBearing.getBearing(), result); + + } + + public void storeBearing(Bearing bearing, DBObject result) { + result.put(FieldNames.DEGREE_BEARING.name(), bearing.getDegrees()); + } + + public void storeSpeed(Speed speed, DBObject result) { + result.put(FieldNames.KNOT_SPEED.name(), speed.getKnots()); + } + + public void storePositioned(Positioned positioned, DBObject result) { + if (positioned.getPosition() != null) { + result.put(FieldNames.LAT_DEG.name(), positioned.getPosition().getLatDeg()); + result.put(FieldNames.LNG_DEG.name(), positioned.getPosition().getLngDeg()); + } + } + + @Override + public void addWindTrackDumper(TrackedRegatta trackedRegatta, TrackedRace trackedRace, WindSource windSource) { + WindTrack windTrack = trackedRace.getOrCreateWindTrack(windSource); + windTrack.addListener(new MongoWindListener(trackedRace, trackedRegatta.getRegatta().getName(), windSource, this, database)); + } + + public DBCollection getWindTrackCollection() { + DBCollection result = database.getCollection(CollectionNames.WIND_TRACKS.name()); + result.createIndex(new BasicDBObject(FieldNames.REGATTA_NAME.name(), null)); + return result; + } + + public DBCollection getGPSFixCollection() { + DBCollection gpsFixCollection = database.getCollection(CollectionNames.GPS_FIXES.name()); + DBObject index = new BasicDBObject(); + index.put(FieldNames.DEVICE_ID.name(), null); + index.put(FieldNames.TIME_AS_MILLIS.name(), null); + gpsFixCollection.createIndex(index); + return gpsFixCollection; + } + + public DBCollection getGPSFixMetadataCollection() { + DBCollection collection = database.getCollection(CollectionNames.GPS_FIXES_METADATA.name()); + DBObject index = new BasicDBObject(); + index.put(FieldNames.DEVICE_ID.name(), null); + collection.createIndex(index); + return collection; + } + + /** + * @param regattaName + * the regatta name is stored only for human readability purposes because a time stamp may be a bit unhandy for + * identifying where the wind fix was collected + */ + public DBObject storeWindTrackEntry(RaceDefinition race, String regattaName, WindSource windSource, Wind wind) { + BasicDBObject result = new BasicDBObject(); + result.put(FieldNames.RACE_ID.name(), race.getId()); + result.put(FieldNames.REGATTA_NAME.name(), regattaName); + result.put(FieldNames.WIND_SOURCE_NAME.name(), windSource.name()); + if (windSource.getId() != null) { + result.put(FieldNames.WIND_SOURCE_ID.name(), windSource.getId()); + } + result.put(FieldNames.WIND.name(), storeWind(wind)); + return result; + } + + private void storeRaceIdentifiers(RaceColumn raceColumn, DBObject dbObject) { + BasicDBObject raceIdentifiersPerFleet = new BasicDBObject(); + for (Fleet fleet : raceColumn.getFleets()) { + RaceIdentifier raceIdentifier = raceColumn.getRaceIdentifier(fleet); + if (raceIdentifier != null) { + DBObject raceIdentifierForFleet = new BasicDBObject(); + storeRaceIdentifier(raceIdentifierForFleet, raceIdentifier); + raceIdentifiersPerFleet.put(MongoUtils.escapeDollarAndDot(fleet.getName()), raceIdentifierForFleet); + } + } + dbObject.put(FieldNames.RACE_IDENTIFIERS.name(), raceIdentifiersPerFleet); + } + + private void storeRaceIdentifier(DBObject dbObject, RaceIdentifier raceIdentifier) { + if (raceIdentifier != null) { + dbObject.put(FieldNames.EVENT_NAME.name(), raceIdentifier.getRegattaName()); + dbObject.put(FieldNames.RACE_NAME.name(), raceIdentifier.getRaceName()); + } + } + + @Override + public void storeLeaderboard(Leaderboard leaderboard) { + DBCollection leaderboardCollection = database.getCollection(CollectionNames.LEADERBOARDS.name()); + try { + leaderboardCollection.createIndex(new BasicDBObject(FieldNames.LEADERBOARD_NAME.name(), 1)); + } catch (NullPointerException npe) { + // sometimes, for reasons yet to be clarified, ensuring an index on the name field causes an NPE + logger.log(Level.SEVERE, "storeLeaderboard", npe); + } + BasicDBObject query = new BasicDBObject(FieldNames.LEADERBOARD_NAME.name(), leaderboard.getName()); + BasicDBObject dbLeaderboard = new BasicDBObject(); + dbLeaderboard.put(FieldNames.LEADERBOARD_NAME.name(), leaderboard.getName()); + if (leaderboard.getDisplayName() != null) { + dbLeaderboard.put(FieldNames.LEADERBOARD_DISPLAY_NAME.name(), leaderboard.getDisplayName()); + } + BasicDBList dbSuppressedCompetitorIds = new BasicDBList(); + for (Competitor suppressedCompetitor : leaderboard.getSuppressedCompetitors()) { + dbSuppressedCompetitorIds.add(suppressedCompetitor.getId()); + } + dbLeaderboard.put(FieldNames.LEADERBOARD_SUPPRESSED_COMPETITOR_IDS.name(), dbSuppressedCompetitorIds); + if (leaderboard instanceof FlexibleLeaderboard) { + storeFlexibleLeaderboard((FlexibleLeaderboard) leaderboard, dbLeaderboard); + } else if (leaderboard instanceof RegattaLeaderboard) { + storeRegattaLeaderboard((RegattaLeaderboard) leaderboard, dbLeaderboard); + } else { + // at least store the scoring scheme + dbLeaderboard.put(FieldNames.SCORING_SCHEME_TYPE.name(), leaderboard.getScoringScheme().getType().name()); + } + if (leaderboard.getDefaultCourseArea() != null) { + dbLeaderboard.put(FieldNames.COURSE_AREA_ID.name(), leaderboard.getDefaultCourseArea().getId().toString()); + } else { + dbLeaderboard.put(FieldNames.COURSE_AREA_ID.name(), null); + } + storeColumnFactors(leaderboard, dbLeaderboard); + storeLeaderboardCorrectionsAndDiscards(leaderboard, dbLeaderboard); + leaderboardCollection.update(query, dbLeaderboard, /* upsrt */ true, /* multi */ false, WriteConcern.SAFE); + } + + private void storeColumnFactors(Leaderboard leaderboard, BasicDBObject dbLeaderboard) { + DBObject raceColumnFactors = new BasicDBObject(); + for (RaceColumn raceColumn : leaderboard.getRaceColumns()) { + Double explicitFactor = raceColumn.getExplicitFactor(); + if (explicitFactor != null) { + raceColumnFactors.put(MongoUtils.escapeDollarAndDot(raceColumn.getName()), explicitFactor); + } + } + dbLeaderboard.put(FieldNames.LEADERBOARD_COLUMN_FACTORS.name(), raceColumnFactors); + } + + private void storeRegattaLeaderboard(RegattaLeaderboard leaderboard, DBObject dbLeaderboard) { + dbLeaderboard.put(FieldNames.REGATTA_NAME.name(), leaderboard.getRegatta().getName()); + } + + private void storeFlexibleLeaderboard(FlexibleLeaderboard leaderboard, BasicDBObject dbLeaderboard) { + BasicDBList dbRaceColumns = new BasicDBList(); + dbLeaderboard.put(FieldNames.SCORING_SCHEME_TYPE.name(), leaderboard.getScoringScheme().getType().name()); + dbLeaderboard.put(FieldNames.LEADERBOARD_COLUMNS.name(), dbRaceColumns); + for (RaceColumn raceColumn : leaderboard.getRaceColumns()) { + BasicDBObject dbRaceColumn = storeRaceColumn(raceColumn); + dbRaceColumns.add(dbRaceColumn); + } + } + + private void storeLeaderboardCorrectionsAndDiscards(Leaderboard leaderboard, BasicDBObject dbLeaderboard) { + if (leaderboard.hasCarriedPoints()) { + BasicDBList dbCarriedPoints = new BasicDBList(); + dbLeaderboard.put(FieldNames.LEADERBOARD_CARRIED_POINTS_BY_ID.name(), dbCarriedPoints); + for (Entry competitorWithCarriedPoints : leaderboard + .getCompetitorsForWhichThereAreCarriedPoints().entrySet()) { + double carriedPoints = competitorWithCarriedPoints.getValue(); + Competitor competitor = competitorWithCarriedPoints.getKey(); + DBObject dbCarriedPointsForCompetitor = new BasicDBObject(); + dbCarriedPointsForCompetitor.put(FieldNames.COMPETITOR_ID.name(), competitor.getId()); + dbCarriedPointsForCompetitor.put(FieldNames.LEADERBOARD_CARRIED_POINTS.name(), carriedPoints); + dbCarriedPoints.add(dbCarriedPointsForCompetitor); + } + } + BasicDBObject dbScoreCorrections = new BasicDBObject(); + storeScoreCorrections(leaderboard, dbScoreCorrections); + dbLeaderboard.put(FieldNames.LEADERBOARD_SCORE_CORRECTIONS.name(), dbScoreCorrections); + final ResultDiscardingRule resultDiscardingRule = leaderboard.getResultDiscardingRule(); + storeResultDiscardingRule(dbLeaderboard, resultDiscardingRule, FieldNames.LEADERBOARD_DISCARDING_THRESHOLDS); + BasicDBList competitorDisplayNames = new BasicDBList(); + for (Competitor competitor : leaderboard.getCompetitors()) { + String displayNameForCompetitor = leaderboard.getDisplayName(competitor); + if (displayNameForCompetitor != null) { + DBObject dbDisplayName = new BasicDBObject(); + dbDisplayName.put(FieldNames.COMPETITOR_ID.name(), competitor.getId()); + dbDisplayName.put(FieldNames.COMPETITOR_DISPLAY_NAME.name(), displayNameForCompetitor); + competitorDisplayNames.add(dbDisplayName); + } + } + dbLeaderboard.put(FieldNames.LEADERBOARD_COMPETITOR_DISPLAY_NAMES.name(), competitorDisplayNames); + } + + /** + * Stores the result discarding rule to dbObject's field identified by field if the result discarding + * rule is not null and is of type {@link ThresholdBasedResultDiscardingRule}. Otherwise, it is assumed that the + * result discarding rule is otherwise implicitly obtained, e.g., from a definition of a regatta with its series, stored elsewhere. + */ + private void storeResultDiscardingRule(DBObject dbObject, + final ResultDiscardingRule resultDiscardingRule, FieldNames field) { + if (resultDiscardingRule != null && resultDiscardingRule instanceof ThresholdBasedResultDiscardingRule) { + BasicDBList dbResultDiscardingThresholds = new BasicDBList(); + for (int threshold : ((ThresholdBasedResultDiscardingRule) resultDiscardingRule).getDiscardIndexResultsStartingWithHowManyRaces()) { + dbResultDiscardingThresholds.add(threshold); + } + dbObject.put(field.name(), dbResultDiscardingThresholds); + } + } + + private BasicDBObject storeRaceColumn(RaceColumn raceColumn) { + BasicDBObject dbRaceColumn = new BasicDBObject(); + dbRaceColumn.put(FieldNames.LEADERBOARD_COLUMN_NAME.name(), raceColumn.getName()); + dbRaceColumn.put(FieldNames.LEADERBOARD_IS_MEDAL_RACE_COLUMN.name(), raceColumn.isMedalRace()); + storeRaceIdentifiers(raceColumn, dbRaceColumn); + return dbRaceColumn; + } + + private void storeScoreCorrections(Leaderboard leaderboard, BasicDBObject dbScoreCorrections) { + TimePoint now = MillisecondsTimePoint.now(); + SettableScoreCorrection scoreCorrection = leaderboard.getScoreCorrection(); + for (RaceColumn raceColumn : scoreCorrection.getRaceColumnsThatHaveCorrections()) { + BasicDBList dbCorrectionForRace = new BasicDBList(); + for (Competitor competitor : scoreCorrection.getCompetitorsThatHaveCorrectionsIn(raceColumn)) { + // TODO bug 655: make score corrections time dependent + if (scoreCorrection.isScoreCorrected(competitor, raceColumn, now)) { + BasicDBObject dbCorrectionForCompetitor = new BasicDBObject(); + dbCorrectionForCompetitor.put(FieldNames.COMPETITOR_ID.name(), competitor.getId()); + MaxPointsReason maxPointsReason = scoreCorrection.getMaxPointsReason(competitor, raceColumn, now); + if (maxPointsReason != MaxPointsReason.NONE) { + dbCorrectionForCompetitor.put(FieldNames.LEADERBOARD_SCORE_CORRECTION_MAX_POINTS_REASON.name(), + maxPointsReason.name()); + } + Double explicitScoreCorrection = scoreCorrection + .getExplicitScoreCorrection(competitor, raceColumn); + if (explicitScoreCorrection != null) { + dbCorrectionForCompetitor.put(FieldNames.LEADERBOARD_CORRECTED_SCORE.name(), + explicitScoreCorrection); + } + dbCorrectionForRace.add(dbCorrectionForCompetitor); + } + } + if (!dbCorrectionForRace.isEmpty()) { + // using the column name as the key for the score corrections requires re-writing the score corrections + // of a meta-leaderboard if the name of one of its leaderboards changes + dbScoreCorrections.put(MongoUtils.escapeDollarAndDot(raceColumn.getName()), dbCorrectionForRace); + } + } + final TimePoint timePointOfLastCorrectionsValidity = scoreCorrection.getTimePointOfLastCorrectionsValidity(); + if (timePointOfLastCorrectionsValidity != null) { + dbScoreCorrections.put(FieldNames.LEADERBOARD_SCORE_CORRECTION_TIMESTAMP.name(), timePointOfLastCorrectionsValidity.asMillis()); + } + if (scoreCorrection.getComment() != null) { + dbScoreCorrections.put(FieldNames.LEADERBOARD_SCORE_CORRECTION_COMMENT.name(), scoreCorrection.getComment()); + } + } + + @Override + public void removeLeaderboard(String leaderboardName) { + DBCollection leaderboardCollection = database.getCollection(CollectionNames.LEADERBOARDS.name()); + BasicDBObject query = new BasicDBObject(FieldNames.LEADERBOARD_NAME.name(), leaderboardName); + leaderboardCollection.remove(query); + } + + @Override + public void renameLeaderboard(String oldName, String newName) { + DBCollection leaderboardCollection = database.getCollection(CollectionNames.LEADERBOARDS.name()); + BasicDBObject query = new BasicDBObject(FieldNames.LEADERBOARD_NAME.name(), oldName); + BasicDBObject renameUpdate = new BasicDBObject("$set", new BasicDBObject(FieldNames.LEADERBOARD_NAME.name(), newName)); + leaderboardCollection.update(query, renameUpdate, /* upsert */ true, /* multi */ false, WriteConcern.SAFE); + } + + @Override + public void storeLeaderboardGroup(LeaderboardGroup leaderboardGroup) { + DBCollection leaderboardGroupCollection = database.getCollection(CollectionNames.LEADERBOARD_GROUPS.name()); + DBCollection leaderboardCollection = database.getCollection(CollectionNames.LEADERBOARDS.name()); + + try { + leaderboardGroupCollection.createIndex(new BasicDBObject(FieldNames.LEADERBOARD_GROUP_NAME.name(), 1)); + } catch (NullPointerException npe) { + // sometimes, for reasons yet to be clarified, ensuring an index on the name field causes an NPE + logger.log(Level.SEVERE, "storeLeaderboardGroup", npe); + } + BasicDBObject query = new BasicDBObject(FieldNames.LEADERBOARD_GROUP_NAME.name(), leaderboardGroup.getName()); + BasicDBObject dbLeaderboardGroup = new BasicDBObject(); + dbLeaderboardGroup.put(FieldNames.LEADERBOARD_GROUP_UUID.name(), leaderboardGroup.getId()); + dbLeaderboardGroup.put(FieldNames.LEADERBOARD_GROUP_NAME.name(), leaderboardGroup.getName()); + dbLeaderboardGroup.put(FieldNames.LEADERBOARD_GROUP_DESCRIPTION.name(), leaderboardGroup.getDescription()); + dbLeaderboardGroup.put(FieldNames.LEADERBOARD_GROUP_DISPLAY_NAME.name(), leaderboardGroup.getDisplayName()); + dbLeaderboardGroup.put(FieldNames.LEADERBOARD_GROUP_DISPLAY_IN_REVERSE_ORDER.name(), leaderboardGroup.isDisplayGroupsInReverseOrder()); + final Leaderboard overallLeaderboard = leaderboardGroup.getOverallLeaderboard(); + if (overallLeaderboard != null) { + BasicDBObject overallLeaderboardQuery = new BasicDBObject(FieldNames.LEADERBOARD_NAME.name(), overallLeaderboard.getName()); + DBObject dbOverallLeaderboard = leaderboardCollection.findOne(overallLeaderboardQuery); + if (dbOverallLeaderboard == null) { + storeLeaderboard(overallLeaderboard); + dbOverallLeaderboard = leaderboardCollection.findOne(overallLeaderboardQuery); + } + ObjectId dbOverallLeaderboardId = (ObjectId) dbOverallLeaderboard.get("_id"); + dbLeaderboardGroup.put(FieldNames.LEADERBOARD_GROUP_OVERALL_LEADERBOARD.name(), dbOverallLeaderboardId); + } + BasicDBList dbLeaderboardIds = new BasicDBList(); + for (Leaderboard leaderboard : leaderboardGroup.getLeaderboards()) { + BasicDBObject leaderboardQuery = new BasicDBObject(FieldNames.LEADERBOARD_NAME.name(), leaderboard.getName()); + DBObject dbLeaderboard = leaderboardCollection.findOne(leaderboardQuery); + if (dbLeaderboard == null) { + storeLeaderboard(leaderboard); + dbLeaderboard = leaderboardCollection.findOne(leaderboardQuery); + } + ObjectId dbLeaderboardId = (ObjectId) dbLeaderboard.get("_id"); + dbLeaderboardIds.add(dbLeaderboardId); + } + dbLeaderboardGroup.put(FieldNames.LEADERBOARD_GROUP_LEADERBOARDS.name(), dbLeaderboardIds); + leaderboardGroupCollection.update(query, dbLeaderboardGroup, true, false, WriteConcern.SAFE); + } + + @Override + public void removeLeaderboardGroup(String groupName) { + DBCollection leaderboardGroupCollection = database.getCollection(CollectionNames.LEADERBOARD_GROUPS.name()); + BasicDBObject query = new BasicDBObject(FieldNames.LEADERBOARD_GROUP_NAME.name(), groupName); + leaderboardGroupCollection.remove(query); + } + + @Override + public void renameLeaderboardGroup(String oldName, String newName) { + DBCollection leaderboardGroupCollection = database.getCollection(CollectionNames.LEADERBOARD_GROUPS.name()); + BasicDBObject query = new BasicDBObject(FieldNames.LEADERBOARD_GROUP_NAME.name(), oldName); + BasicDBObject update = new BasicDBObject("$set", new BasicDBObject(FieldNames.LEADERBOARD_GROUP_NAME.name(), newName)); + leaderboardGroupCollection.update(query, update, /* upsert */ true, /* multi */ false, WriteConcern.SAFE); + } + + @Override + public void storeServerConfiguration(SailingServerConfiguration serverConfiguration) { + DBCollection serverCollection = database.getCollection(CollectionNames.SERVER_CONFIGURATION.name()); + DBObject newServerConfig = new BasicDBObject(); + newServerConfig.put(FieldNames.SERVER_IS_STANDALONE.name(), serverConfiguration.isStandaloneServer()); + DBObject currentServerConfig = serverCollection.findOne(); + if(currentServerConfig != null) { + serverCollection.update(currentServerConfig, newServerConfig, /* upsrt */ true, /* multi */ false, WriteConcern.SAFE); + } else { + serverCollection.save(newServerConfig); + } + } + + @Override + public void storeSailingServer(RemoteSailingServerReference server) { + DBCollection serverCollection = database.getCollection(CollectionNames.SAILING_SERVERS.name()); + serverCollection.createIndex(new BasicDBObject(FieldNames.SERVER_NAME.name(), 1)); + DBObject query = new BasicDBObject(); + query.put(FieldNames.SERVER_NAME.name(), server.getName()); + DBObject serverDBObject = new BasicDBObject(); + serverDBObject.put(FieldNames.SERVER_NAME.name(), server.getName()); + serverDBObject.put(FieldNames.SERVER_URL.name(), server.getURL().toExternalForm()); + serverCollection.update(query, serverDBObject, /* upsrt */ true, /* multi */ false, WriteConcern.SAFE); + } + + @Override + public void removeSailingServer(String name) { + DBCollection serverCollection = database.getCollection(CollectionNames.SAILING_SERVERS.name()); + BasicDBObject query = new BasicDBObject(FieldNames.SERVER_NAME.name(), name); + serverCollection.remove(query); + } + + /** + * StoreEvent() uses some deprecated methods of event to keep backward compatibility. + */ + @SuppressWarnings("deprecation") + @Override + public void storeEvent(Event event) { + DBCollection eventCollection = database.getCollection(CollectionNames.EVENTS.name()); + eventCollection.createIndex(new BasicDBObject(FieldNames.EVENT_ID.name(), 1)); + DBObject query = new BasicDBObject(); + query.put(FieldNames.EVENT_ID.name(), event.getId()); + DBObject eventDBObject = new BasicDBObject(); + eventDBObject.put(FieldNames.EVENT_NAME.name(), event.getName()); + eventDBObject.put(FieldNames.EVENT_DESCRIPTION.name(), event.getDescription()); + eventDBObject.put(FieldNames.EVENT_ID.name(), event.getId()); + eventDBObject.put(FieldNames.EVENT_LOGO_IMAGE_URL.name(), event.getLogoImageURL() != null ? event.getLogoImageURL().toString() : null); + eventDBObject.put(FieldNames.EVENT_OFFICIAL_WEBSITE_URL.name(), event.getOfficialWebsiteURL() != null ? event.getOfficialWebsiteURL().toString() : null); + eventDBObject.put(FieldNames.EVENT_SAILORS_INFO_WEBSITE_URL.name(), event.getSailorsInfoWebsiteURL() != null ? event.getSailorsInfoWebsiteURL().toString() : null); + storeTimePoint(event.getStartDate(), eventDBObject, FieldNames.EVENT_START_DATE); + storeTimePoint(event.getEndDate(), eventDBObject, FieldNames.EVENT_END_DATE); + eventDBObject.put(FieldNames.EVENT_IS_PUBLIC.name(), event.isPublic()); + DBObject venueDBObject = getVenueAsDBObject(event.getVenue()); + eventDBObject.put(FieldNames.VENUE.name(), venueDBObject); + BasicDBList imageURLs = new BasicDBList(); + for (URL imageURL : event.getImageURLs()) { + imageURLs.add(imageURL.toString()); + } + eventDBObject.put(FieldNames.EVENT_IMAGE_URLS.name(), imageURLs); + BasicDBList videoURLs = new BasicDBList(); + for (URL videoURL : event.getVideoURLs()) { + videoURLs.add(videoURL.toString()); + } + eventDBObject.put(FieldNames.EVENT_VIDEO_URLS.name(), videoURLs); + BasicDBList sponsorImageURLs = new BasicDBList(); + for (URL sponsorImageURL : event.getSponsorImageURLs()) { + sponsorImageURLs.add(sponsorImageURL.toString()); + } + eventDBObject.put(FieldNames.EVENT_SPONSOR_IMAGE_URLS.name(), sponsorImageURLs); + BasicDBList images = new BasicDBList(); + for (ImageDescriptor image : event.getImages()) { + DBObject imageObject = createImageObject(image); + images.add(imageObject); + } + eventDBObject.put(FieldNames.EVENT_IMAGES.name(), images); + BasicDBList videos = new BasicDBList(); + for (VideoDescriptor video: event.getVideos()) { + DBObject videoObject = createVideoObject(video); + videos.add(videoObject); + } + eventDBObject.put(FieldNames.EVENT_VIDEOS.name(), videos); + eventCollection.update(query, eventDBObject, /* upsrt */ true, /* multi */ false, WriteConcern.SAFE); + // now store the links to the leaderboard groups + DBCollection linksCollection = database.getCollection(CollectionNames.LEADERBOARD_GROUP_LINKS_FOR_EVENTS.name()); + linksCollection.createIndex(new BasicDBObject(FieldNames.EVENT_ID.name(), 1)); + BasicDBList lgUUIDs = new BasicDBList(); + for (LeaderboardGroup lg : event.getLeaderboardGroups()) { + lgUUIDs.add(lg.getId()); + } + DBObject dbLinks = new BasicDBObject(); + dbLinks.put(FieldNames.EVENT_ID.name(), event.getId()); + dbLinks.put(FieldNames.LEADERBOARD_GROUP_UUID.name(), lgUUIDs); + linksCollection.update(query, dbLinks, /* upsrt */ true, /* multi */ false, WriteConcern.SAFE); + } + + @Override + public void renameEvent(Serializable id, String newName) { + DBCollection eventCollection = database.getCollection(CollectionNames.EVENTS.name()); + BasicDBObject query = new BasicDBObject(FieldNames.EVENT_ID.name(), id); + BasicDBObject renameUpdate = new BasicDBObject("$set", new BasicDBObject(FieldNames.EVENT_NAME.name(), newName)); + eventCollection.update(query, renameUpdate, /* upsert */ true, /* multi */ false, WriteConcern.SAFE); + } + + @Override + public void removeEvent(Serializable id) { + DBCollection eventsCollection = database.getCollection(CollectionNames.EVENTS.name()); + BasicDBObject query = new BasicDBObject(FieldNames.EVENT_ID.name(), id); + eventsCollection.remove(query); + } + + private DBObject getVenueAsDBObject(Venue venue) { + DBObject result = new BasicDBObject(); + result.put(FieldNames.VENUE_NAME.name(), venue.getName()); + BasicDBList courseAreaList = new BasicDBList(); + result.put(FieldNames.COURSE_AREAS.name(), courseAreaList); + for (CourseArea courseArea : venue.getCourseAreas()) { + DBObject dbCourseArea = new BasicDBObject(); + courseAreaList.add(dbCourseArea); + dbCourseArea.put(FieldNames.COURSE_AREA_NAME.name(), courseArea.getName()); + dbCourseArea.put(FieldNames.COURSE_AREA_ID.name(), courseArea.getId()); + } + return result; + } + + @Override + public void storeRegatta(Regatta regatta) { + DBCollection regattasCollection = database.getCollection(CollectionNames.REGATTAS.name()); + regattasCollection.createIndex(new BasicDBObject(FieldNames.REGATTA_NAME.name(), 1)); + regattasCollection.createIndex(new BasicDBObject(FieldNames.REGATTA_ID.name(), 1)); + DBObject dbRegatta = new BasicDBObject(); + DBObject query = new BasicDBObject(FieldNames.REGATTA_NAME.name(), regatta.getName()); + dbRegatta.put(FieldNames.REGATTA_NAME.name(), regatta.getName()); + dbRegatta.put(FieldNames.REGATTA_ID.name(), regatta.getId()); + storeTimePoint(regatta.getStartDate(), dbRegatta, FieldNames.REGATTA_START_DATE); + storeTimePoint(regatta.getEndDate(), dbRegatta, FieldNames.REGATTA_END_DATE); + dbRegatta.put(FieldNames.SCORING_SCHEME_TYPE.name(), regatta.getScoringScheme().getType().name()); + if (regatta.getBoatClass() != null) { + dbRegatta.put(FieldNames.BOAT_CLASS_NAME.name(), regatta.getBoatClass().getName()); + dbRegatta.put(FieldNames.BOAT_CLASS_TYPICALLY_STARTS_UPWIND.name(), regatta.getBoatClass().typicallyStartsUpwind()); + } + dbRegatta.put(FieldNames.REGATTA_SERIES.name(), storeSeries(regatta.getSeries())); + + if (regatta.getDefaultCourseArea() != null) { + dbRegatta.put(FieldNames.COURSE_AREA_ID.name(), regatta.getDefaultCourseArea().getId().toString()); + } else { + dbRegatta.put(FieldNames.COURSE_AREA_ID.name(), null); + } + if (regatta.getRegattaConfiguration() != null) { + JsonSerializer serializer = RegattaConfigurationJsonSerializer.create(); + JSONObject json = serializer.serialize(regatta.getRegattaConfiguration()); + DBObject configurationObject = (DBObject) JSON.parse(json.toString()); + dbRegatta.put(FieldNames.REGATTA_REGATTA_CONFIGURATION.name(), configurationObject); + } + dbRegatta.put(FieldNames.REGATTA_USE_START_TIME_INFERENCE.name(), regatta.useStartTimeInference()); + dbRegatta.put(FieldNames.REGATTA_RANKING_METRIC.name(), storeRankingMetric(regatta)); + regattasCollection.update(query, dbRegatta, /* upsrt */ true, /* multi */ false, WriteConcern.SAFE); + } + + private DBObject storeRankingMetric(Regatta regatta) { + DBObject rankingMetricJson = new BasicDBObject(); + final String rankingMetricTypeName = regatta.getRankingMetricType().name(); + rankingMetricJson.put(FieldNames.REGATTA_RANKING_METRIC_TYPE.name(), rankingMetricTypeName); + return rankingMetricJson; + } + + @Override + public void removeRegatta(Regatta regatta) { + DBCollection regattasCollection = database.getCollection(CollectionNames.REGATTAS.name()); + DBObject query = new BasicDBObject(FieldNames.REGATTA_NAME.name(), regatta.getName()); + regattasCollection.remove(query); + } + + private BasicDBList storeSeries(Iterable series) { + BasicDBList dbSeries = new BasicDBList(); + for (Series s : series) { + dbSeries.add(storeSeries(s)); + } + return dbSeries; + } + + private DBObject storeSeries(Series s) { + DBObject dbSeries = new BasicDBObject(); + dbSeries.put(FieldNames.SERIES_NAME.name(), s.getName()); + dbSeries.put(FieldNames.SERIES_IS_MEDAL.name(), s.isMedal()); + dbSeries.put(FieldNames.SERIES_HAS_SPLIT_FLEET_CONTIGUOUS_SCORING.name(), s.hasSplitFleetContiguousScoring()); + dbSeries.put(FieldNames.SERIES_STARTS_WITH_ZERO_SCORE.name(), s.isStartsWithZeroScore()); + dbSeries.put(FieldNames.SERIES_STARTS_WITH_NON_DISCARDABLE_CARRY_FORWARD.name(), s.isFirstColumnIsNonDiscardableCarryForward()); + BasicDBList dbFleets = new BasicDBList(); + for (Fleet fleet : s.getFleets()) { + dbFleets.add(storeFleet(fleet)); + } + dbSeries.put(FieldNames.SERIES_FLEETS.name(), dbFleets); + BasicDBList dbRaceColumns = new BasicDBList(); + for (RaceColumn raceColumn : s.getRaceColumns()) { + dbRaceColumns.add(storeRaceColumn(raceColumn)); + } + dbSeries.put(FieldNames.SERIES_RACE_COLUMNS.name(), dbRaceColumns); + if (s.getResultDiscardingRule() != null) { + storeResultDiscardingRule(dbSeries, s.getResultDiscardingRule(), FieldNames.SERIES_DISCARDING_THRESHOLDS); + } + return dbSeries; + } + + private DBObject storeFleet(Fleet fleet) { + DBObject dbFleet = new BasicDBObject(FieldNames.FLEET_NAME.name(), fleet.getName()); + if (fleet instanceof FleetImpl) { + dbFleet.put(FieldNames.FLEET_ORDERING.name(), ((FleetImpl) fleet).getOrdering()); + if(fleet.getColor() != null) { + com.sap.sse.common.Util.Triple colorAsRGB = fleet.getColor().getAsRGB(); + // we save the color as a integer value representing the RGB values + int colorAsInt = (256 * 256 * colorAsRGB.getC()) + colorAsRGB.getB() * 256 + colorAsRGB.getA(); + dbFleet.put(FieldNames.FLEET_COLOR.name(), colorAsInt); + } else { + dbFleet.put(FieldNames.FLEET_COLOR.name(), null); + } + } + return dbFleet; + } + + @Override + public void storeRegattaForRaceID(String raceIDAsString, Regatta regatta) { + DBCollection regattaForRaceIDCollection = database.getCollection(CollectionNames.REGATTA_FOR_RACE_ID.name()); + DBObject query = new BasicDBObject(FieldNames.RACE_ID_AS_STRING.name(), raceIDAsString); + DBObject entry = new BasicDBObject(FieldNames.RACE_ID_AS_STRING.name(), raceIDAsString); + entry.put(FieldNames.REGATTA_NAME.name(), regatta.getName()); + regattaForRaceIDCollection.update(query, entry, /* upsrt */ true, /* multi */ false, WriteConcern.SAFE); + } + + @Override + public void removeRegattaForRaceID(String raceIDAsString, Regatta regatta) { + DBCollection regattaForRaceIDCollection = database.getCollection(CollectionNames.REGATTA_FOR_RACE_ID.name()); + DBObject query = new BasicDBObject(FieldNames.RACE_ID_AS_STRING.name(), raceIDAsString); + regattaForRaceIDCollection.remove(query); + } + + public DBCollection getRaceLogCollection() { + DBCollection result = database.getCollection(CollectionNames.RACE_LOGS.name()); + result.createIndex(new BasicDBObject(FieldNames.RACE_LOG_IDENTIFIER.name(), null)); + return result; + } + + private void storeRaceLogEventAuthor(DBObject dbObject, AbstractLogEventAuthor author) { + if (author != null) { + dbObject.put(FieldNames.RACE_LOG_EVENT_AUTHOR_NAME.name(), author.getName()); + dbObject.put(FieldNames.RACE_LOG_EVENT_AUTHOR_PRIORITY.name(), author.getPriority()); + } + } + + public DBObject storeRaceLogEntry(RaceLogIdentifier raceLogIdentifier, RaceLogFlagEvent flagEvent) { + BasicDBObject result = new BasicDBObject(); + storeRaceLogIdentifier(raceLogIdentifier, result); + result.put(FieldNames.RACE_LOG_EVENT.name(), storeRaceLogFlagEvent(flagEvent)); + return result; + } + + private void storeRaceLogIdentifier(RaceLogIdentifier raceLogIdentifier, DBObject result) { + result.put(FieldNames.RACE_LOG_IDENTIFIER.name(), TripleSerializer.serialize(raceLogIdentifier.getIdentifier())); + } + + public DBObject storeRaceLogEntry(RaceLogIdentifier raceLogIdentifier, RaceLogStartTimeEvent startTimeEvent) { + BasicDBObject result = new BasicDBObject(); + storeRaceLogIdentifier(raceLogIdentifier, result); + result.put(FieldNames.RACE_LOG_EVENT.name(), storeRaceLogStartTimeEvent(startTimeEvent)); + return result; + } + + public DBObject storeRaceLogEntry(RaceLogIdentifier raceLogIdentifier, RaceLogPassChangeEvent passChangeEvent) { + BasicDBObject result = new BasicDBObject(); + storeRaceLogIdentifier(raceLogIdentifier, result); + result.put(FieldNames.RACE_LOG_EVENT.name(), storeRaceLogPassChangeEvent(passChangeEvent)); + return result; + } + + public DBObject storeRaceLogEntry(RaceLogIdentifier raceLogIdentifier, RaceLogRaceStatusEvent raceStatusEvent) { + BasicDBObject result = new BasicDBObject(); + storeRaceLogIdentifier(raceLogIdentifier, result); + result.put(FieldNames.RACE_LOG_EVENT.name(), storeRaceLogRaceStatusEvent(raceStatusEvent)); + return result; + } + + public DBObject storeRaceLogEntry(RaceLogIdentifier raceLogIdentifier, RaceLogCourseAreaChangedEvent courseAreaChangedEvent) { + BasicDBObject result = new BasicDBObject(); + storeRaceLogIdentifier(raceLogIdentifier, result); + result.put(FieldNames.RACE_LOG_EVENT.name(), storeRaceLogCourseAreaChangedEvent(courseAreaChangedEvent)); + return result; + } + + public DBObject storeRaceLogEntry(RaceLogIdentifier raceLogIdentifier, RaceLogCourseDesignChangedEvent courseDesignChangedEvent) { + BasicDBObject result = new BasicDBObject(); + storeRaceLogIdentifier(raceLogIdentifier, result); + result.put(FieldNames.RACE_LOG_EVENT.name(), storeRaceLogCourseDesignChangedEvent(courseDesignChangedEvent)); + return result; + } + + public DBObject storeRaceLogEntry(RaceLogIdentifier raceLogIdentifier, RaceLogFinishPositioningListChangedEvent finishPositioningListChangedEvent) { + BasicDBObject result = new BasicDBObject(); + storeRaceLogIdentifier(raceLogIdentifier, result); + result.put(FieldNames.RACE_LOG_EVENT.name(), storeRaceLogFinishPositioningListChangedEvent(finishPositioningListChangedEvent)); + return result; + } + + public DBObject storeRaceLogEntry(RaceLogIdentifier raceLogIdentifier, RaceLogFinishPositioningConfirmedEvent finishPositioningConfirmedEvent) { + BasicDBObject result = new BasicDBObject(); + storeRaceLogIdentifier(raceLogIdentifier, result); + result.put(FieldNames.RACE_LOG_EVENT.name(), storeRaceLogFinishPositioningConfirmedEvent(finishPositioningConfirmedEvent)); + return result; + } + + public DBObject storeRaceLogEntry(RaceLogIdentifier raceLogIdentifier, RaceLogPathfinderEvent pathfinderEvent) { + BasicDBObject result = new BasicDBObject(); + storeRaceLogIdentifier(raceLogIdentifier, result); + result.put(FieldNames.RACE_LOG_EVENT.name(), storeRaceLogPathfinderEvent(pathfinderEvent)); + return result; + } + + public DBObject storeRaceLogEntry(RaceLogIdentifier raceLogIdentifier, RaceLogGateLineOpeningTimeEvent gateLineOpeningTimeEvent) { + BasicDBObject result = new BasicDBObject(); + storeRaceLogIdentifier(raceLogIdentifier, result); + result.put(FieldNames.RACE_LOG_EVENT.name(), storeRaceLogGateLineOpeningTimeEvent(gateLineOpeningTimeEvent)); + return result; + } + + public DBObject storeRaceLogEntry(RaceLogIdentifier raceLogIdentifier, RaceLogStartProcedureChangedEvent event) { + DBObject result = new BasicDBObject(); + storeRaceLogIdentifier(raceLogIdentifier, result); + result.put(FieldNames.RACE_LOG_EVENT.name(), storeRaceLogStartProcedureChangedEvent(event)); + return result; + } + + public DBObject storeRaceLogEntry(RaceLogIdentifier raceLogIdentifier, RaceLogProtestStartTimeEvent event) { + DBObject result = new BasicDBObject(); + storeRaceLogIdentifier(raceLogIdentifier, result); + result.put(FieldNames.RACE_LOG_EVENT.name(), storeRaceLogProtestStartTimeEvent(event)); + return result; + } + + public DBObject storeRaceLogEntry(RaceLogIdentifier raceLogIdentifier, RaceLogWindFixEvent event) { + DBObject result = new BasicDBObject(); + storeRaceLogIdentifier(raceLogIdentifier, result); + result.put(FieldNames.RACE_LOG_EVENT.name(), storeRaceLogWindFix(event)); + return result; + } + + public DBObject storeRaceLogEntry(RaceLogIdentifier raceLogIdentifier, RaceLogDenoteForTrackingEvent event) { + BasicDBObject result = new BasicDBObject(); + storeRaceLogIdentifier(raceLogIdentifier, result); + result.put(FieldNames.RACE_LOG_EVENT.name(), storeRaceLogDenoteForTrackingEvent(event)); + return result; + } + + public DBObject storeRaceLogEntry(RaceLogIdentifier raceLogIdentifier, RaceLogStartTrackingEvent event) { + BasicDBObject result = new BasicDBObject(); + storeRaceLogIdentifier(raceLogIdentifier, result); + result.put(FieldNames.RACE_LOG_EVENT.name(), storeRaceLogStartTrackingEvent(event)); + return result; + } + + public DBObject storeRaceLogEntry(RaceLogIdentifier raceLogIdentifier, RaceLogRevokeEvent event) { + BasicDBObject result = new BasicDBObject(); + storeRaceLogIdentifier(raceLogIdentifier, result); + result.put(FieldNames.RACE_LOG_EVENT.name(), storeRaceLogRevokeEvent(event)); + return result; + } + + public DBObject storeRaceLogEntry(RaceLogIdentifier raceLogIdentifier, RaceLogRegisterCompetitorEvent event) { + BasicDBObject result = new BasicDBObject(); + storeRaceLogIdentifier(raceLogIdentifier, result); + result.put(FieldNames.RACE_LOG_EVENT.name(), storeRaceLogRegisterCompetitorEvent(event)); + return result; + } + + public DBObject storeRaceLogEntry(RaceLogIdentifier raceLogIdentifier, RaceLogEndOfTrackingEvent event) { + BasicDBObject result = new BasicDBObject(); + storeRaceLogIdentifier(raceLogIdentifier, result); + result.put(FieldNames.RACE_LOG_EVENT.name(), storeRaceLogEndOfTrackingEvent(event)); + return result; + } + + public DBObject storeRaceLogEntry(RaceLogIdentifier raceLogIdentifier, RaceLogStartOfTrackingEvent event) { + BasicDBObject result = new BasicDBObject(); + storeRaceLogIdentifier(raceLogIdentifier, result); + result.put(FieldNames.RACE_LOG_EVENT.name(), storeRaceLogStartOfTrackingEvent(event)); + return result; + } + + public DBObject storeRaceLogEntry(RaceLogIdentifier raceLogIdentifier, RaceLogAdditionalScoringInformationEvent event) { + BasicDBObject result = new BasicDBObject(); + storeRaceLogIdentifier(raceLogIdentifier, result); + result.put(FieldNames.RACE_LOG_EVENT.name(), storeAdditionalScoringInformation(event)); + return result; + } + + private Object storeAdditionalScoringInformation(RaceLogAdditionalScoringInformationEvent event) { + DBObject result = new BasicDBObject(); + storeRaceLogEventProperties(event, result); + result.put(FieldNames.RACE_LOG_EVENT_CLASS.name(), RaceLogAdditionalScoringInformationEvent.class.getSimpleName()); + result.put(FieldNames.RACE_LOG_ADDITIONAL_SCORING_INFORMATION_TYPE.name(), event.getType().name()); + return result; + } + + public DBObject storeRaceLogEntry(RaceLogIdentifier raceLogIdentifier, RaceLogFixedMarkPassingEvent event) { + BasicDBObject result = new BasicDBObject(); + storeRaceLogIdentifier(raceLogIdentifier, result); + result.put(FieldNames.RACE_LOG_EVENT.name(), storeRaceLogFixedMarkPassingEvent(event)); + return result; + } + + public DBObject storeRaceLogEntry(RaceLogIdentifier raceLogIdentifier, RaceLogSuppressedMarkPassingsEvent event) { + BasicDBObject result = new BasicDBObject(); + storeRaceLogIdentifier(raceLogIdentifier, result); + result.put(FieldNames.RACE_LOG_EVENT.name(), storeRaceLogSuppressedMarkPassingsEvent(event)); + return result; + } + + private Object storeRaceLogWindFix(RaceLogWindFixEvent event) { + DBObject result = new BasicDBObject(); + storeRaceLogEventProperties(event, result); + result.put(FieldNames.RACE_LOG_EVENT_CLASS.name(), RaceLogWindFixEvent.class.getSimpleName()); + result.put(FieldNames.WIND.name(), storeWind(event.getWindFix())); + result.put(FieldNames.IS_MAGNETIC.name(), event.isMagnetic()); + return result; + } + + private Object storeRaceLogProtestStartTimeEvent(RaceLogProtestStartTimeEvent event) { + DBObject result = new BasicDBObject(); + storeRaceLogEventProperties(event, result); + result.put(FieldNames.RACE_LOG_EVENT_CLASS.name(), RaceLogProtestStartTimeEvent.class.getSimpleName()); + storeTimePoint(event.getProtestStartTime(), result, FieldNames.RACE_LOG_PROTEST_START_TIME); + return result; + } + + private Object storeRaceLogEndOfTrackingEvent(RaceLogEndOfTrackingEvent event) { + DBObject result = new BasicDBObject(); + storeRaceLogEventProperties(event, result); + result.put(FieldNames.RACE_LOG_EVENT_CLASS.name(), RaceLogEndOfTrackingEvent.class.getSimpleName()); + return result; + } + + private Object storeRaceLogStartOfTrackingEvent(RaceLogStartOfTrackingEvent event) { + DBObject result = new BasicDBObject(); + storeRaceLogEventProperties(event, result); + result.put(FieldNames.RACE_LOG_EVENT_CLASS.name(), RaceLogStartOfTrackingEvent.class.getSimpleName()); + return result; + } + + private Object storeRaceLogStartProcedureChangedEvent(RaceLogStartProcedureChangedEvent event) { + DBObject result = new BasicDBObject(); + storeRaceLogEventProperties(event, result); + result.put(FieldNames.RACE_LOG_EVENT_CLASS.name(), RaceLogStartProcedureChangedEvent.class.getSimpleName()); + result.put(FieldNames.RACE_LOG_START_PROCEDURE_TYPE.name(), event.getStartProcedureType().name()); + return result; + } + + private Object storeRaceLogPathfinderEvent(RaceLogPathfinderEvent pathfinderEvent) { + DBObject result = new BasicDBObject(); + storeRaceLogEventProperties(pathfinderEvent, result); + result.put(FieldNames.RACE_LOG_EVENT_CLASS.name(), RaceLogPathfinderEvent.class.getSimpleName()); + result.put(FieldNames.RACE_LOG_PATHFINDER_ID.name(), pathfinderEvent.getPathfinderId()); + return result; + } + + private void storeDeviceMappingEvent(RegattaLogDeviceMappingEvent event, DBObject result, FieldNames fromField, FieldNames toField) { + try { + result.put(FieldNames.DEVICE_ID.name(), storeDeviceId(deviceIdentifierServiceFinder, event.getDevice())); + } catch (TransformationException | NoCorrespondingServiceRegisteredException e) { + logger.log(Level.WARNING, "Could not store device identifier for mappng event", e); + } + if (event.getFrom() != null) { + storeTimePoint(event.getFrom(), result, fromField); + } + if (event.getTo() != null) { + storeTimePoint(event.getTo(), result, toField); + } + } + + private Object storeRaceLogDenoteForTrackingEvent(RaceLogDenoteForTrackingEvent event) { + DBObject result = new BasicDBObject(); + storeRaceLogEventProperties(event, result); + result.put(FieldNames.RACE_LOG_EVENT_CLASS.name(), RaceLogDenoteForTrackingEvent.class.getSimpleName()); + result.put(FieldNames.RACE_NAME.name(), event.getRaceName()); + result.put(FieldNames.BOAT_CLASS_NAME.name(), event.getBoatClass().getName()); + result.put(FieldNames.RACE_ID.name(), event.getRaceId()); + return result; + } + + private Object storeRaceLogStartTrackingEvent(RaceLogStartTrackingEvent event) { + DBObject result = new BasicDBObject(); + storeRaceLogEventProperties(event, result); + result.put(FieldNames.RACE_LOG_EVENT_CLASS.name(), RaceLogStartTrackingEvent.class.getSimpleName()); + return result; + } + + private Object storeRaceLogRevokeEvent(RaceLogRevokeEvent event) { + DBObject result = new BasicDBObject(); + storeRaceLogEventProperties(event, result); + result.put(FieldNames.RACE_LOG_EVENT_CLASS.name(), RaceLogRevokeEvent.class.getSimpleName()); + result.put(FieldNames.RACE_LOG_REVOKED_EVENT_ID.name(), event.getRevokedEventId()); + result.put(FieldNames.RACE_LOG_REVOKED_EVENT_TYPE.name(), event.getRevokedEventType()); + result.put(FieldNames.RACE_LOG_REVOKED_EVENT_SHORT_INFO.name(), event.getRevokedEventShortInfo()); + result.put(FieldNames.RACE_LOG_REVOKED_REASON.name(), event.getReason()); + return result; + } + + private Object storeRaceLogRegisterCompetitorEvent(RaceLogRegisterCompetitorEvent event) { + DBObject result = new BasicDBObject(); + storeRaceLogEventProperties(event, result); + result.put(FieldNames.RACE_LOG_EVENT_CLASS.name(), RaceLogRegisterCompetitorEvent.class.getSimpleName()); + result.put(FieldNames.RACE_LOG_COMPETITOR_ID.name(), event.getCompetitor().getId()); + return result; + } + + public DBObject storeRaceLogEntry(RaceLogIdentifier raceLogIdentifier, RaceLogUseCompetitorsFromRaceLogEvent event) { + DBObject result = new BasicDBObject(); + storeRaceLogEventProperties(event, result); + result.put(FieldNames.RACE_LOG_EVENT_CLASS.name(), RaceLogUseCompetitorsFromRaceLogEvent.class.getSimpleName()); + return result; + } + + private Object storeRaceLogFixedMarkPassingEvent(RaceLogFixedMarkPassingEvent event) { + DBObject result = new BasicDBObject(); + storeRaceLogEventProperties(event, result); + result.put(FieldNames.RACE_LOG_EVENT_CLASS.name(), RaceLogFixedMarkPassingEvent.class.getSimpleName()); + result.put(FieldNames.INDEX_OF_PASSED_WAYPOINT.name(), event.getZeroBasedIndexOfPassedWaypoint()); + result.put(FieldNames.TIMEPOINT_OF_FIXED_MARKPASSING.name(), event.getTimePointOfFixedPassing().asMillis()); + return result; + } + + private Object storeRaceLogSuppressedMarkPassingsEvent(RaceLogSuppressedMarkPassingsEvent event) { + DBObject result = new BasicDBObject(); + storeRaceLogEventProperties(event, result); + result.put(FieldNames.RACE_LOG_EVENT_CLASS.name(), RaceLogSuppressedMarkPassingsEvent.class.getSimpleName()); + result.put(FieldNames.INDEX_OF_FIRST_SUPPRESSED_WAYPOINT.name(), event.getZeroBasedIndexOfFirstSuppressedWaypoint()); + return result; + } + + public DBObject storeRaceLogFlagEvent(RaceLogFlagEvent flagEvent) { + DBObject result = new BasicDBObject(); + storeRaceLogEventProperties(flagEvent, result); + result.put(FieldNames.RACE_LOG_EVENT_CLASS.name(), RaceLogFlagEvent.class.getSimpleName()); + result.put(FieldNames.RACE_LOG_EVENT_FLAG_UPPER.name(), flagEvent.getUpperFlag().name()); + result.put(FieldNames.RACE_LOG_EVENT_FLAG_LOWER.name(), flagEvent.getLowerFlag().name()); + result.put(FieldNames.RACE_LOG_EVENT_FLAG_DISPLAYED.name(), String.valueOf(flagEvent.isDisplayed())); + return result; + } + + private DBObject storeRaceLogStartTimeEvent(RaceLogStartTimeEvent startTimeEvent) { + DBObject result = new BasicDBObject(); + storeRaceLogEventProperties(startTimeEvent, result); + result.put(FieldNames.RACE_LOG_EVENT_CLASS.name(), RaceLogStartTimeEvent.class.getSimpleName()); + storeTimePoint(startTimeEvent.getStartTime(), result, FieldNames.RACE_LOG_EVENT_START_TIME); + result.put(FieldNames.RACE_LOG_EVENT_NEXT_STATUS.name(), startTimeEvent.getNextStatus().name()); + return result; + } + + private void storeRaceLogEventProperties(RaceLogEvent event, DBObject result) { + // for compatibility reasons we reuse the field name of Timed + storeTimePoint(event.getLogicalTimePoint(), result, FieldNames.TIME_AS_MILLIS); + storeTimePoint(event.getCreatedAt(), result, FieldNames.RACE_LOG_EVENT_CREATED_AT); + result.put(FieldNames.RACE_LOG_EVENT_ID.name(), event.getId()); + result.put(FieldNames.RACE_LOG_EVENT_PASS_ID.name(), event.getPassId()); + result.put(FieldNames.RACE_LOG_EVENT_INVOLVED_BOATS.name(), storeInvolvedBoatsForRaceLogEvent(event.getInvolvedBoats())); + storeRaceLogEventAuthor(result, event.getAuthor()); + } + + + private BasicDBList storeInvolvedBoatsForRaceLogEvent(List competitors) { + BasicDBList dbInvolvedCompetitorIds = new BasicDBList(); + for (Competitor competitor : competitors) { + dbInvolvedCompetitorIds.add(competitor.getId()); + } + return dbInvolvedCompetitorIds; + } + + private DBObject storeRaceLogPassChangeEvent(RaceLogPassChangeEvent passChangeEvent) { + DBObject result = new BasicDBObject(); + storeRaceLogEventProperties(passChangeEvent, result); + result.put(FieldNames.RACE_LOG_EVENT_CLASS.name(), RaceLogPassChangeEvent.class.getSimpleName()); + return result; + } + + private DBObject storeRaceLogDependentStartTimeEvent(RaceLogDependentStartTimeEvent dependentStartTimeEvent) { + DBObject result = new BasicDBObject(); + storeRaceLogEventProperties(dependentStartTimeEvent, result); + result.put(FieldNames.RACE_LOG_EVENT_CLASS.name(), RaceLogDependentStartTimeEvent.class.getSimpleName()); + result.put(FieldNames.RACE_LOG_DEPDENDENT_ON_REGATTALIKE.name(), dependentStartTimeEvent.getDependentOnRaceIdentifier().getRegattaLikeParentName()); + result.put(FieldNames.RACE_LOG_DEPDENDENT_ON_RACECOLUMN.name(), dependentStartTimeEvent.getDependentOnRaceIdentifier().getRaceColumnName()); + result.put(FieldNames.RACE_LOG_DEPDENDENT_ON_FLEET.name(), dependentStartTimeEvent.getDependentOnRaceIdentifier().getFleetName()); + storeDuration(dependentStartTimeEvent.getStartTimeDifference(), result, FieldNames.RACE_LOG_START_TIME_DIFFERENCE_IN_MS); + result.put(FieldNames.RACE_LOG_EVENT_NEXT_STATUS.name(), dependentStartTimeEvent.getNextStatus().name()); + return result; + } + + private void storeDuration(Duration duration, DBObject result, FieldNames fieldName) { + if (duration != null) { + result.put(fieldName.name(), duration.asMillis()); + } + } + + private DBObject storeRaceLogRaceStatusEvent(RaceLogRaceStatusEvent raceStatusEvent) { + DBObject result = new BasicDBObject(); + storeRaceLogEventProperties(raceStatusEvent, result); + result.put(FieldNames.RACE_LOG_EVENT_CLASS.name(), RaceLogRaceStatusEvent.class.getSimpleName()); + result.put(FieldNames.RACE_LOG_EVENT_NEXT_STATUS.name(), raceStatusEvent.getNextStatus().name()); + return result; + } + + private DBObject storeRaceLogCourseAreaChangedEvent(RaceLogCourseAreaChangedEvent courseAreaChangedEvent) { + DBObject result = new BasicDBObject(); + storeRaceLogEventProperties(courseAreaChangedEvent, result); + result.put(FieldNames.RACE_LOG_EVENT_CLASS.name(), RaceLogCourseAreaChangedEvent.class.getSimpleName()); + result.put(FieldNames.COURSE_AREA_ID.name(), courseAreaChangedEvent.getCourseAreaId()); + return result; + } + + private DBObject storeRaceLogCourseDesignChangedEvent(RaceLogCourseDesignChangedEvent courseDesignChangedEvent) { + DBObject result = new BasicDBObject(); + storeRaceLogEventProperties(courseDesignChangedEvent, result); + result.put(FieldNames.RACE_LOG_EVENT_CLASS.name(), RaceLogCourseDesignChangedEvent.class.getSimpleName()); + result.put(FieldNames.RACE_LOG_COURSE_DESIGN_NAME.name(), courseDesignChangedEvent.getCourseDesign().getName()); + result.put(FieldNames.RACE_LOG_COURSE_DESIGN.name(), storeCourseBase(courseDesignChangedEvent.getCourseDesign())); + return result; + } + + private Object storeRaceLogFinishPositioningListChangedEvent(RaceLogFinishPositioningListChangedEvent finishPositioningListChangedEvent) { + DBObject result = new BasicDBObject(); + storeRaceLogEventProperties(finishPositioningListChangedEvent, result); + result.put(FieldNames.RACE_LOG_EVENT_CLASS.name(), RaceLogFinishPositioningListChangedEvent.class.getSimpleName()); + result.put(FieldNames.RACE_LOG_POSITIONED_COMPETITORS.name(), storePositionedCompetitors(finishPositioningListChangedEvent.getPositionedCompetitorsIDsNamesMaxPointsReasons())); + + return result; + } + + private Object storeRaceLogFinishPositioningConfirmedEvent(RaceLogFinishPositioningConfirmedEvent finishPositioningConfirmedEvent) { + DBObject result = new BasicDBObject(); + storeRaceLogEventProperties(finishPositioningConfirmedEvent, result); + result.put(FieldNames.RACE_LOG_EVENT_CLASS.name(), RaceLogFinishPositioningConfirmedEvent.class.getSimpleName()); + result.put(FieldNames.RACE_LOG_POSITIONED_COMPETITORS.name(), storePositionedCompetitors(finishPositioningConfirmedEvent.getPositionedCompetitorsIDsNamesMaxPointsReasons())); + + return result; + } + + private Object storeRaceLogGateLineOpeningTimeEvent(RaceLogGateLineOpeningTimeEvent gateLineOpeningTimeEvent){ + DBObject result = new BasicDBObject(); + storeRaceLogEventProperties(gateLineOpeningTimeEvent, result); + result.put(FieldNames.RACE_LOG_EVENT_CLASS.name(), RaceLogGateLineOpeningTimeEvent.class.getSimpleName()); + result.put(FieldNames.RACE_LOG_GATE_LINE_OPENING_TIME.name(), gateLineOpeningTimeEvent.getGateLineOpeningTimes().getGateLaunchStopTime()); + result.put(FieldNames.RACE_LOG_GOLF_DOWN_TIME.name(), gateLineOpeningTimeEvent.getGateLineOpeningTimes().getGolfDownTime()); + return result; + } + + private BasicDBList storePositionedCompetitors(CompetitorResults positionedCompetitors) { + BasicDBList dbList = new BasicDBList(); + if (positionedCompetitors != null) { + for (CompetitorResult competitorPair : positionedCompetitors) { + dbList.add(storePositionedCompetitor(competitorPair)); + } + } + return dbList; + } + + private DBObject storePositionedCompetitor(CompetitorResult competitorResult) { + DBObject result = new BasicDBObject(); + result.put(FieldNames.COMPETITOR_ID.name(), competitorResult.getCompetitorId()); + result.put(FieldNames.COMPETITOR_DISPLAY_NAME.name(), competitorResult.getCompetitorDisplayName()); + result.put(FieldNames.LEADERBOARD_SCORE_CORRECTION_MAX_POINTS_REASON.name(), competitorResult.getMaxPointsReason() == null ? null : competitorResult.getMaxPointsReason().name()); + result.put(FieldNames.LEADERBOARD_CORRECTED_SCORE.name(), competitorResult.getScore()); + result.put(FieldNames.RACE_LOG_FINISHING_TIME_AS_MILLIS.name(), competitorResult.getFinishingTime() == null ? null : competitorResult.getFinishingTime().asMillis()); + result.put(FieldNames.LEADERBOARD_RANK.name(), competitorResult.getOneBasedRank()); + result.put(FieldNames.LEADERBOARD_SCORE_CORRECTION_COMMENT.name(), competitorResult.getComment()); + return result; + } + + private BasicDBList storeCourseBase(CourseBase courseData) { + BasicDBList dbList = new BasicDBList(); + + for (Waypoint waypoint : courseData.getWaypoints()) { + dbList.add(storeWaypoint(waypoint)); + } + return dbList; + } + + private DBObject storeWaypoint(Waypoint waypoint) { + DBObject result = new BasicDBObject(); + result.put(FieldNames.WAYPOINT_PASSINGINSTRUCTIONS.name(), getPassingInstructions(waypoint.getPassingInstructions())); + result.put(FieldNames.CONTROLPOINT.name(), storeControlPoint(waypoint.getControlPoint())); + return result; + } + + private DBObject storeControlPoint(ControlPoint controlPoint) { + DBObject result = new BasicDBObject(); + if (controlPoint instanceof Mark) { + result.put(FieldNames.CONTROLPOINT_CLASS.name(), Mark.class.getSimpleName()); + result.put(FieldNames.CONTROLPOINT_VALUE.name(), storeMark((Mark) controlPoint)); + } else if (controlPoint instanceof ControlPointWithTwoMarks) { + result.put(FieldNames.CONTROLPOINT_CLASS.name(), ControlPointWithTwoMarks.class.getSimpleName()); + result.put(FieldNames.CONTROLPOINT_VALUE.name(), storeControlPointWithTwoMarks((ControlPointWithTwoMarks) controlPoint)); + } + return result; + } + + private DBObject storeControlPointWithTwoMarks(ControlPointWithTwoMarks cpwtm) { + DBObject result = new BasicDBObject(); + result.put(FieldNames.CONTROLPOINTWITHTWOMARKS_ID.name(), cpwtm.getId()); + result.put(FieldNames.CONTROLPOINTWITHTWOMARKS_NAME.name(), cpwtm.getName()); + result.put(FieldNames.CONTROLPOINTWITHTWOMARKS_LEFT.name(), storeMark(cpwtm.getLeft())); + result.put(FieldNames.CONTROLPOINTWITHTWOMARKS_RIGHT.name(), storeMark(cpwtm.getRight())); + return result; + } + + private DBObject storeMark(Mark mark) { + DBObject result = new BasicDBObject(); + result.put(FieldNames.MARK_ID.name(), mark.getId()); + result.put(FieldNames.MARK_COLOR.name(), mark.getColor()); + result.put(FieldNames.MARK_NAME.name(), mark.getName()); + result.put(FieldNames.MARK_PATTERN.name(), mark.getPattern()); + result.put(FieldNames.MARK_SHAPE.name(), mark.getShape()); + result.put(FieldNames.MARK_TYPE.name(), mark.getType() == null ? null : mark.getType().name()); + return result; + } + + private String getPassingInstructions(PassingInstruction passingInstructions) { + final String passing; + if (passingInstructions != null) { + passing = passingInstructions.name(); + } else { + passing = null; + } + return passing; + } + @Override + public void storeCompetitor(Competitor competitor) { + DBCollection collection = database.getCollection(CollectionNames.COMPETITORS.name()); + JSONObject json = competitorSerializer.serialize(competitor); + DBObject query = (DBObject) JSON.parse(CompetitorJsonSerializer.getCompetitorIdQuery(competitor).toString()); + DBObject entry = (DBObject) JSON.parse(json.toString()); + collection.update(query, entry, /* upsrt */true, /* multi */false, WriteConcern.SAFE); + } + + @Override + public void removeAllCompetitors() { + logger.info("Removing all persistent competitor info"); + DBCollection collection = database.getCollection(CollectionNames.COMPETITORS.name()); + collection.drop(); + } + + @Override + public void removeCompetitor(Competitor competitor) { + logger.info("Removing persistent competitor info for competitor "+competitor.getName()+" with ID "+competitor.getId()); + DBCollection collection = database.getCollection(CollectionNames.COMPETITORS.name()); + DBObject query = (DBObject) JSON.parse(CompetitorJsonSerializer.getCompetitorIdQuery(competitor).toString()); + collection.remove(query, WriteConcern.SAFE); + } + + @Override + public void storeDeviceConfiguration(DeviceConfigurationMatcher matcher, DeviceConfiguration configuration) { + DBCollection configurationsCollections = database.getCollection(CollectionNames.CONFIGURATIONS.name()); + + DBObject query = new BasicDBObject(); + query.put(FieldNames.CONFIGURATION_MATCHER_ID.name(), matcher.getMatcherIdentifier()); + + DBObject entryObject = new BasicDBObject(); + entryObject.put(FieldNames.CONFIGURATION_MATCHER_ID.name(), matcher.getMatcherIdentifier()); + entryObject.put(FieldNames.CONFIGURATION_MATCHER.name(), createDeviceConfigurationMatcherObject(matcher)); + entryObject.put(FieldNames.CONFIGURATION_CONFIG.name(), createDeviceConfigurationObject(configuration)); + + configurationsCollections.update(query, entryObject, /* upsrt */ true, /* multi */ false, WriteConcern.SAFE); + } + + private DBObject createDeviceConfigurationMatcherObject(DeviceConfigurationMatcher matcher) { + DBObject matcherObject = new BasicDBObject(); + matcherObject.put(FieldNames.CONFIGURATION_MATCHER_TYPE.name(), matcher.getMatcherType().name()); + if (matcher instanceof DeviceConfigurationMatcherSingle) { + BasicDBList client = new BasicDBList(); + client.add(((DeviceConfigurationMatcherSingle)matcher).getClientIdentifier()); + matcherObject.put(FieldNames.CONFIGURATION_MATCHER_CLIENTS.name(), client); + } else if (matcher instanceof DeviceConfigurationMatcherMulti) { + BasicDBList clients = new BasicDBList(); + Util.addAll(((DeviceConfigurationMatcherMulti)matcher).getClientIdentifiers(), clients); + matcherObject.put(FieldNames.CONFIGURATION_MATCHER_CLIENTS.name(), clients); + } + return matcherObject; + } + + private DBObject createDeviceConfigurationObject(DeviceConfiguration configuration) { + JsonSerializer serializer = DeviceConfigurationJsonSerializer.create(); + JSONObject json = serializer.serialize(configuration); + DBObject entry = (DBObject) JSON.parse(json.toString()); + return entry; + } + + @Override + public void removeDeviceConfiguration(DeviceConfigurationMatcher matcher) { + DBCollection configurationsCollections = database.getCollection(CollectionNames.CONFIGURATIONS.name()); + DBObject query = new BasicDBObject(); + query.put(FieldNames.CONFIGURATION_MATCHER_ID.name(), matcher.getMatcherIdentifier()); + configurationsCollections.remove(query); + } + + public static DBObject storeDeviceId( + TypeBasedServiceFinder deviceIdentifierServiceFinder, DeviceIdentifier device) + throws TransformationException, NoCorrespondingServiceRegisteredException { + String type = device.getIdentifierType(); + DeviceIdentifierMongoHandler handler = deviceIdentifierServiceFinder.findService(type); + com.sap.sse.common.Util.Pair pair = handler.serialize(device); + type = pair.getA(); + Object deviceTypeSpecificId = pair.getB(); + return new BasicDBObjectBuilder() + .add(FieldNames.DEVICE_TYPE.name(), type) + .add(FieldNames.DEVICE_TYPE_SPECIFIC_ID.name(), deviceTypeSpecificId) + .add(FieldNames.DEVICE_STRING_REPRESENTATION.name(), device.getStringRepresentation()).get(); + } + + void storeRaceLogEventEvent(DBObject eventEntry) { + getRaceLogCollection().insert(eventEntry); + } + + @Override + public void removeRaceLog(RaceLogIdentifier identifier) { + DBObject query = new BasicDBObject(); + storeRaceLogIdentifier(identifier, query); + getRaceLogCollection().remove(query); + } + + @Override + public void removeRegattaLog(RegattaLikeIdentifier identifier) { + DBObject query = new BasicDBObject(); + addRegattaLikeIdentifier(identifier, query); + getRegattaLogCollection().remove(query); + } + + @Override + public void storeResultUrl(String resultProviderName, URL url) { + DBCollection resultUrlsCollection = database.getCollection(CollectionNames.RESULT_URLS.name()); + DBObject query = new BasicDBObject(FieldNames.RESULT_PROVIDERNAME.name(), resultProviderName); + DBObject entry = new BasicDBObject(FieldNames.RESULT_PROVIDERNAME.name(), resultProviderName); + entry.put(FieldNames.RESULT_URL.name(), url.toString()); + resultUrlsCollection.update(query, entry, /* upsrt */true, /* multi */false, WriteConcern.SAFE); + } + + @Override + public void removeResultUrl(String resultProviderName, URL url) { + DBCollection resultUrlsCollection = database.getCollection(CollectionNames.RESULT_URLS.name()); + DBObject query = new BasicDBObjectBuilder().add(FieldNames.RESULT_PROVIDERNAME.name(), resultProviderName) + .add(FieldNames.RESULT_URL.name(), url.toString()).get(); + resultUrlsCollection.remove(query); + } + + public DBCollection getRegattaLogCollection() { + DBCollection result = database.getCollection(CollectionNames.REGATTA_LOGS.name()); + DBObject index = new BasicDBObject(FieldNames.REGATTA_LOG_IDENTIFIER_TYPE.name(), null); + index.put(FieldNames.REGATTA_LOG_IDENTIFIER_NAME.name(), null); + result.createIndex(index); + return result; + } + + private DBObject createBasicRegattaLogEventDBObject(RegattaLogEvent event) { + DBObject result = new BasicDBObject(); + storeTimed(event, result); + storeTimePoint(event.getCreatedAt(), result, FieldNames.REGATTA_LOG_EVENT_CREATED_AT); + result.put(FieldNames.REGATTA_LOG_EVENT_ID.name(), event.getId()); + result.put(FieldNames.REGATTA_LOG_EVENT_AUTHOR_NAME.name(), event.getAuthor().getName()); + result.put(FieldNames.REGATTA_LOG_EVENT_AUTHOR_PRIORITY.name(), event.getAuthor().getPriority()); + return result; + } + + private void addRegattaLikeIdentifier(RegattaLikeIdentifier regattaLikeId, DBObject toObject) { + toObject.put(FieldNames.REGATTA_LOG_IDENTIFIER_TYPE.name(), regattaLikeId.getIdentifierType()); + toObject.put(FieldNames.REGATTA_LOG_IDENTIFIER_NAME.name(), regattaLikeId.getName()); + } + + private void storeRegattaLogEvent(RegattaLikeIdentifier regattaLikeId, DBObject innerObject) { + DBObject result = new BasicDBObject(FieldNames.REGATTA_LOG_EVENT.name(), innerObject); + addRegattaLikeIdentifier(regattaLikeId, result); + getRegattaLogCollection().insert(result); + } + + public void storeRegattaLogEvent(RegattaLikeIdentifier regattaLikeId, RegattaLogDeviceCompetitorMappingEvent event) { + DBObject result = createBasicRegattaLogEventDBObject(event); + result.put(FieldNames.REGATTA_LOG_EVENT_CLASS.name(), RegattaLogDeviceCompetitorMappingEvent.class.getSimpleName()); + storeDeviceMappingEvent(event, result, FieldNames.REGATTA_LOG_FROM, FieldNames.REGATTA_LOG_TO); + result.put(FieldNames.COMPETITOR_ID.name(), event.getMappedTo().getId()); + storeRegattaLogEvent(regattaLikeId, result); + } + + public void storeRegattaLogEvent(RegattaLikeIdentifier regattaLikeId, RegattaLogDeviceMarkMappingEvent event) { + DBObject result = createBasicRegattaLogEventDBObject(event); + result.put(FieldNames.REGATTA_LOG_EVENT_CLASS.name(), RegattaLogDeviceMarkMappingEvent.class.getSimpleName()); + storeDeviceMappingEvent(event, result, FieldNames.REGATTA_LOG_FROM, FieldNames.REGATTA_LOG_TO); + result.put(FieldNames.MARK.name(), storeMark(event.getMappedTo())); + storeRegattaLogEvent(regattaLikeId, result); + } + + public void storeRegattaLogEvent(RegattaLikeIdentifier regattaLikeId, RegattaLogRevokeEvent event) { + DBObject result = createBasicRegattaLogEventDBObject(event); + result.put(FieldNames.REGATTA_LOG_EVENT_CLASS.name(), RegattaLogRevokeEvent.class.getSimpleName()); + result.put(FieldNames.REGATTA_LOG_REVOKED_EVENT_ID.name(), event.getRevokedEventId()); + result.put(FieldNames.REGATTA_LOG_REVOKED_EVENT_TYPE.name(), event.getRevokedEventType()); + result.put(FieldNames.REGATTA_LOG_REVOKED_EVENT_SHORT_INFO.name(), event.getRevokedEventShortInfo()); + result.put(FieldNames.REGATTA_LOG_REVOKED_REASON.name(), event.getReason()); + storeRegattaLogEvent(regattaLikeId, result); + } + + public void storeRegattaLogEvent(RegattaLikeIdentifier regattaLikeId, RegattaLogRegisterCompetitorEvent event) { + DBObject result = createBasicRegattaLogEventDBObject(event); + result.put(FieldNames.REGATTA_LOG_EVENT_CLASS.name(), RegattaLogRegisterCompetitorEvent.class.getSimpleName()); + result.put(FieldNames.REGATTA_LOG_COMPETITOR_ID.name(), event.getCompetitor().getId()); + storeRegattaLogEvent(regattaLikeId, result); + } + + public void storeRegattaLogEvent(RegattaLikeIdentifier regattaLikeId, RegattaLogCloseOpenEndedDeviceMappingEvent event) { + DBObject result = createBasicRegattaLogEventDBObject(event); + result.put(FieldNames.REGATTA_LOG_EVENT_CLASS.name(), RegattaLogCloseOpenEndedDeviceMappingEvent.class.getSimpleName()); + result.put(FieldNames.REGATTA_LOG_DEVICE_MAPPING_EVENT_ID.name(), event.getDeviceMappingEventId()); + storeTimePoint(event.getClosingTimePoint(), result, FieldNames.REGATTA_LOG_CLOSING_TIMEPOINT); + storeRegattaLogEvent(regattaLikeId, result); + } + + public void storeRegattaLogEvent(RegattaLikeIdentifier regattaLikeId, RegattaLogSetCompetitorTimeOnTimeFactorEvent event) { + DBObject result = createBasicRegattaLogEventDBObject(event); + result.put(FieldNames.REGATTA_LOG_EVENT_CLASS.name(), RegattaLogCloseOpenEndedDeviceMappingEvent.class.getSimpleName()); + result.put(FieldNames.REGATTA_LOG_COMPETITOR_ID.name(), event.getCompetitor().getId()); + result.put(FieldNames.REGATTA_LOG_TIME_ON_TIME_FACTOR.name(), event.getTimeOnTimeFactor()); + } + + public DBObject storeRaceLogEntry(RaceLogIdentifier raceLogIdentifier, RaceLogDependentStartTimeEvent event) { + BasicDBObject result = new BasicDBObject(); + storeRaceLogIdentifier(raceLogIdentifier, result); + result.put(FieldNames.RACE_LOG_EVENT.name(), storeRaceLogDependentStartTimeEvent(event)); + return result; + } + + public void storeRegattaLogEvent(RegattaLikeIdentifier regattaLikeId, RegattaLogSetCompetitorTimeOnDistanceAllowancePerNauticalMileEvent event) { + DBObject result = createBasicRegattaLogEventDBObject(event); + result.put(FieldNames.REGATTA_LOG_EVENT_CLASS.name(), RegattaLogCloseOpenEndedDeviceMappingEvent.class.getSimpleName()); + result.put(FieldNames.REGATTA_LOG_COMPETITOR_ID.name(), event.getCompetitor().getId()); + result.put(FieldNames.REGATTA_LOG_TIME_ON_DISTANCE_SECONDS_ALLOWANCE_PER_NAUTICAL_MILE.name(), event.getTimeOnDistanceAllowancePerNauticalMile().asSeconds()); + storeRegattaLogEvent(regattaLikeId, result); + } + + public void storeRegattaLogEvent(RegattaLikeIdentifier regattaLikeIdentifier, RegattaLogDefineMarkEvent event) { + DBObject result = createBasicRegattaLogEventDBObject(event); + result.put(FieldNames.REGATTA_LOG_EVENT_CLASS.name(), RegattaLogDefineMarkEvent.class.getSimpleName()); + result.put(FieldNames.REGATTA_LOG_MARK.name(), storeMark(event.getMark())); + storeRegattaLogEvent(regattaLikeIdentifier, result); + } + + private DBObject createImageObject(ImageDescriptor image) { + DBObject result = new BasicDBObject(); + result.put(FieldNames.IMAGE_URL.name(), image.getURL().toString()); + result.put(FieldNames.IMAGE_LOCALE.name(), image.getLocale() != null ? image.getLocale().toLanguageTag() : null); + result.put(FieldNames.IMAGE_TITLE.name(), image.getTitle()); + result.put(FieldNames.IMAGE_SUBTITLE.name(), image.getSubtitle()); + result.put(FieldNames.IMAGE_COPYRIGHT.name(), image.getCopyright()); + result.put(FieldNames.IMAGE_WIDTH_IN_PX.name(), image.getWidthInPx()); + result.put(FieldNames.IMAGE_HEIGHT_IN_PX.name(), image.getHeightInPx()); + storeTimePoint(image.getCreatedAtDate(), result, FieldNames.IMAGE_CREATEDATDATE); + BasicDBList tags = new BasicDBList(); + for (String tag : image.getTags()) { + tags.add(tag); + } + result.put(FieldNames.IMAGE_TAGS.name(), tags); + return result; + } + + private DBObject createVideoObject(VideoDescriptor video) { + DBObject result = new BasicDBObject(); + result.put(FieldNames.VIDEO_URL.name(), video.getURL().toString()); + result.put(FieldNames.VIDEO_LOCALE.name(), video.getLocale() != null ? video.getLocale().toLanguageTag() : null); + result.put(FieldNames.VIDEO_THUMBNAIL_URL.name(), video.getThumbnailURL() != null ? video.getThumbnailURL().toString() : null); + result.put(FieldNames.VIDEO_TITLE.name(), video.getTitle()); + result.put(FieldNames.VIDEO_SUBTITLE.name(), video.getSubtitle()); + result.put(FieldNames.VIDEO_MIMETYPE.name(), video.getMimeType() != null ? video.getMimeType().name() : null); + result.put(FieldNames.VIDEO_COPYRIGHT.name(), video.getCopyright()); + result.put(FieldNames.VIDEO_LENGTH_IN_SECONDS.name(), video.getLengthInSeconds()); + storeTimePoint(video.getCreatedAtDate(), result, FieldNames.VIDEO_CREATEDATDATE); + BasicDBList tags = new BasicDBList(); + for (String tag : video.getTags()) { + tags.add(tag); + } + result.put(FieldNames.VIDEO_TAGS.name(), tags); + return result; + } +} \ No newline at end of file diff --git a/java/com.sap.sailing.domain.persistence/src/com/sap/sailing/domain/persistence/impl/MongoRaceLogStoreVisitor.java b/java/com.sap.sailing.domain.persistence/src/com/sap/sailing/domain/persistence/impl/MongoRaceLogStoreVisitor.java index 4dff4932552..a65b20e14ad 100644 --- a/java/com.sap.sailing.domain.persistence/src/com/sap/sailing/domain/persistence/impl/MongoRaceLogStoreVisitor.java +++ b/java/com.sap.sailing.domain.persistence/src/com/sap/sailing/domain/persistence/impl/MongoRaceLogStoreVisitor.java @@ -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); + } } diff --git a/java/com.sap.sailing.domain.persistence/src/com/sap/sailing/domain/persistence/impl/MongoRegattaLogStoreVisitor.java b/java/com.sap.sailing.domain.persistence/src/com/sap/sailing/domain/persistence/impl/MongoRegattaLogStoreVisitor.java index c0c1143c042..c3c796c59a6 100644 --- a/java/com.sap.sailing.domain.persistence/src/com/sap/sailing/domain/persistence/impl/MongoRegattaLogStoreVisitor.java +++ b/java/com.sap.sailing.domain.persistence/src/com/sap/sailing/domain/persistence/impl/MongoRegattaLogStoreVisitor.java @@ -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); + } } diff --git a/java/com.sap.sailing.domain.persistence/src/com/sap/sailing/domain/persistence/racelog/tracking/impl/MongoGPSFixStoreImpl.java b/java/com.sap.sailing.domain.persistence/src/com/sap/sailing/domain/persistence/racelog/tracking/impl/MongoGPSFixStoreImpl.java index 9fe5ba23215..bee06e81e00 100755 --- a/java/com.sap.sailing.domain.persistence/src/com/sap/sailing/domain/persistence/racelog/tracking/impl/MongoGPSFixStoreImpl.java +++ b/java/com.sap.sailing.domain.persistence/src/com/sap/sailing/domain/persistence/racelog/tracking/impl/MongoGPSFixStoreImpl.java @@ -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 track, AbstractLog log, Competitor competitor) + public void loadCompetitorTrack(DynamicGPSFixTrack track, RegattaLog log, Competitor competitor) throws NoCorrespondingServiceRegisteredException, TransformationException{ - List> mappings = new DeviceCompetitorMappingFinder<>(log).analyze().get(competitor); + List> mappings = new RegattaLogDeviceCompetitorMappingFinder(log).analyze().get(competitor); if (mappings != null) { for (DeviceMapping 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 track, AbstractLog log, Mark mark) + public void loadMarkTrack(DynamicGPSFixTrack track, RegattaLog log, Mark mark) throws NoCorrespondingServiceRegisteredException, TransformationException{ - List> mappings = new DeviceMarkMappingFinder<>(log).analyze().get(mark); + List> mappings = new RegattaLogDeviceMarkMappingFinder(log).analyze().get(mark); if (mappings != null) { for (DeviceMapping 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 track, AbstractLog log, + public void loadCompetitorTrack(DynamicGPSFixTrack track, RegattaLog log, Competitor competitor, TimePoint start, TimePoint end) throws TransformationException { - List> mappings = new DeviceCompetitorMappingFinder<>(log).analyze().get(competitor); + List> mappings = new RegattaLogDeviceCompetitorMappingFinder(log).analyze().get(competitor); if (mappings != null) { for (DeviceMapping 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 track, AbstractLog log, Mark mark, + public void loadMarkTrack(DynamicGPSFixTrack track, RegattaLog log, Mark mark, TimePoint start, TimePoint end) throws TransformationException, NoCorrespondingServiceRegisteredException { - List> mappings = new DeviceMarkMappingFinder<>(log).analyze().get(mark); + List> mappings = new RegattaLogDeviceMarkMappingFinder(log).analyze().get(mark); if (mappings != null) { for (DeviceMapping 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(); } - } diff --git a/java/com.sap.sailing.domain.racelogtrackingadapter.test/src/com/sap/sailing/domain/racelogtracking/test/AbstractGPSFixStoreTest.java b/java/com.sap.sailing.domain.racelogtrackingadapter.test/src/com/sap/sailing/domain/racelogtracking/test/AbstractGPSFixStoreTest.java index f48a27959ec..bc7380eb902 100644 --- a/java/com.sap.sailing.domain.racelogtrackingadapter.test/src/com/sap/sailing/domain/racelogtracking/test/AbstractGPSFixStoreTest.java +++ b/java/com.sap.sailing.domain.racelogtrackingadapter.test/src/com/sap/sailing/domain/racelogtracking/test/AbstractGPSFixStoreTest.java @@ -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))); } diff --git a/java/com.sap.sailing.domain.racelogtrackingadapter.test/src/com/sap/sailing/domain/racelogtracking/test/impl/CreateAndTrackWithRaceLogTest.java b/java/com.sap.sailing.domain.racelogtrackingadapter.test/src/com/sap/sailing/domain/racelogtracking/test/impl/CreateAndTrackWithRaceLogTest.java index 17302ae2345..7525270de13 100644 --- a/java/com.sap.sailing.domain.racelogtrackingadapter.test/src/com/sap/sailing/domain/racelogtracking/test/impl/CreateAndTrackWithRaceLogTest.java +++ b/java/com.sap.sailing.domain.racelogtrackingadapter.test/src/com/sap/sailing/domain/racelogtracking/test/impl/CreateAndTrackWithRaceLogTest.java @@ -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); diff --git a/java/com.sap.sailing.domain.racelogtrackingadapter.test/src/com/sap/sailing/domain/racelogtracking/test/impl/TrackedRaceLoadsFixesTest.java b/java/com.sap.sailing.domain.racelogtrackingadapter.test/src/com/sap/sailing/domain/racelogtracking/test/impl/TrackedRaceLoadsFixesTest.java index 501f9f43025..1cd8a239441 100644 --- a/java/com.sap.sailing.domain.racelogtrackingadapter.test/src/com/sap/sailing/domain/racelogtracking/test/impl/TrackedRaceLoadsFixesTest.java +++ b/java/com.sap.sailing.domain.racelogtrackingadapter.test/src/com/sap/sailing/domain/racelogtracking/test/impl/TrackedRaceLoadsFixesTest.java @@ -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. 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. 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. 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)); - } } diff --git a/java/com.sap.sailing.domain.racelogtrackingadapter/src/com/sap/sailing/domain/racelogtracking/RaceLogTrackingAdapter.java b/java/com.sap.sailing.domain.racelogtrackingadapter/src/com/sap/sailing/domain/racelogtracking/RaceLogTrackingAdapter.java index 6204f5fd191..525379b7b7d 100755 --- a/java/com.sap.sailing.domain.racelogtrackingadapter/src/com/sap/sailing/domain/racelogtracking/RaceLogTrackingAdapter.java +++ b/java/com.sap.sailing.domain.racelogtrackingadapter/src/com/sap/sailing/domain/racelogtracking/RaceLogTrackingAdapter.java @@ -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 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 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 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 to, - RacingEventService service); + void copyCompetitors(RaceColumn fromRaceColumn, Fleet fromFleet, Iterable> toRaces); } diff --git a/java/com.sap.sailing.domain.racelogtrackingadapter/src/com/sap/sailing/domain/racelogtracking/impl/RaceLogConnectivityParams.java b/java/com.sap.sailing.domain.racelogtrackingadapter/src/com/sap/sailing/domain/racelogtracking/impl/RaceLogConnectivityParams.java index 1c5c8928bab..acb440a692a 100644 --- a/java/com.sap.sailing.domain.racelogtrackingadapter/src/com/sap/sailing/domain/racelogtracking/impl/RaceLogConnectivityParams.java +++ b/java/com.sap.sailing.domain.racelogtrackingadapter/src/com/sap/sailing/domain/racelogtracking/impl/RaceLogConnectivityParams.java @@ -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; diff --git a/java/com.sap.sailing.domain.racelogtrackingadapter/src/com/sap/sailing/domain/racelogtracking/impl/RaceLogRaceTracker.java b/java/com.sap.sailing.domain.racelogtrackingadapter/src/com/sap/sailing/domain/racelogtracking/impl/RaceLogRaceTracker.java index 747f938f666..ef560d210fc 100755 --- a/java/com.sap.sailing.domain.racelogtrackingadapter/src/com/sap/sailing/domain/racelogtracking/impl/RaceLogRaceTracker.java +++ b/java/com.sap.sailing.domain.racelogtrackingadapter/src/com/sap/sailing/domain/racelogtracking/impl/RaceLogRaceTracker.java @@ -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>> getNewCompetitorMappings() { - return new MultiLogAnalyzer<>(new DeviceCompetitorMappingFinder.Factory(), - new MapWithValueCollectionReducer<>(), params.getLogHierarchy()).analyze(); + private Map>> getNewCompetitorMappings() throws DoesNotHaveRegattaLogException { + return new RegattaLogDeviceCompetitorMappingFinder(params.getRegattaLog()).analyze(); } - private Map>> getNewMarkMappings() { - return new MultiLogAnalyzer<>(new DeviceMarkMappingFinder.Factory(), new MapWithValueCollectionReducer<>(), - params.getLogHierarchy()).analyze(); + private Map>> 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> 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> 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 boolean hasMappingAlreadyBeenLoaded( DeviceMapping newMapping, List> 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 true, 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 true, 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 competitors = new MultiLogAnalyzer<>(RegisteredCompetitorsAnalyzer.Factory.INSTANCE, - new SetReducer(), params.getLogHierarchy()).analyze(); + Iterable competitors = raceColumn.getAllCompetitors(params.getFleet()); Serializable raceId = denoteEvent.getRaceId(); final RaceDefinition raceDef = new RaceDefinitionImpl(raceName, course, boatClass, competitors, raceId); Iterable sidelines = Collections. 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); diff --git a/java/com.sap.sailing.domain.racelogtrackingadapter/src/com/sap/sailing/domain/racelogtracking/impl/RaceLogTrackingAdapterImpl.java b/java/com.sap.sailing.domain.racelogtrackingadapter/src/com/sap/sailing/domain/racelogtracking/impl/RaceLogTrackingAdapterImpl.java index ac2b5d80332..af340dd6ed1 100755 --- a/java/com.sap.sailing.domain.racelogtrackingadapter/src/com/sap/sailing/domain/racelogtracking/impl/RaceLogTrackingAdapterImpl.java +++ b/java/com.sap.sailing.domain.racelogtrackingadapter/src/com/sap/sailing/domain/racelogtracking/impl/RaceLogTrackingAdapterImpl.java @@ -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 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 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 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 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 toRaceLogs, RacingEventService service) { - final Set competitors = new RegisteredCompetitorsAnalyzer<>(fromRaceLog).analyze(); - for (RaceLog toRaceLog : toRaceLogs) { - registerCompetitors(service, toRaceLog, competitors); + public void copyCompetitors(final RaceColumn fromRaceColumn, final Fleet fromFleet, final Iterable> toRaces) { + Iterable competitorsToCopy = fromRaceColumn.getAllCompetitors(fromFleet); + for (Pair 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> { - EventT createDeviceMarkMapping(DeviceIdentifier device, TimePoint timePoint); - } - - private , LogT extends AbstractLog> void pingMark( - LogT log, Mark mark, GPSFix gpsFix, RacingEventService service, - DeviceMarkMappingEventFactory 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 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 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 , EventT extends AbstractLogEvent, VisitorT> void registerCompetitors( - AbstractLogEventAuthor author, LogT log, Set competitors, - Function registerEventFactory) { - Set alreadyRegistered = new HashSet(new RegisteredCompetitorsAnalyzer<>(log).analyze()); - Set toBeRegistered = new HashSet(); - - for (Competitor c : competitors) { - toBeRegistered.add(c); - } - - Set toBeRemoved = new HashSet(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 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 competitors) { - registerCompetitors(service.getServerAuthor(), regattaLog, competitors, - c -> new RegattaLogRegisterCompetitorEventImpl(MillisecondsTimePoint.now(), - MillisecondsTimePoint.now(), service.getServerAuthor(), UUID.randomUUID(), c)); - } - private MailService getMailService() { ServiceReference ref = Activator.getContext().getServiceReference(MailService.class); if (ref == null) { diff --git a/java/com.sap.sailing.domain.shared.android.test/src/com/sap/sailing/domain/racelog/analyzing/test/MultiLogAnalyzerTest.java b/java/com.sap.sailing.domain.shared.android.test/src/com/sap/sailing/domain/racelog/analyzing/test/MultiLogAnalyzerTest.java deleted file mode 100644 index d7734f9bd2a..00000000000 --- a/java/com.sap.sailing.domain.shared.android.test/src/com/sap/sailing/domain/racelog/analyzing/test/MultiLogAnalyzerTest.java +++ /dev/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 result = new MultiLogAnalyzer<>( - RegisteredCompetitorsAnalyzer.Factory.INSTANCE, new MultiLogAnalyzer.SetReducer(), 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>> 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)); - } -} diff --git a/java/com.sap.sailing.domain.shared.android.test/src/com/sap/sailing/domain/racelog/test/SerializeRaceLogEventsTest.java b/java/com.sap.sailing.domain.shared.android.test/src/com/sap/sailing/domain/racelog/test/SerializeRaceLogEventsTest.java index b2bc042d036..11c5f87fe94 100755 --- a/java/com.sap.sailing.domain.shared.android.test/src/com/sap/sailing/domain/racelog/test/SerializeRaceLogEventsTest.java +++ b/java/com.sap.sailing.domain.shared.android.test/src/com/sap/sailing/domain/racelog/test/SerializeRaceLogEventsTest.java @@ -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())); } diff --git a/java/com.sap.sailing.domain.shared.android.test/src/com/sap/sailing/domain/racelog/tracking/analyzing/test/RevokeEventTest.java b/java/com.sap.sailing.domain.shared.android.test/src/com/sap/sailing/domain/racelog/tracking/analyzing/test/RevokeEventTest.java deleted file mode 100644 index c3d00398143..00000000000 --- a/java/com.sap.sailing.domain.shared.android.test/src/com/sap/sailing/domain/racelog/tracking/analyzing/test/RevokeEventTest.java +++ /dev/null @@ -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(); - } -} diff --git a/java/com.sap.sailing.domain.shared.android.test/src/com/sap/sailing/domain/regattalog/tracking/analyzing/test/AbstractRegattaLogTrackingTest.java b/java/com.sap.sailing.domain.shared.android.test/src/com/sap/sailing/domain/regattalog/tracking/analyzing/test/AbstractRegattaLogTrackingTest.java new file mode 100644 index 00000000000..cff23604d76 --- /dev/null +++ b/java/com.sap.sailing.domain.shared.android.test/src/com/sap/sailing/domain/regattalog/tracking/analyzing/test/AbstractRegattaLogTrackingTest.java @@ -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"); + } + +} \ No newline at end of file diff --git a/java/com.sap.sailing.domain.shared.android.test/src/com/sap/sailing/domain/racelog/tracking/analyzing/test/DeviceMappingFinderTest.java b/java/com.sap.sailing.domain.shared.android.test/src/com/sap/sailing/domain/regattalog/tracking/analyzing/test/DeviceMappingFinderTest.java similarity index 78% rename from java/com.sap.sailing.domain.shared.android.test/src/com/sap/sailing/domain/racelog/tracking/analyzing/test/DeviceMappingFinderTest.java rename to java/com.sap.sailing.domain.shared.android.test/src/com/sap/sailing/domain/regattalog/tracking/analyzing/test/DeviceMappingFinderTest.java index 212503f37c7..39b26f4124f 100644 --- a/java/com.sap.sailing.domain.shared.android.test/src/com/sap/sailing/domain/racelog/tracking/analyzing/test/DeviceMappingFinderTest.java +++ b/java/com.sap.sailing.domain.shared.android.test/src/com/sap/sailing/domain/regattalog/tracking/analyzing/test/DeviceMappingFinderTest.java @@ -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> 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); } diff --git a/java/com.sap.sailing.domain.shared.android.test/src/com/sap/sailing/domain/regattalog/tracking/analyzing/test/RevokeEventTest.java b/java/com.sap.sailing.domain.shared.android.test/src/com/sap/sailing/domain/regattalog/tracking/analyzing/test/RevokeEventTest.java new file mode 100644 index 00000000000..bdd39dec5b3 --- /dev/null +++ b/java/com.sap.sailing.domain.shared.android.test/src/com/sap/sailing/domain/regattalog/tracking/analyzing/test/RevokeEventTest.java @@ -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(); + } +} diff --git a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/impl/AllEventsOfTypeFinder.java b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/impl/AllEventsOfTypeFinder.java index 02f11683e67..0608dbba198 100644 --- a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/impl/AllEventsOfTypeFinder.java +++ b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/impl/AllEventsOfTypeFinder.java @@ -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, EventT extends AbstractLogEvent, VisitorT> extends BaseLogAnalyzer> { diff --git a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/race/CompetitorResult.java b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/race/CompetitorResult.java new file mode 100644 index 00000000000..50c07b9a824 --- /dev/null +++ b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/race/CompetitorResult.java @@ -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(); +} diff --git a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/race/CompetitorResults.java b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/race/CompetitorResults.java index 0cd9baf9035..9abbcae0b33 100644 --- a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/race/CompetitorResults.java +++ b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/race/CompetitorResults.java @@ -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> { - +public interface CompetitorResults extends Iterable { + boolean add(CompetitorResult result); } diff --git a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/race/RaceLogEventVisitor.java b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/race/RaceLogEventVisitor.java index 77174f3ac21..fb4f8d3d823 100644 --- a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/race/RaceLogEventVisitor.java +++ b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/race/RaceLogEventVisitor.java @@ -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); } diff --git a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/race/RaceLogFinishPositioningConfirmedEvent.java b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/race/RaceLogFinishPositioningConfirmedEvent.java index 801779a9631..7f04d90f9f8 100644 --- a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/race/RaceLogFinishPositioningConfirmedEvent.java +++ b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/race/RaceLogFinishPositioningConfirmedEvent.java @@ -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 { diff --git a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/race/RaceLogFinishPositioningListChangedEvent.java b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/race/RaceLogFinishPositioningListChangedEvent.java index 9fac2be5e73..072864893da 100644 --- a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/race/RaceLogFinishPositioningListChangedEvent.java +++ b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/race/RaceLogFinishPositioningListChangedEvent.java @@ -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 { } \ No newline at end of file diff --git a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/race/analyzing/impl/ConfirmedFinishPositioningListFinder.java b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/race/analyzing/impl/ConfirmedFinishPositioningListFinder.java index e1ce52945f6..381df5b1c36 100644 --- a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/race/analyzing/impl/ConfirmedFinishPositioningListFinder.java +++ b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/race/analyzing/impl/ConfirmedFinishPositioningListFinder.java @@ -19,7 +19,6 @@ public class ConfirmedFinishPositioningListFinder extends RaceLogAnalyzer return courseDesignEvent.getCourseDesign(); } } - return null; } - } diff --git a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/race/analyzing/impl/RaceLogRegisteredCompetitorsAnalyzer.java b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/race/analyzing/impl/RaceLogRegisteredCompetitorsAnalyzer.java new file mode 100644 index 00000000000..73420f406c4 --- /dev/null +++ b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/race/analyzing/impl/RaceLogRegisteredCompetitorsAnalyzer.java @@ -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> { + + public RaceLogRegisteredCompetitorsAnalyzer(RaceLog raceLog) { + super(raceLog); + } + + @Override + protected Set performAnalysis() { + final Set 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; + } +} diff --git a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/race/impl/AbstractRaceLogChangedVisitor.java b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/race/impl/AbstractRaceLogChangedVisitor.java index d042544fb76..8407d6f2d86 100755 --- a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/race/impl/AbstractRaceLogChangedVisitor.java +++ b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/race/impl/AbstractRaceLogChangedVisitor.java @@ -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); + } } diff --git a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/race/impl/BaseRaceLogEventVisitor.java b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/race/impl/BaseRaceLogEventVisitor.java index 1c9038da9a5..bff059adf00 100644 --- a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/race/impl/BaseRaceLogEventVisitor.java +++ b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/race/impl/BaseRaceLogEventVisitor.java @@ -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) { + + } } diff --git a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/race/impl/CompetitorResultImpl.java b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/race/impl/CompetitorResultImpl.java new file mode 100644 index 00000000000..da8728f267b --- /dev/null +++ b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/race/impl/CompetitorResultImpl.java @@ -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 + "]"; + } + +} diff --git a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/race/impl/CompetitorResultsImpl.java b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/race/impl/CompetitorResultsImpl.java index 576fa702a42..67b4e6cd896 100644 --- a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/race/impl/CompetitorResultsImpl.java +++ b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/race/impl/CompetitorResultsImpl.java @@ -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> implements CompetitorResults { +public class CompetitorResultsImpl extends ArrayList implements CompetitorResults { private static final long serialVersionUID = 4928351242700897387L; - } diff --git a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/race/tracking/RaceLogCloseOpenEndedDeviceMappingEvent.java b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/race/tracking/RaceLogCloseOpenEndedDeviceMappingEvent.java deleted file mode 100644 index 25becd6a796..00000000000 --- a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/race/tracking/RaceLogCloseOpenEndedDeviceMappingEvent.java +++ /dev/null @@ -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 { - -} diff --git a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/race/tracking/RaceLogDefineMarkEvent.java b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/race/tracking/RaceLogDefineMarkEvent.java deleted file mode 100644 index db38a837a84..00000000000 --- a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/race/tracking/RaceLogDefineMarkEvent.java +++ /dev/null @@ -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(); -} diff --git a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/race/tracking/RaceLogDenoteForTrackingEvent.java b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/race/tracking/RaceLogDenoteForTrackingEvent.java index 9035e3b53a6..2115177e8f5 100644 --- a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/race/tracking/RaceLogDenoteForTrackingEvent.java +++ b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/race/tracking/RaceLogDenoteForTrackingEvent.java @@ -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 * */ diff --git a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/race/tracking/RaceLogDeviceCompetitorMappingEvent.java b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/race/tracking/RaceLogDeviceCompetitorMappingEvent.java deleted file mode 100644 index dbaee1c7e75..00000000000 --- a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/race/tracking/RaceLogDeviceCompetitorMappingEvent.java +++ /dev/null @@ -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 { - -} diff --git a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/race/tracking/RaceLogDeviceMarkMappingEvent.java b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/race/tracking/RaceLogDeviceMarkMappingEvent.java deleted file mode 100644 index 73af94d801e..00000000000 --- a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/race/tracking/RaceLogDeviceMarkMappingEvent.java +++ /dev/null @@ -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 { - -} diff --git a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/race/tracking/RaceLogStartTrackingEvent.java b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/race/tracking/RaceLogStartTrackingEvent.java index cb162dcb430..efc256e5796 100644 --- a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/race/tracking/RaceLogStartTrackingEvent.java +++ b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/race/tracking/RaceLogStartTrackingEvent.java @@ -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 diff --git a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/race/tracking/RaceLogUseCompetitorsFromRaceLogEvent.java b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/race/tracking/RaceLogUseCompetitorsFromRaceLogEvent.java new file mode 100644 index 00000000000..fa91d9bf970 --- /dev/null +++ b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/race/tracking/RaceLogUseCompetitorsFromRaceLogEvent.java @@ -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 { +} diff --git a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/race/tracking/analyzing/impl/RaceLogDefinedMarkFinder.java b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/race/tracking/analyzing/impl/RaceLogDefinedMarkFinder.java deleted file mode 100644 index 23859c29e34..00000000000 --- a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/race/tracking/analyzing/impl/RaceLogDefinedMarkFinder.java +++ /dev/null @@ -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> { - public RaceLogDefinedMarkFinder(RaceLog raceLog) { - super(raceLog); - } - - public static class Factory implements AnalyzerFactory> { - @Override - public RaceLogAnalyzer> createAnalyzer(AbstractLog log) { - return new RaceLogDefinedMarkFinder((RaceLog) log); - } - } - - @Override - protected Collection performAnalysis() { - List result = new ArrayList(); - for (RaceLogEvent event : getLog().getUnrevokedEvents()) { - if (event instanceof RaceLogDefineMarkEvent) { - RaceLogDefineMarkEvent dME = (RaceLogDefineMarkEvent) event; - result.add(dME.getMark()); - } - } - return result; - } -} diff --git a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/race/tracking/analyzing/impl/RaceLogLastPingMappingEventFinder.java b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/race/tracking/analyzing/impl/RaceLogLastPingMappingEventFinder.java deleted file mode 100644 index dd484bce77a..00000000000 --- a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/race/tracking/analyzing/impl/RaceLogLastPingMappingEventFinder.java +++ /dev/null @@ -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 -extends LastPingMappingEventFinder { - - public RaceLogLastPingMappingEventFinder(RaceLog log, WithID forItem) { - super(log, forItem); - } - -} diff --git a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/race/tracking/analyzing/impl/RaceLogOpenEndedDeviceMappingCloser.java b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/race/tracking/analyzing/impl/RaceLogOpenEndedDeviceMappingCloser.java deleted file mode 100644 index 20e355f91ad..00000000000 --- a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/race/tracking/analyzing/impl/RaceLogOpenEndedDeviceMappingCloser.java +++ /dev/null @@ -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 { - - 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); - } - -} diff --git a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/race/tracking/analyzing/impl/RaceLogUsesOwnCompetitorsAnalyzer.java b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/race/tracking/analyzing/impl/RaceLogUsesOwnCompetitorsAnalyzer.java new file mode 100644 index 00000000000..ce8327b5cf4 --- /dev/null +++ b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/race/tracking/analyzing/impl/RaceLogUsesOwnCompetitorsAnalyzer.java @@ -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{ + public RaceLogUsesOwnCompetitorsAnalyzer(RaceLog raceLog) { + super(raceLog); + } + + @Override + protected Boolean performAnalysis() { + RaceLog raceLog = getLog(); + List event = new AllEventsOfTypeFinder<>(raceLog, /*only unrevoked*/ true, RaceLogUseCompetitorsFromRaceLogEvent.class).analyze(); + return event.size() >= 1; + } +} diff --git a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/race/tracking/analyzing/impl/RegisteredCompetitorsAnalyzer.java b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/race/tracking/analyzing/impl/RegisteredCompetitorsAnalyzer.java new file mode 100644 index 00000000000..3efe4f5f786 --- /dev/null +++ b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/race/tracking/analyzing/impl/RegisteredCompetitorsAnalyzer.java @@ -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> { + private RegattaLog regattaLog; + + public RegisteredCompetitorsAnalyzer(RaceLog raceLog, RegattaLog regattaLog) { + super(raceLog); + this.regattaLog = regattaLog; + } + + @Override + protected Set performAnalysis() { + final Set 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; + } +} diff --git a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/race/tracking/impl/AbstractRaceLogDeviceMappingEventImpl.java b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/race/tracking/impl/AbstractRaceLogDeviceMappingEventImpl.java deleted file mode 100644 index 5729089b331..00000000000 --- a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/race/tracking/impl/AbstractRaceLogDeviceMappingEventImpl.java +++ /dev/null @@ -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 -extends AbstractDeviceMappingEventImpl 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 getInvolvedBoats() { - return raceLogEventData.getInvolvedBoats(); - } - - @Override - public String toString() { - return raceLogEventData.toString(); - } -} diff --git a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/race/tracking/impl/RaceLogCloseOpenEndedDeviceMappingEventImpl.java b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/race/tracking/impl/RaceLogCloseOpenEndedDeviceMappingEventImpl.java deleted file mode 100644 index bd20d1e61eb..00000000000 --- a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/race/tracking/impl/RaceLogCloseOpenEndedDeviceMappingEventImpl.java +++ /dev/null @@ -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 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 getInvolvedBoats() { - return raceLogEventData.getInvolvedBoats(); - } - - @Override - public String toString() { - return raceLogEventData.toString(); - } - - @Override - public void accept(RaceLogEventVisitor visitor) { - visitor.visit(this); - } -} diff --git a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/race/tracking/impl/RaceLogDefineMarkEventImpl.java b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/race/tracking/impl/RaceLogDefineMarkEventImpl.java deleted file mode 100644 index acac6f03b27..00000000000 --- a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/race/tracking/impl/RaceLogDefineMarkEventImpl.java +++ /dev/null @@ -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(); - } - -} diff --git a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/race/tracking/impl/RaceLogDeviceCompetitorMappingEventImpl.java b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/race/tracking/impl/RaceLogDeviceCompetitorMappingEventImpl.java deleted file mode 100644 index 070972b396f..00000000000 --- a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/race/tracking/impl/RaceLogDeviceCompetitorMappingEventImpl.java +++ /dev/null @@ -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 - 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); - } -} diff --git a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/race/tracking/impl/RaceLogDeviceMarkMappingEventImpl.java b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/race/tracking/impl/RaceLogDeviceMarkMappingEventImpl.java deleted file mode 100644 index abcdf21bfd9..00000000000 --- a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/race/tracking/impl/RaceLogDeviceMarkMappingEventImpl.java +++ /dev/null @@ -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 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); - } -} diff --git a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/race/tracking/impl/RaceLogUseCompetitorsFromRaceLogEventImpl.java b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/race/tracking/impl/RaceLogUseCompetitorsFromRaceLogEventImpl.java new file mode 100644 index 00000000000..72a86255084 --- /dev/null +++ b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/race/tracking/impl/RaceLogUseCompetitorsFromRaceLogEventImpl.java @@ -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); + } + +} diff --git a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/regatta/RegattaLogEventVisitor.java b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/regatta/RegattaLogEventVisitor.java index e880a8fdad8..bb949b3860c 100644 --- a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/regatta/RegattaLogEventVisitor.java +++ b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/regatta/RegattaLogEventVisitor.java @@ -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); } diff --git a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/regatta/events/RegattaLogCloseOpenEndedDeviceMappingEvent.java b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/regatta/events/RegattaLogCloseOpenEndedDeviceMappingEvent.java index 31729ef4e2b..af41a6417b3 100644 --- a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/regatta/events/RegattaLogCloseOpenEndedDeviceMappingEvent.java +++ b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/regatta/events/RegattaLogCloseOpenEndedDeviceMappingEvent.java @@ -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 { +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(); } diff --git a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/regatta/events/RegattaLogDefineMarkEvent.java b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/regatta/events/RegattaLogDefineMarkEvent.java new file mode 100644 index 00000000000..03c39fb4e67 --- /dev/null +++ b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/regatta/events/RegattaLogDefineMarkEvent.java @@ -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(); +} diff --git a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/regatta/events/RegattaLogDeviceCompetitorMappingEvent.java b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/regatta/events/RegattaLogDeviceCompetitorMappingEvent.java index 9ac5a429372..67e73aa1528 100644 --- a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/regatta/events/RegattaLogDeviceCompetitorMappingEvent.java +++ b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/regatta/events/RegattaLogDeviceCompetitorMappingEvent.java @@ -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 { - -} +package com.sap.sailing.domain.abstractlog.regatta.events; + +import com.sap.sailing.domain.base.Competitor; + +public interface RegattaLogDeviceCompetitorMappingEvent extends RegattaLogDeviceMappingEvent { + +} diff --git a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/shared/events/DeviceMappingEvent.java b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/regatta/events/RegattaLogDeviceMappingEvent.java similarity index 71% rename from java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/shared/events/DeviceMappingEvent.java rename to java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/regatta/events/RegattaLogDeviceMappingEvent.java index ed69b2cb35d..5bce4d51ef9 100644 --- a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/shared/events/DeviceMappingEvent.java +++ b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/regatta/events/RegattaLogDeviceMappingEvent.java @@ -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 *

* 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 extends AbstractLogEvent, Revokable { +public interface RegattaLogDeviceMappingEvent extends RegattaLogEvent, Revokable { ItemType getMappedTo(); DeviceIdentifier getDevice(); diff --git a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/shared/events/impl/AbstractDeviceMappingEventImpl.java b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/regatta/events/RegattaLogDeviceMappingEventImpl.java similarity index 73% rename from java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/shared/events/impl/AbstractDeviceMappingEventImpl.java rename to java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/regatta/events/RegattaLogDeviceMappingEventImpl.java index 65a4d94129f..faeecc9eb1f 100644 --- a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/shared/events/impl/AbstractDeviceMappingEventImpl.java +++ b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/regatta/events/RegattaLogDeviceMappingEventImpl.java @@ -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 extends AbstractLogEventImpl implements -DeviceMappingEvent { +public abstract class RegattaLogDeviceMappingEventImpl extends AbstractLogEventImpl implements +RegattaLogDeviceMappingEvent { private static final long serialVersionUID = -8439653251231710356L; private final ItemType mappedTo; @@ -18,7 +18,7 @@ DeviceMappingEvent { 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 { 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); diff --git a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/regatta/events/RegattaLogDeviceMarkMappingEvent.java b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/regatta/events/RegattaLogDeviceMarkMappingEvent.java index c51078cdcdd..0bf70f85644 100644 --- a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/regatta/events/RegattaLogDeviceMarkMappingEvent.java +++ b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/regatta/events/RegattaLogDeviceMarkMappingEvent.java @@ -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 { - -} +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, RegattaLogEvent { + +} diff --git a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/regatta/events/impl/RegattaLogCloseOpenEndedDeviceMappingEventImpl.java b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/regatta/events/impl/RegattaLogCloseOpenEndedDeviceMappingEventImpl.java index 834b6a08bbe..8d45195d2a0 100644 --- a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/regatta/events/impl/RegattaLogCloseOpenEndedDeviceMappingEventImpl.java +++ b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/regatta/events/impl/RegattaLogCloseOpenEndedDeviceMappingEventImpl.java @@ -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 -implements RegattaLogCloseOpenEndedDeviceMappingEvent { +public class RegattaLogCloseOpenEndedDeviceMappingEventImpl extends AbstractLogEventImpl + 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 diff --git a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/regatta/events/impl/RegattaLogDefineMarkEventImpl.java b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/regatta/events/impl/RegattaLogDefineMarkEventImpl.java new file mode 100644 index 00000000000..88b6bda748d --- /dev/null +++ b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/regatta/events/impl/RegattaLogDefineMarkEventImpl.java @@ -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 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(); + } + +} diff --git a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/regatta/events/impl/RegattaLogDeviceCompetitorMappingEventImpl.java b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/regatta/events/impl/RegattaLogDeviceCompetitorMappingEventImpl.java index aaf28ee10f2..f969abeb0f4 100644 --- a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/regatta/events/impl/RegattaLogDeviceCompetitorMappingEventImpl.java +++ b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/regatta/events/impl/RegattaLogDeviceCompetitorMappingEventImpl.java @@ -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 implements +public class RegattaLogDeviceCompetitorMappingEventImpl extends RegattaLogDeviceMappingEventImpl 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); } diff --git a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/regatta/events/impl/RegattaLogDeviceMarkMappingEventImpl.java b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/regatta/events/impl/RegattaLogDeviceMarkMappingEventImpl.java index f00b34d389d..fcf242deadb 100644 --- a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/regatta/events/impl/RegattaLogDeviceMarkMappingEventImpl.java +++ b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/regatta/events/impl/RegattaLogDeviceMarkMappingEventImpl.java @@ -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 -implements RegattaLogDeviceMarkMappingEvent { +public class RegattaLogDeviceMarkMappingEventImpl extends RegattaLogDeviceMappingEventImpl 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); } diff --git a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/regatta/impl/BaseRegattaLogEventVisitor.java b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/regatta/impl/BaseRegattaLogEventVisitor.java index a55ee5b8c90..d934cf6e5dd 100644 --- a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/regatta/impl/BaseRegattaLogEventVisitor.java +++ b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/regatta/impl/BaseRegattaLogEventVisitor.java @@ -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) { + } } diff --git a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/regatta/impl/RegattaLogEventListener.java b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/regatta/impl/RegattaLogEventListener.java index e086b07da51..4d60900e54b 100644 --- a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/regatta/impl/RegattaLogEventListener.java +++ b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/regatta/impl/RegattaLogEventListener.java @@ -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); + } } diff --git a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/regatta/tracking/analyzing/impl/RegattaLogAnalyzer.java b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/regatta/tracking/analyzing/impl/RegattaLogAnalyzer.java new file mode 100644 index 00000000000..4513bf2dea7 --- /dev/null +++ b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/regatta/tracking/analyzing/impl/RegattaLogAnalyzer.java @@ -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 extends BaseLogAnalyzer + { + + public RegattaLogAnalyzer(RegattaLog raceLog) { + super(raceLog); + } + + protected Iterable getPassEvents() { + return log.getFixes(); + } + + protected Iterable getPassEventsDescending() { + return log.getFixesDescending(); + } +} diff --git a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/regatta/tracking/analyzing/impl/RegattaLogDefinedMarkAnalyzer.java b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/regatta/tracking/analyzing/impl/RegattaLogDefinedMarkAnalyzer.java new file mode 100644 index 00000000000..20c91877585 --- /dev/null +++ b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/regatta/tracking/analyzing/impl/RegattaLogDefinedMarkAnalyzer.java @@ -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> { + + public RegattaLogDefinedMarkAnalyzer(RegattaLog log) { + super(log); + } + + @Override + protected Collection performAnalysis() { + List result = new ArrayList(); + List defineMarkEvents = new AllEventsOfTypeFinder<>(log, true, RegattaLogDefineMarkEvent.class) + .analyze(); + + for (RegattaLogEvent event : defineMarkEvents) { + RegattaLogDefineMarkEvent dME = (RegattaLogDefineMarkEvent) event; + result.add(dME.getMark()); + } + return result; + } +} diff --git a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/regatta/tracking/analyzing/impl/RegattaLogDeviceCompetitorMappingFinder.java b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/regatta/tracking/analyzing/impl/RegattaLogDeviceCompetitorMappingFinder.java new file mode 100644 index 00000000000..a8eb5d6ee8c --- /dev/null +++ b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/regatta/tracking/analyzing/impl/RegattaLogDeviceCompetitorMappingFinder.java @@ -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 { + + public RegattaLogDeviceCompetitorMappingFinder(RegattaLog log) { + super(log); + } + + @Override + protected boolean isValidMapping(RegattaLogDeviceMappingEvent mapping) { + return mapping instanceof RegattaLogDeviceCompetitorMappingEvent; + } +} diff --git a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/regatta/tracking/analyzing/impl/RegattaLogDeviceMappingFinder.java b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/regatta/tracking/analyzing/impl/RegattaLogDeviceMappingFinder.java new file mode 100644 index 00000000000..635e7212c7d --- /dev/null +++ b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/regatta/tracking/analyzing/impl/RegattaLogDeviceMappingFinder.java @@ -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. + *

+ * 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}. + *

+ * 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 extends RegattaLogAnalyzer>>> { + 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 createMapping(DeviceIdentifier device, ItemT item, + TimePoint from, TimePoint to, Serializable originalEventId) { + return new DeviceMappingImpl(item, device, new TimeRangeImpl(from, to), + Collections.singletonList(originalEventId)); + } + + private List getItemSet(Map> map, T item) { + List list = map.get(item); + if (list == null) { + list = new ArrayList(); + map.put(item, list); + } + return list; + } + @Override + protected Map>> performAnalysis() { + Map>> events = new HashMap>>(); + Map>> mappings = new HashMap>>(); + Map closingEvents = new HashMap(); + + for (RegattaLogEvent e : getLog().getUnrevokedEvents()) { + if (e instanceof RegattaLogDeviceMappingEvent && isValidMapping(((RegattaLogDeviceMappingEvent) e))) { + @SuppressWarnings("unchecked") + RegattaLogDeviceMappingEvent mappingEvent = (RegattaLogDeviceMappingEvent) 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> closeOpenRanges(List> events, ItemT item, + Map closingEvents) { + List> result = new ArrayList>(); + for (RegattaLogDeviceMappingEvent 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; + } +} diff --git a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/regatta/tracking/analyzing/impl/RegattaLogDeviceMarkMappingFinder.java b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/regatta/tracking/analyzing/impl/RegattaLogDeviceMarkMappingFinder.java new file mode 100644 index 00000000000..c692f4d22ba --- /dev/null +++ b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/regatta/tracking/analyzing/impl/RegattaLogDeviceMarkMappingFinder.java @@ -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 { + + public RegattaLogDeviceMarkMappingFinder(RegattaLog log) { + super(log); + } + + @Override + protected boolean isValidMapping(RegattaLogDeviceMappingEvent mapping) { + return mapping instanceof RegattaLogDeviceMarkMappingEvent; + } +} diff --git a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/regatta/tracking/analyzing/impl/RegattaLogOpenEndedDeviceMappingCloser.java b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/regatta/tracking/analyzing/impl/RegattaLogOpenEndedDeviceMappingCloser.java index 783d3872c1c..431f644d934 100644 --- a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/regatta/tracking/analyzing/impl/RegattaLogOpenEndedDeviceMappingCloser.java +++ b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/regatta/tracking/analyzing/impl/RegattaLogOpenEndedDeviceMappingCloser.java @@ -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 { + RegattaLogAnalyzer> { + 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 performAnalysis() { + List result = new ArrayList(); + + 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; } } diff --git a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/shared/analyzing/CompetitorDeregistrator.java b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/shared/analyzing/CompetitorDeregistrator.java new file mode 100644 index 00000000000..813a4f40e18 --- /dev/null +++ b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/shared/analyzing/CompetitorDeregistrator.java @@ -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, EventT extends AbstractLogEvent, VisitorT> +extends BaseLogAnalyzer { + + private static final Logger logger = Logger.getLogger(CompetitorDeregistrator.class.getName()); + protected final Iterable competitorsToDeregister; + private AbstractLogEventAuthor eventAuthor; + + public CompetitorDeregistrator(LogT log, Iterable competitorsToDeregister, AbstractLogEventAuthor eventAuthor) { + super(log); + this.competitorsToDeregister = competitorsToDeregister; + this.eventAuthor = eventAuthor; + } + + @Override + protected Void performAnalysis() { + HashSet competitorSet = new HashSet(); + 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; + } +} diff --git a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/shared/analyzing/CompetitorsInLogAnalyzer.java b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/shared/analyzing/CompetitorsInLogAnalyzer.java new file mode 100644 index 00000000000..7001fda0406 --- /dev/null +++ b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/shared/analyzing/CompetitorsInLogAnalyzer.java @@ -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, EventT extends AbstractLogEvent, VisitorT> + extends BaseLogAnalyzer> { + + public CompetitorsInLogAnalyzer(LogT log) { + super(log); + } + + @Override + protected Set performAnalysis() { + Set result = new HashSet(); + + for (EventT event : getLog().getUnrevokedEvents()) { + if (event instanceof RegisterCompetitorEvent) { + result.add(((RegisterCompetitorEvent) event).getCompetitor()); + } + } + + return result; + } +} \ No newline at end of file diff --git a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/shared/analyzing/DeviceCompetitorMappingFinder.java b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/shared/analyzing/DeviceCompetitorMappingFinder.java deleted file mode 100644 index c562f1e6066..00000000000 --- a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/shared/analyzing/DeviceCompetitorMappingFinder.java +++ /dev/null @@ -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, EventT extends AbstractLogEvent, VisitorT> - extends DeviceMappingFinder { - - public static class Factory implements AnalyzerFactory>>> { - @SuppressWarnings({ "rawtypes", "unchecked" }) - @Override - public LogAnalyzer>>> createAnalyzer(AbstractLog log) { - return new DeviceCompetitorMappingFinder(log); - } - } - - public DeviceCompetitorMappingFinder(LogT log) { - super(log); - } - - @Override - protected boolean isValidMapping(DeviceMappingEvent mapping) { - return mapping instanceof DeviceCompetitorMappingEvent; - } -} diff --git a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/shared/analyzing/DeviceMappingFinder.java b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/shared/analyzing/DeviceMappingFinder.java deleted file mode 100644 index b973abcdca9..00000000000 --- a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/shared/analyzing/DeviceMappingFinder.java +++ /dev/null @@ -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. - *

- * 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}. - *

- * 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, EventT extends AbstractLogEvent, -VisitorT, ItemT extends WithID> extends BaseLogAnalyzer>>> { - - public static class Factory implements AnalyzerFactory>>> { - @SuppressWarnings({ "rawtypes", "unchecked" }) - @Override - public LogAnalyzer>>> 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 getMapping(DeviceIdentifier device, ItemT item, - TimePoint from, TimePoint to, Serializable originalEventId) { - return new DeviceMappingImpl(item, device, new TimeRangeImpl(from, to), - Collections.singletonList(originalEventId)); - } - - private List getItemSet(Map> map, T item) { - List list = map.get(item); - if (list == null) { - list = new ArrayList(); - map.put(item, list); - } - return list; - } - @Override - protected Map>> performAnalysis() { - Map>> events = new HashMap>>(); - Map>> mappings = new HashMap>>(); - Map> closingEvents = new HashMap>(); - - for (EventT e : getLog().getUnrevokedEvents()) { - if (e instanceof DeviceMappingEvent && isValidMapping(((DeviceMappingEvent) e))) { - @SuppressWarnings("unchecked") - DeviceMappingEvent mappingEvent = (DeviceMappingEvent) 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> closeOpenRanges(List> events, ItemT item, - Map> closingEvents) { - List> result = new ArrayList>(); - - for (DeviceMappingEvent 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; - } -} diff --git a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/shared/analyzing/DeviceMarkMappingFinder.java b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/shared/analyzing/DeviceMarkMappingFinder.java deleted file mode 100644 index c8ef195833f..00000000000 --- a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/shared/analyzing/DeviceMarkMappingFinder.java +++ /dev/null @@ -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, EventT extends AbstractLogEvent, VisitorT> - extends DeviceMappingFinder { - - public static class Factory implements AnalyzerFactory>>> { - @SuppressWarnings({ "rawtypes", "unchecked" }) - @Override - public LogAnalyzer>>> createAnalyzer(AbstractLog log) { - return new DeviceMarkMappingFinder(log); - } - } - - public DeviceMarkMappingFinder(LogT log) { - super(log); - } - - @Override - protected boolean isValidMapping(DeviceMappingEvent mapping) { - return mapping instanceof DeviceMarkMappingEvent; - } -} diff --git a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/shared/analyzing/LastPingMappingEventFinder.java b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/shared/analyzing/LastPingMappingEventFinder.java deleted file mode 100644 index 045dbbab2a8..00000000000 --- a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/shared/analyzing/LastPingMappingEventFinder.java +++ /dev/null @@ -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 , -EventT extends AbstractLogEvent, VisitorT, ItemT extends WithID> -extends BaseLogAnalyzer> { - private final WithID item; - - public LastPingMappingEventFinder(LogT log, WithID forItem) { - super(log); - this.item = forItem; - } - - @Override - protected DeviceMappingEvent 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 cast = (DeviceMappingEvent) mappingEvent; - return cast; - } - } - } - return null; - } - -} diff --git a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/shared/analyzing/OpenEndedDeviceMappingCloser.java b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/shared/analyzing/OpenEndedDeviceMappingCloser.java deleted file mode 100644 index df6d098f905..00000000000 --- a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/shared/analyzing/OpenEndedDeviceMappingCloser.java +++ /dev/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, -EventT extends AbstractLogEvent,VisitorT, CloseEventT extends CloseOpenEndedDeviceMappingEvent> -extends BaseLogAnalyzer> { - 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 performAnalysis() { - List result = new ArrayList(); - - 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; - } -} diff --git a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/shared/analyzing/RegisteredCompetitorsAnalyzer.java b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/shared/analyzing/RegisteredCompetitorsAnalyzer.java deleted file mode 100644 index 5a533a1a6e1..00000000000 --- a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/shared/analyzing/RegisteredCompetitorsAnalyzer.java +++ /dev/null @@ -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, EventT extends AbstractLogEvent, VisitorT> - extends BaseLogAnalyzer> { - - public static enum Factory implements AnalyzerFactory> { - INSTANCE; - - @SuppressWarnings({ "rawtypes", "unchecked" }) - @Override - public RegisteredCompetitorsAnalyzer createAnalyzer(AbstractLog log) { - return new RegisteredCompetitorsAnalyzer(log); - } - } - - public RegisteredCompetitorsAnalyzer(LogT log) { - super(log); - } - - @Override - protected Set performAnalysis() { - Set result = new HashSet(); - - for (EventT event : getLog().getUnrevokedEvents()) { - if (event instanceof RegisterCompetitorEvent) { - result.add(((RegisterCompetitorEvent) event).getCompetitor()); - } - } - - return result; - } - -} diff --git a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/shared/events/CloseOpenEndedDeviceMappingEvent.java b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/shared/events/CloseOpenEndedDeviceMappingEvent.java deleted file mode 100644 index b68af413ed0..00000000000 --- a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/shared/events/CloseOpenEndedDeviceMappingEvent.java +++ /dev/null @@ -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 extends AbstractLogEvent, 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(); -} diff --git a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/shared/events/DeviceCompetitorMappingEvent.java b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/shared/events/DeviceCompetitorMappingEvent.java deleted file mode 100644 index b69f0a013da..00000000000 --- a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/shared/events/DeviceCompetitorMappingEvent.java +++ /dev/null @@ -1,7 +0,0 @@ -package com.sap.sailing.domain.abstractlog.shared.events; - -import com.sap.sailing.domain.base.Competitor; - -public interface DeviceCompetitorMappingEvent extends DeviceMappingEvent { - -} diff --git a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/shared/events/DeviceMarkMappingEvent.java b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/shared/events/DeviceMarkMappingEvent.java deleted file mode 100644 index 57cf64aa6c9..00000000000 --- a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/shared/events/DeviceMarkMappingEvent.java +++ /dev/null @@ -1,8 +0,0 @@ -package com.sap.sailing.domain.abstractlog.shared.events; - -import com.sap.sailing.domain.base.Mark; - - -public interface DeviceMarkMappingEvent extends DeviceMappingEvent { - -} diff --git a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/shared/events/impl/BaseCloseOpenEndedDeviceMappingEventImpl.java b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/shared/events/impl/BaseCloseOpenEndedDeviceMappingEventImpl.java deleted file mode 100644 index 82f1b490017..00000000000 --- a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/shared/events/impl/BaseCloseOpenEndedDeviceMappingEventImpl.java +++ /dev/null @@ -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 extends AbstractLogEventImpl - implements CloseOpenEndedDeviceMappingEvent { - 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; - } -} diff --git a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/racelogtracking/DeviceMapping.java b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/racelogtracking/DeviceMapping.java index 1e7554055d6..6a2fd5f831d 100644 --- a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/racelogtracking/DeviceMapping.java +++ b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/racelogtracking/DeviceMapping.java @@ -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 diff --git a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/racelogtracking/impl/DeviceMappingImpl.java b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/racelogtracking/impl/DeviceMappingImpl.java index 7e916b7779b..c97d346d67b 100644 --- a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/racelogtracking/impl/DeviceMappingImpl.java +++ b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/racelogtracking/impl/DeviceMappingImpl.java @@ -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 implements DeviceMapping return timeRange.from(); } - public static DeviceMapping convertToDeviceMapping(DeviceMappingEvent event) { + public static DeviceMapping convertToDeviceMapping(RegattaLogDeviceMappingEvent event) { return new DeviceMappingImpl(event.getMappedTo(), event.getDevice(), new TimeRangeImpl(event.getFrom(), event.getTo()), event.getId()); } diff --git a/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/CompetitorProviderCacheInvalidationTest.java b/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/CompetitorProviderCacheInvalidationTest.java index 28a3e8018d4..3bccce5f657 100644 --- a/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/CompetitorProviderCacheInvalidationTest.java +++ b/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/CompetitorProviderCacheInvalidationTest.java @@ -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 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 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 expected) { Set actual = new HashSet<>(); Util.addAll(competitorProviderFlexibleLeaderboard.getAllCompetitors(), actual); assertEquals(expected, actual); Set actualForRace = new HashSet<>(); + + //For the race only the competitors registered on RaceLog as RaceLogUseCompetitorsFromRaceLogEvent is present + Set 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 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 actualForRaceYellow = new HashSet<>(); + Set 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); } } diff --git a/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/MarkPassingUpdateFromRaceLogFinishPositioingListTest.java b/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/MarkPassingUpdateFromRaceLogFinishPositioingListTest.java new file mode 100644 index 00000000000..6f44d8502a5 --- /dev/null +++ b/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/MarkPassingUpdateFromRaceLogFinishPositioingListTest.java @@ -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 withoutLast = new ArrayList<>(); + final NavigableSet 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 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... finishingTimes) { + final CompetitorResults results = new CompetitorResultsImpl(); + int rank = 1; + for (Pair finishingTime : finishingTimes) { + results.add(new CompetitorResultImpl(finishingTime.getA().getId(), finishingTime.getA().getName(), rank++, /* maxPointsReason */ + null, /* score */null, finishingTime.getB(), /* comment */null)); + } + return results; + } +} diff --git a/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/mock/MockedTrackedRace.java b/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/mock/MockedTrackedRace.java index 50d85683056..ecf28a13037 100755 --- a/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/mock/MockedTrackedRace.java +++ b/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/mock/MockedTrackedRace.java @@ -487,6 +487,27 @@ public class MockedTrackedRace implements DynamicTrackedRace { public Iterable getRaceColumns() { return null; } + + @Override + public Iterable getCompetitorsRegisteredInRegattaLog() { + return null; + } + + @Override + public void registerCompetitor(Competitor competitor) { + } + + @Override + public void registerCompetitors(Iterable competitor) { + } + + @Override + public void deregisterCompetitor(Competitor competitor) { + } + + @Override + public void deregisterCompetitors(Iterable 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 resolve(SharedDomainFactory domainFactory) { return this; } + + @Override + public void updateMarkPassingsAfterRaceLogChanges() { + } } diff --git a/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/mock/MockedTrackedRaceWithStartTimeAndRanks.java b/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/mock/MockedTrackedRaceWithStartTimeAndRanks.java index 2267dc3d786..95715cebb2c 100755 --- a/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/mock/MockedTrackedRaceWithStartTimeAndRanks.java +++ b/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/mock/MockedTrackedRaceWithStartTimeAndRanks.java @@ -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) { } diff --git a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/base/RaceColumn.java b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/base/RaceColumn.java index 73d88aa7405..821ce4d4c7f 100644 --- a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/base/RaceColumn.java +++ b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/base/RaceColumn.java @@ -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 null particularly + * for columns in a {@link MetaLeaderboard}. + * + * @return the regatta log or null 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 getAllCompetitors(); @@ -242,4 +253,96 @@ public interface RaceColumn extends Named { * Same as {@link #getAllCompetitors()}, but restricted to the single race identified by the fleet parameter. */ Iterable 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 getAllMarks(); + + /** + * Same as {@link #getAllMarks()}, but restricted to the single race identified by the fleet parameter. + */ + Iterable 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 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.

+ * + * 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. + *

+ * + * 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, 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 currentlyRegisteredCompetitors, Fleet fleet) throws CompetitorRegistrationOnRaceLogDisabledException; } diff --git a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/base/impl/AbstractRaceColumn.java b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/base/impl/AbstractRaceColumn.java index a6c40da780e..bc797de581b 100755 --- a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/base/impl/AbstractRaceColumn.java +++ b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/base/impl/AbstractRaceColumn.java @@ -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 raceIdentifiers; private Map 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 getAllCompetitors() { - final Set result = new HashSet<>(); + Set 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 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 getAllCompetitors(final Fleet fleet) { final Iterable 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 viaRaceLog = new RegisteredCompetitorsAnalyzer<>(getRaceLog(fleet)).analyze(); + Set 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 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 competitors, Fleet fleet) + throws CompetitorRegistrationOnRaceLogDisabledException { + if (!isCompetitorRegistrationInRacelogEnabled(fleet)) { + throw new CompetitorRegistrationOnRaceLogDisabledException("Competitor registration not allowed for fleet "+fleet+" in column "+this); + } + HashSet competitorSet = new HashSet(); + 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 getAllMarks() { + final Set 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 viaRegattaLog = new RegattaLogDefinedMarkAnalyzer(regattaLog).analyze(); + result.addAll(viaRegattaLog); + regattaLogMarksAlreadyAdded = true; + } + } + return result; + } + + @Override + public Iterable getMarks(Fleet fleet) { + final Set 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 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"); + } + } + } +} \ No newline at end of file diff --git a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/base/impl/RaceColumnInSeriesImpl.java b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/base/impl/RaceColumnInSeriesImpl.java index 2554e5d157d..975d98fc0a0 100755 --- a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/base/impl/RaceColumnInSeriesImpl.java +++ b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/base/impl/RaceColumnInSeriesImpl.java @@ -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(); + } } diff --git a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/base/impl/RaceColumnRaceLogReplicator.java b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/base/impl/RaceColumnRaceLogReplicator.java index 43a03747b95..55ac0fcd741 100644 --- a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/base/impl/RaceColumnRaceLogReplicator.java +++ b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/base/impl/RaceColumnRaceLogReplicator.java @@ -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); + } } diff --git a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/base/impl/RegattaImpl.java b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/base/impl/RegattaImpl.java index cf30214a41b..013a14b7ccb 100755 --- a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/base/impl/RegattaImpl.java +++ b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/base/impl/RegattaImpl.java @@ -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 true. 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 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 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 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 null, 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(), 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 RegattaImpl(RaceLogStore raceLogStore, RegattaLogStore regattaLogStore, - String name, BoatClass boatClass, TimePoint startDate, TimePoint endDate, Iterable series, boolean persistent, ScoringScheme scoringScheme, - Serializable id, CourseArea courseArea, boolean useStartTimeInference, RankingMetricConstructor rankingMetricConstructor) { + public RegattaImpl(RaceLogStore raceLogStore, RegattaLogStore regattaLogStore, String name, + BoatClass boatClass, TimePoint startDate, TimePoint endDate, Iterable 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 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 getCompetitorsRegisteredInRegattaLog() { + RegattaLog regattaLog = getRegattaLog(); + CompetitorsInLogAnalyzer analyzer = new CompetitorsInLogAnalyzer<>( + regattaLog); + return analyzer.analyze(); + } + + @Override + public void registerCompetitor(Competitor competitor) { + registerCompetitors(Collections.singleton(competitor)); + } + + @Override + public void registerCompetitors(Iterable 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 competitors) { + RegattaLog regattaLog = getRegattaLike().getRegattaLog(); + CompetitorDeregistrator deregisterer = new CompetitorDeregistrator<>(regattaLog, competitors, regattaLogEventAuthorForRegatta); + deregisterer.analyze(); + } } diff --git a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/base/impl/SimpleAbstractRaceColumn.java b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/base/impl/SimpleAbstractRaceColumn.java index df31a14f4ae..904259d680f 100755 --- a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/base/impl/SimpleAbstractRaceColumn.java +++ b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/base/impl/SimpleAbstractRaceColumn.java @@ -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 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(); + } + } } diff --git a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/leaderboard/FlexibleRaceColumn.java b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/leaderboard/FlexibleRaceColumn.java index 5f8bfbb45a7..e5a599e61dc 100755 --- a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/leaderboard/FlexibleRaceColumn.java +++ b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/leaderboard/FlexibleRaceColumn.java @@ -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); } diff --git a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/leaderboard/impl/AbstractLeaderboardImpl.java b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/leaderboard/impl/AbstractLeaderboardImpl.java index e5947108d43..4c3ef7f9c9f 100755 --- a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/leaderboard/impl/AbstractLeaderboardImpl.java +++ b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/leaderboard/impl/AbstractLeaderboardImpl.java @@ -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 null + * @param scoreComparator + * the comparator to use to compare basic scores, such as net points + * @param name + * must not be null */ 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 getAllCompetitors() { return getOrCreateCompetitorsProvider().getAllCompetitors(); } - + @Override public Iterable 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 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 getCompetitorsRegisteredInRegattaLog() { + RegattaLog regattaLog = getRegattaLike().getRegattaLog(); + CompetitorsInLogAnalyzer analyzer = new CompetitorsInLogAnalyzer<>( + regattaLog); + return analyzer.analyze(); + } + + @Override + public void registerCompetitor(Competitor competitor) { + registerCompetitors(Collections.singleton(competitor)); + } + + @Override + public void registerCompetitors(Iterable 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 competitors) { + RegattaLog regattaLog = getRegattaLike().getRegattaLog(); + CompetitorDeregistrator deregisterer = new CompetitorDeregistrator<>(regattaLog, competitors, regattaLogEventAuthorForAbstractLeaderboard); + deregisterer.analyze(); + } } diff --git a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/leaderboard/impl/CompetitorProviderFromRaceColumnsAndRegattaLike.java b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/leaderboard/impl/CompetitorProviderFromRaceColumnsAndRegattaLike.java index fbf18e485bc..cf94f788fe8 100644 --- a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/leaderboard/impl/CompetitorProviderFromRaceColumnsAndRegattaLike.java +++ b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/leaderboard/impl/CompetitorProviderFromRaceColumnsAndRegattaLike.java @@ -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: *

    *
  • a competitor is registered with or unregistered from a race log of any of the race columns or the regatta log
  • *
  • a race column is added or removed
  • *
  • a tracked race is linked to or unlinked from any of the race columns
  • + *
  • the racelog is marked as providing it's own competitors via the {@link RaceLogUseCompetitorsFromRaceLogEvent}
  • + *
  • the racelog is marked as no longer providing it's own competitors by revoking an event of type {@link RaceLogUseCompetitorsFromRaceLogEvent}
  • *
* + * 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 allCompetitorsCache; - + private final ConcurrentHashMap, Iterable> 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 getAllCompetitors() { if (allCompetitorsCache == null) { final Set 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 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 not 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 not eliminate + * suppressed competitors. */ public Iterable getAllCompetitors(final RaceColumn raceColumn, final Fleet fleet) { Pair key = new Pair<>(raceColumn, fleet); Iterable result = allCompetitorsCacheByRace.get(key); if (result == null) { - final Set resultSet = new HashSet<>(); + final Set 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 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 getCompetitorsFromRegattaLogAndRegisterAsRegattaLogListener() { - Set 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. } } diff --git a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/leaderboard/impl/FlexibleLeaderboardImpl.java b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/leaderboard/impl/FlexibleLeaderboardImpl.java index 62d50860e6a..5f4ad1673c5 100644 --- a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/leaderboard/impl/FlexibleLeaderboardImpl.java +++ b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/leaderboard/impl/FlexibleLeaderboardImpl.java @@ -38,11 +38,19 @@ import com.sap.sailing.domain.tracking.TrackedRace; import com.sap.sse.common.Duration; /** - * A leaderboard implementation that allows users to flexibly configure which columns exist. No constraints need to be observed regarding - * the columns belonging to the same regatta or even boat class.

+ * A leaderboard implementation that allows users to flexibly configure which columns exist. No constraints need to be + * observed regarding the columns belonging to the same regatta or even boat class. + *

* - * The flexible leaderboard listens as {@link RaceColumnListener} on all its {@link RaceColumn}s and forwards all events to - * all {@link RaceColumnListener}s subscribed with this leaderboard. + * The flexible leaderboard listens as {@link RaceColumnListener} on all its {@link RaceColumn}s and forwards all events + * to all {@link RaceColumnListener}s subscribed with this leaderboard. + *

+ * + * This class also implements the {@link IsRegattaLike} interface, emulating several aspects that otherwise would be + * found on a {@link Regatta} that is modeled properly with its series and fleets. In particular, the + * {@link IsRegattaLike} interface requires this leaderboard to provide a {@link RegattaLog} and to grant access to its + * {@link RaceColumn}s by name. A {@link BaseRegattaLikeImpl} is used as a delegate to implement the {@link IsRegattaLike} + * interface. * * @author Axel Uhl (D043530) * @@ -97,7 +105,7 @@ public class FlexibleLeaderboardImpl extends AbstractLeaderboardImpl implements * Deserialization has to be maintained in lock-step with {@link #writeObject(ObjectOutputStream) serialization}. * 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. + * assembled for this empty race log store and applied to all columns. */ private void readObject(ObjectInputStream ois) throws ClassNotFoundException, IOException { ois.defaultReadObject(); @@ -152,6 +160,7 @@ public class FlexibleLeaderboardImpl extends AbstractLeaderboardImpl implements column.addRaceColumnListener(this); races.add(column); column.setRaceLogInformation(raceLogStore, new FlexibleLeaderboardAsRegattaLikeIdentifier(this)); + column.setRegattaLikeHelper(regattaLikeHelper); getRaceColumnListeners().notifyListenersAboutRaceColumnAddedToContainer(column); } return column; diff --git a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/leaderboard/impl/RaceColumnImpl.java b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/leaderboard/impl/RaceColumnImpl.java index 12709513ea8..d128c2be3e7 100644 --- a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/leaderboard/impl/RaceColumnImpl.java +++ b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/leaderboard/impl/RaceColumnImpl.java @@ -2,9 +2,11 @@ package com.sap.sailing.domain.leaderboard.impl; import java.util.Collections; +import com.sap.sailing.domain.abstractlog.regatta.RegattaLog; import com.sap.sailing.domain.base.Fleet; import com.sap.sailing.domain.base.impl.AbstractRaceColumn; import com.sap.sailing.domain.leaderboard.FlexibleRaceColumn; +import com.sap.sailing.domain.regattalike.IsRegattaLike; import com.sap.sailing.domain.tracking.RaceExecutionOrderProvider; public class RaceColumnImpl extends AbstractRaceColumn implements FlexibleRaceColumn { @@ -13,6 +15,7 @@ public class RaceColumnImpl extends AbstractRaceColumn implements FlexibleRaceCo private boolean medalRace; private final RaceExecutionOrderProvider raceExecutionOrderProvider; + private IsRegattaLike regattaLikeHelper; public RaceColumnImpl(String name, boolean medalRace, RaceExecutionOrderProvider raceExecutionOrderProvider) { super(); @@ -51,4 +54,18 @@ public class RaceColumnImpl extends AbstractRaceColumn implements FlexibleRaceCo public RaceExecutionOrderProvider getRaceExecutionOrderProvider() { return raceExecutionOrderProvider; } + + @Override + public void setRegattaLikeHelper(IsRegattaLike regattaLikeHelper) { + this.regattaLikeHelper = regattaLikeHelper; + } + + @Override + public RegattaLog getRegattaLog() { + if (regattaLikeHelper != null){ + return regattaLikeHelper.getRegattaLog(); + } else { + return null; + } + } } diff --git a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/leaderboard/meta/MetaLeaderboardColumn.java b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/leaderboard/meta/MetaLeaderboardColumn.java index 491b73ff655..0583a1db0df 100755 --- a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/leaderboard/meta/MetaLeaderboardColumn.java +++ b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/leaderboard/meta/MetaLeaderboardColumn.java @@ -4,12 +4,15 @@ import java.util.Collections; 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.base.Competitor; 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.RaceColumnListener; import com.sap.sailing.domain.base.impl.SimpleAbstractRaceColumn; import com.sap.sailing.domain.common.RaceIdentifier; +import com.sap.sailing.domain.common.racelog.tracking.CompetitorRegistrationOnRaceLogDisabledException; import com.sap.sailing.domain.leaderboard.Leaderboard; import com.sap.sailing.domain.leaderboard.ResultDiscardingRule; import com.sap.sailing.domain.racelog.RaceLogIdentifier; @@ -219,4 +222,51 @@ public class MetaLeaderboardColumn extends SimpleAbstractRaceColumn implements R } return result; } + + @Override + public RegattaLog getRegattaLog() { + return null; + } + + @Override + public Iterable getAllMarks() { + return Collections.emptySet(); + } + + @Override + public Iterable getMarks(Fleet fleet) { + return Collections.emptySet(); + } + + @Override + public void registerCompetitor(Competitor competitor, Fleet fleet) + throws CompetitorRegistrationOnRaceLogDisabledException { + throw new CompetitorRegistrationOnRaceLogDisabledException(); + } + + @Override + public void registerCompetitors(Iterable competitor, Fleet fleet) + throws CompetitorRegistrationOnRaceLogDisabledException { + throw new CompetitorRegistrationOnRaceLogDisabledException(); + } + + @Override + public void deregisterCompetitor(Competitor competitors, Fleet fleet) + throws CompetitorRegistrationOnRaceLogDisabledException { + throw new CompetitorRegistrationOnRaceLogDisabledException(); + } + + @Override + public void deregisterCompetitors(Iterable competitors, Fleet fleet) + throws CompetitorRegistrationOnRaceLogDisabledException { + throw new CompetitorRegistrationOnRaceLogDisabledException(); + } + + @Override + public void enableCompetitorRegistrationOnRaceLog(Fleet fleetByName) { + } + + @Override + public void disableCompetitorRegistrationOnRaceLog(Fleet fleetByName) { + } } diff --git a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/masterdataimport/TopLevelMasterData.java b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/masterdataimport/TopLevelMasterData.java index 4a461b1dcaa..4a75185a9ef 100644 --- a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/masterdataimport/TopLevelMasterData.java +++ b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/masterdataimport/TopLevelMasterData.java @@ -13,11 +13,10 @@ import java.util.logging.Logger; import com.sap.sailing.domain.abstractlog.AbstractLogEvent; import com.sap.sailing.domain.abstractlog.race.RaceLog; import com.sap.sailing.domain.abstractlog.race.RaceLogEvent; -import com.sap.sailing.domain.abstractlog.race.tracking.RaceLogDeviceMarkMappingEvent; import com.sap.sailing.domain.abstractlog.regatta.RegattaLog; import com.sap.sailing.domain.abstractlog.regatta.RegattaLogEvent; +import com.sap.sailing.domain.abstractlog.regatta.events.RegattaLogDeviceMappingEvent; import com.sap.sailing.domain.abstractlog.regatta.events.RegattaLogDeviceMarkMappingEvent; -import com.sap.sailing.domain.abstractlog.shared.events.DeviceMappingEvent; import com.sap.sailing.domain.base.CourseArea; import com.sap.sailing.domain.base.Event; import com.sap.sailing.domain.base.Fleet; @@ -121,8 +120,8 @@ public class TopLevelMasterData implements Serializable { private void addAllFixesIfMappingEvent(GPSFixStore gpsFixStore, Map> relevantFixes, AbstractLogEvent logEvent) { - if (logEvent instanceof DeviceMappingEvent) { - DeviceMappingEvent mappingEvent = (DeviceMappingEvent) logEvent; + if (logEvent instanceof RegattaLogDeviceMappingEvent) { + RegattaLogDeviceMappingEvent mappingEvent = (RegattaLogDeviceMappingEvent) logEvent; try { addAllFixesForMappingEvent(gpsFixStore, relevantFixes, mappingEvent); } catch (NoCorrespondingServiceRegisteredException | TransformationException e) { @@ -133,7 +132,7 @@ public class TopLevelMasterData implements Serializable { } private void addAllFixesForMappingEvent(GPSFixStore gpsFixStore, Map> relevantFixes, - DeviceMappingEvent mappingEvent) throws NoCorrespondingServiceRegisteredException, TransformationException { + RegattaLogDeviceMappingEvent mappingEvent) throws NoCorrespondingServiceRegisteredException, TransformationException { DynamicGPSFixTrack track; if (isMarkMappingEvent(mappingEvent)) { track = new DynamicGPSFixTrackImpl(mappingEvent.getMappedTo(), 10000); @@ -157,21 +156,13 @@ public class TopLevelMasterData implements Serializable { } } - private boolean isMarkMappingEvent(DeviceMappingEvent mappingEvent) { - boolean isMarkMappingEvent = false; - if (mappingEvent instanceof RaceLogDeviceMarkMappingEvent || mappingEvent instanceof RegattaLogDeviceMarkMappingEvent) { - isMarkMappingEvent = true; - } - return isMarkMappingEvent; + private boolean isMarkMappingEvent(RegattaLogDeviceMappingEvent mappingEvent) { + return mappingEvent instanceof RegattaLogDeviceMarkMappingEvent; } /** * Workaround to look for the events connected to RegattaLeadeboards. There should be a proper connection between * regatta and event soon. TODO - * - * @param groupsToExport - * @param allEvents - * @return */ private Map> createEventMap(Set groupsToExport, Iterable allEvents) { @@ -194,7 +185,6 @@ public class TopLevelMasterData implements Serializable { } } } - } return eventsForLeaderboardGroup; } diff --git a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/racelog/tracking/EmptyGPSFixStore.java b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/racelog/tracking/EmptyGPSFixStore.java index a763c559b66..e88b8d4ca52 100644 --- a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/racelog/tracking/EmptyGPSFixStore.java +++ b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/racelog/tracking/EmptyGPSFixStore.java @@ -1,6 +1,6 @@ package com.sap.sailing.domain.racelog.tracking; -import com.sap.sailing.domain.abstractlog.AbstractLog; +import com.sap.sailing.domain.abstractlog.regatta.RegattaLog; import com.sap.sailing.domain.base.Competitor; import com.sap.sailing.domain.base.Mark; import com.sap.sailing.domain.common.racelog.tracking.TransformationException; @@ -23,12 +23,12 @@ public enum EmptyGPSFixStore implements GPSFixStore { @Override public void loadCompetitorTrack(DynamicGPSFixTrack track, - AbstractLog log, Competitor competitor) { + RegattaLog log, Competitor competitor) { } @Override public void loadMarkTrack(DynamicGPSFixTrack track, - AbstractLog log, Mark mark) { + RegattaLog log, Mark mark) { } @Override @@ -68,12 +68,12 @@ public enum EmptyGPSFixStore implements GPSFixStore { } @Override - public void loadCompetitorTrack(DynamicGPSFixTrack track, AbstractLog log, + public void loadCompetitorTrack(DynamicGPSFixTrack track, RegattaLog log, Competitor competitor, TimePoint start, TimePoint end) throws TransformationException { } @Override - public void loadMarkTrack(DynamicGPSFixTrack track, AbstractLog log, Mark mark, + public void loadMarkTrack(DynamicGPSFixTrack track, RegattaLog log, Mark mark, TimePoint start, TimePoint end) throws TransformationException, NoCorrespondingServiceRegisteredException { } } diff --git a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/racelog/tracking/GPSFixStore.java b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/racelog/tracking/GPSFixStore.java index eedda260a79..d0f3c30c81f 100644 --- a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/racelog/tracking/GPSFixStore.java +++ b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/racelog/tracking/GPSFixStore.java @@ -1,8 +1,8 @@ package com.sap.sailing.domain.racelog.tracking; -import com.sap.sailing.domain.abstractlog.AbstractLog; -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.RegattaLog; +import com.sap.sailing.domain.abstractlog.regatta.events.RegattaLogDeviceCompetitorMappingEvent; +import com.sap.sailing.domain.abstractlog.regatta.events.RegattaLogDeviceMarkMappingEvent; import com.sap.sailing.domain.base.Competitor; import com.sap.sailing.domain.base.Mark; import com.sap.sailing.domain.common.racelog.tracking.TransformationException; @@ -19,14 +19,14 @@ import com.sap.sse.common.WithID; public interface GPSFixStore { /** - * Load all fixes that correspond to the {@link DeviceCompetitorMappingEvent}s found in the {@code raceLog}. + * Load all fixes that correspond to the {@link RegattaLogDeviceCompetitorMappingEvent}s found in the {@code raceLog}. */ - void loadCompetitorTrack(DynamicGPSFixTrack track, AbstractLog log, + void loadCompetitorTrack(DynamicGPSFixTrack track, RegattaLog log, Competitor competitor) throws TransformationException; /** * Load all fixes within the start and end time point (inclusive) that correspond to the - * {@link DeviceCompetitorMappingEvent}s found in the {@code raceLog}. + * {@link RegattaLogDeviceCompetitorMappingEvent}s found in the {@code raceLog}. * * @param start * if null, the start of the time range for which to load fixes is only constrained by the @@ -35,18 +35,18 @@ public interface GPSFixStore { * if null, the end of the time range for which to load fixes is only constrained by the * device mapping intervals */ - void loadCompetitorTrack(DynamicGPSFixTrack track, AbstractLog log, + void loadCompetitorTrack(DynamicGPSFixTrack track, RegattaLog log, Competitor competitor, TimePoint start, TimePoint end) throws TransformationException; /** - * Load all fixes that correspond to the {@link DeviceMarkMappingEvent}s found in the {@code raceLog}. + * Load all fixes that correspond to the {@link RegattaLogDeviceMarkMappingEvent}s found in the {@code raceLog}. */ - void loadMarkTrack(DynamicGPSFixTrack track, AbstractLog log, Mark mark) throws TransformationException, + void loadMarkTrack(DynamicGPSFixTrack track, RegattaLog log, Mark mark) throws TransformationException, NoCorrespondingServiceRegisteredException; /** * Load all fixes within the start and end time point (inclusive) that correspond to the - * {@link DeviceMarkMappingEvent}s found in the {@code raceLog}. + * {@link RegattaLogDeviceMarkMappingEvent}s found in the {@code raceLog}. * * @param start * if null, the start of the time range for which to load fixes is only constrained by the @@ -55,7 +55,7 @@ public interface GPSFixStore { * if null, the end of the time range for which to load fixes is only constrained by the * device mapping intervals */ - void loadMarkTrack(DynamicGPSFixTrack track, AbstractLog log, Mark mark, TimePoint start, + void loadMarkTrack(DynamicGPSFixTrack track, RegattaLog log, Mark mark, TimePoint start, TimePoint end) throws TransformationException, NoCorrespondingServiceRegisteredException; /** diff --git a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/regattalike/HasRegattaLike.java b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/regattalike/HasRegattaLike.java index b246fb87258..deb887970fb 100644 --- a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/regattalike/HasRegattaLike.java +++ b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/regattalike/HasRegattaLike.java @@ -1,6 +1,8 @@ package com.sap.sailing.domain.regattalike; import com.sap.sailing.domain.abstractlog.race.RaceLog; +import com.sap.sailing.domain.base.Competitor; +import com.sap.sailing.domain.base.RaceColumn; import com.sap.sailing.domain.base.Regatta; import com.sap.sailing.domain.leaderboard.FlexibleLeaderboard; @@ -15,4 +17,26 @@ public interface HasRegattaLike { IsRegattaLike getRegattaLike(); RaceLog getRacelog(String raceColumnName, String fleetName); + + /** + * Determines the competitors registered in the regatta log. Note that this is not necessarily the complete set of + * competitors participating in this "regatta." For that, use {@link #getAllCompetitors()}. + */ + Iterable getCompetitorsRegisteredInRegattaLog(); + + /** + * Determines the combined set of all competitors from all race columns that this object's {@link IsRegattaLike} + * has. + * + * @see #getRegattaLike() + * @see IsRegattaLike#getRaceColumnByName(String) + * @see RaceColumn#getAllCompetitors() + */ + Iterable getAllCompetitors(); + + void registerCompetitor(Competitor competitor); + void registerCompetitors(Iterable competitor); + + void deregisterCompetitor(Competitor competitor); + void deregisterCompetitors(Iterable competitor); } diff --git a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/regattalike/LeaderboardThatHasRegattaLike.java b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/regattalike/LeaderboardThatHasRegattaLike.java index 1731a2710c3..a245e7d2f86 100644 --- a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/regattalike/LeaderboardThatHasRegattaLike.java +++ b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/regattalike/LeaderboardThatHasRegattaLike.java @@ -1,7 +1,9 @@ package com.sap.sailing.domain.regattalike; +import com.sap.sailing.domain.base.Competitor; import com.sap.sailing.domain.leaderboard.HasRaceColumnsAndRegattaLike; import com.sap.sailing.domain.leaderboard.Leaderboard; public interface LeaderboardThatHasRegattaLike extends Leaderboard, HasRaceColumnsAndRegattaLike { + Iterable getCompetitorsRegisteredInRegattaLog(); } diff --git a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/DynamicTrackedRace.java b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/DynamicTrackedRace.java index 85e2055ac8d..f2f1c07b13c 100755 --- a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/DynamicTrackedRace.java +++ b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/DynamicTrackedRace.java @@ -1,5 +1,8 @@ package com.sap.sailing.domain.tracking; +import com.sap.sailing.domain.abstractlog.race.CompetitorResult; +import com.sap.sailing.domain.abstractlog.race.RaceLog; +import com.sap.sailing.domain.abstractlog.race.RaceLogFinishPositioningConfirmedEvent; import com.sap.sailing.domain.base.Competitor; import com.sap.sailing.domain.base.CourseBase; import com.sap.sailing.domain.base.Mark; @@ -34,13 +37,28 @@ public interface DynamicTrackedRace extends TrackedRace { DynamicGPSFixTrack getOrCreateTrack(Mark mark); /** - * Updates all mark passings for competitor for this race. The - * mark passings must be provided in the order of the race's course and in - * increasing time stamps. Calling this method replaces all previous mark passings - * for this race for competitor and ensures that the "leaderboard" - * and all other derived information are updated accordingly. + * Updates all mark passings for competitor for this race. The mark passings must be provided in the + * order of the race's course and in increasing time stamps. Calling this method replaces all previous mark passings + * for this race for competitor and ensures that the "leaderboard" and all other derived information + * are updated accordingly. + *

+ * + * When an attached {@link RaceLog} has a {@link RaceLogFinishPositioningConfirmedEvent} that sets a + * {@link CompetitorResult#getFinishingTime() finishing time} for a competitor, it will be used to override the + * {@link MarkPassing#getTimePoint() time point} of the finishing waypoint's mark passing or, if no mark passing for + * the finishing waypoint exists yet for that competitor, create one. This can, in particular, be helpful when + * determining the time sailed for the {@code competitor} in order to determine the calculated time after applying + * any handicap rules and metrics.

*/ void updateMarkPassings(Competitor competitor, Iterable markPassings); + + /** + * When there is a significant change in the race logs attached to this race, such as adding another race log or + * removing a race log or switching to another pass in one of the race logs attached, the effects on the + * valid {@link RaceLogFinishPositioningConfirmedEvent} are analyzed, and if relevant, the mark passings + * for the finish line that are affected will be {@link #updateMarkPassings(Competitor, Iterable) updated}. + */ + void updateMarkPassingsAfterRaceLogChanges(); /** * Sets the start time as received from the tracking infrastructure. This isn't necessarily diff --git a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/MarkPassing.java b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/MarkPassing.java index c0e35282026..be1b5c8c789 100755 --- a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/MarkPassing.java +++ b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/MarkPassing.java @@ -8,4 +8,15 @@ public interface MarkPassing extends Timed { Waypoint getWaypoint(); Competitor getCompetitor(); + + /** + * This mark passing may be a replacement of another mark passing that was created based on some other evidence, + * such as a race committee-provided finishing time. In this case, this method will return the original mark + * passing that was replaced. For regular mark passings, this method will return {@code this} object. It may + * return {@code null} if this mark passing has been synthesized, e.g., solely from a {@link RaceLog} event and needs + * to be removed again if that event is removed because it didn't replace any original mark passing. + * + * TODO what if we receive a real update for the finish mark passing? + */ + MarkPassing getOriginal(); } diff --git a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/TrackedRace.java b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/TrackedRace.java index 290b6e31eb1..94fde1cf210 100755 --- a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/TrackedRace.java +++ b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/TrackedRace.java @@ -10,7 +10,8 @@ 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.state.racingprocedure.RacingProcedure; import com.sap.sailing.domain.abstractlog.regatta.RegattaLog; -import com.sap.sailing.domain.abstractlog.shared.events.DeviceMappingEvent; +import com.sap.sailing.domain.abstractlog.regatta.events.RegattaLogDefineMarkEvent; +import com.sap.sailing.domain.abstractlog.regatta.events.RegattaLogDeviceMappingEvent; import com.sap.sailing.domain.base.Competitor; import com.sap.sailing.domain.base.Course; import com.sap.sailing.domain.base.Leg; @@ -658,15 +659,10 @@ public interface TrackedRace extends Serializable, IsManagedByCache getMarksFromRaceAndLogs() { + default Iterable getMarksFromRegattaLogs() { return getMarks(); } } diff --git a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/impl/DummyMarkPassingWithTimePointAndCompetitor.java b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/impl/DummyMarkPassingWithTimePointAndCompetitor.java index 8dfccfd3922..0ff9c034bac 100755 --- a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/impl/DummyMarkPassingWithTimePointAndCompetitor.java +++ b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/impl/DummyMarkPassingWithTimePointAndCompetitor.java @@ -30,4 +30,9 @@ public class DummyMarkPassingWithTimePointAndCompetitor implements MarkPassing { public Competitor getCompetitor() { return competitor; } + + @Override + public MarkPassing getOriginal() { + return this; + } } diff --git a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/impl/DummyMarkPassingWithTimePointOnly.java b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/impl/DummyMarkPassingWithTimePointOnly.java index 1edec662f70..8e94e07d7d1 100755 --- a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/impl/DummyMarkPassingWithTimePointOnly.java +++ b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/impl/DummyMarkPassingWithTimePointOnly.java @@ -102,4 +102,9 @@ public class DummyMarkPassingWithTimePointOnly implements MarkPassing { } }; } + + @Override + public MarkPassing getOriginal() { + return this; + } } diff --git a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/impl/DynamicTrackedRaceImpl.java b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/impl/DynamicTrackedRaceImpl.java index 6a9f5794f4d..c631792071e 100755 --- a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/impl/DynamicTrackedRaceImpl.java +++ b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/impl/DynamicTrackedRaceImpl.java @@ -3,11 +3,13 @@ package com.sap.sailing.domain.tracking.impl; import java.io.IOException; import java.io.ObjectInputStream; import java.io.Serializable; +import java.util.ArrayList; import java.util.Collection; import java.util.ConcurrentModificationException; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; +import java.util.List; import java.util.Map; import java.util.NavigableSet; import java.util.Set; @@ -15,7 +17,11 @@ import java.util.function.Consumer; import java.util.logging.Level; import java.util.logging.Logger; +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.analyzing.impl.ConfirmedFinishPositioningListFinder; import com.sap.sailing.domain.abstractlog.race.analyzing.impl.RaceLogResolver; import com.sap.sailing.domain.base.BoatClass; import com.sap.sailing.domain.base.Competitor; @@ -74,6 +80,13 @@ DynamicTrackedRace, GPSTrackListener { private transient Set startTimeChangedListeners; private transient Set raceAbortedListeners; + /** + * Caches the result from {@link #getResultsFromRaceLogs}. This cache is updated in + * {@link #updateMarkPassingsAfterRaceLogChanges()} which must be called by + * {@link DynamicTrackedRaceLogListener} when the race log situation may have changed. + */ + private Map competitorResultsFromRaceLog; + public DynamicTrackedRaceImpl(TrackedRegatta trackedRegatta, RaceDefinition race, Iterable sidelines, WindStore windStore, GPSFixStore gpsFixStore, long delayToLiveInMillis, long millisecondsOverWhichToAverageWind, long millisecondsOverWhichToAverageSpeed, @@ -82,6 +95,7 @@ DynamicTrackedRace, GPSTrackListener { super(trackedRegatta, race, sidelines, windStore, gpsFixStore, delayToLiveInMillis, millisecondsOverWhichToAverageWind, millisecondsOverWhichToAverageSpeed, delayForCacheInvalidationOfWindEstimation, useInternalMarkPassingAlgorithm, rankingMetricConstructor, raceLogResolver); + this.competitorResultsFromRaceLog = new HashMap<>(); this.logListener = new DynamicTrackedRaceLogListener(this); if (markPassingCalculator != null) { logListener.setMarkPassingUpdateListener(markPassingCalculator.getListener()); @@ -468,8 +482,145 @@ DynamicTrackedRace, GPSTrackListener { notifyListeners(listener -> listener.markPassingReceived(competitor, oldMarkPassings, markPassings)); } + /** + * A mark passing produced from a {@link RaceLogFinishPositioningConfirmedEvent} where a + * {@link CompetitorResult#getFinishingTime() finishing time} has been provided for a competitor. The mark passing + * may have replaced an original mark passing, as provided by the {@link MarkPassingCalculator} or an external + * connector, or it may have been provided solely based on the presence of the finishing time in the + * {@link RaceLogFinishPositioningConfirmedEvent}. This leads to a different implementation of the + * {@link #getOriginal} implementation. + * + * @author Axel Uhl (D043530) + */ + private static class MarkPassingFromRaceLogProvidedFinishingTimeImpl extends MarkPassingImpl { + private static final long serialVersionUID = 2900812554717213461L; + private final MarkPassing original; + + public MarkPassingFromRaceLogProvidedFinishingTimeImpl(TimePoint timePoint, Waypoint waypoint, Competitor competitor, MarkPassing original) { + super(timePoint, waypoint, competitor); + this.original = original; + } + + /** + * May return {@code null} in case this mark passing was created based solely on the finishing + * time taken from a {@link RaceLogFinishPositioningConfirmedEvent}, or may contain the original + * {@link MarkPassing} that it replaced, otherwise. The original mark passing is expected not to + * implement this interface. + */ + @Override + public MarkPassing getOriginal() { + return original; + } + } + @Override - public void updateMarkPassings(Competitor competitor, Iterable markPassings) { + public void updateMarkPassings(Competitor competitor, final Iterable markPassings) { + final CompetitorResult resultFromRaceLog = competitorResultsFromRaceLog.get(competitor); + final Iterable markPassingsToUse = createOrUpdateFinishMarkPassingIfRequired(competitor, markPassings, resultFromRaceLog); + updateMarkPassingsNotConsideringFinishingTimesFromRaceLog(competitor, markPassingsToUse); + } + + @Override + public void updateMarkPassingsAfterRaceLogChanges() { + competitorResultsFromRaceLog = getResultsFromRaceLogs(); + updateFinishingTimesFromRaceLog(); + } + + /** + * Iterates over the {@code markPassings} and checks if the finish mark passing needs to be updated based on the + * {@link CompetitorResult}. In the following cases an updated mark passings {@link Iterable} is returned that + * contains an update regarding the finish mark passing: + * + *

    + *
  • An original finish mark passing exists, not wrapped by an updated mark passing or wrapped but not having the + * correct time, or no finish mark passing exists at all, and we have a finishing time in the + * {@code competitorResult}: then an updated wrapper mark passing is used; if an original finish mark passing + * existed, it will be used as the wrapper's {@link MarkPassing#getOriginal()} value; otherwise, {@code null} is + * used as the original.
  • + *
  • An original finish mark passing exists that is wrapped by an updated finishing time that came from the race + * log previously, and we have no finishing time in the {@code competitorResult}: then the wrapper is replaced by + * the original finish mark passing, thus reverting the finishing time to that of the original mark passing.
  • + *
  • A wrapper finish mark passing exists that has a {@code null} original, meaning it was created solely based + * on the race log finishing time, and we have no finish time in the {@code competitorResult}: then the synthetic + * finish mark passing is removed.
  • + *
+ * + * If no such modification was required, the unmodified {@code markPassings} object is returned; otherwise, a new + * {@link Iterable} that contains the modifications regarding the finish mark passing is returned.

+ * + * Note that if that is a result of {@link #getMarkPassings(Competitor)} or + * {@link #getMarkPassingsInOrder(Waypoint)} then the caller must hold the corresponding read lock while calling + * this method. + */ + private Iterable createOrUpdateFinishMarkPassingIfRequired(final Competitor competitor, Iterable markPassings, CompetitorResult competitorResult) { + assert competitorResult == null || competitorResult.getCompetitorId().equals(competitor.getId()); + final Waypoint finish = getRace().getCourse().getLastWaypoint(); + final List copyOfMarkPassings = new ArrayList<>(); + boolean neededToCreateOrUpdateFinishMarkPassing = false; + boolean foundFinishMarkPassing = false; + for (final MarkPassing originalMarkPassing : markPassings) { + if (originalMarkPassing.getWaypoint() != finish) { + copyOfMarkPassings.add(originalMarkPassing); + } else { + foundFinishMarkPassing = true; + final MarkPassing finishMarkPassingToUse; + if (competitorResult != null && competitorResult.getFinishingTime() != null + && (originalMarkPassing.getOriginal() == originalMarkPassing || !originalMarkPassing.getTimePoint().equals(competitorResult.getFinishingTime()))) { + // since we so far only have the original mark passing or a wrapper mark passing with an + // incorrect time point, we need to create a wrapper mark passing: + finishMarkPassingToUse = new MarkPassingFromRaceLogProvidedFinishingTimeImpl( + competitorResult.getFinishingTime(), finish, competitor, + originalMarkPassing.getOriginal()); + logger.info(getRace().getName()+": Updating finish mark passing "+originalMarkPassing.getOriginal()+" to "+finishMarkPassingToUse); + neededToCreateOrUpdateFinishMarkPassing = true; + } else { + finishMarkPassingToUse = originalMarkPassing.getOriginal(); + if (copyOfMarkPassings != originalMarkPassing) { + logger.info(getRace().getName()+": Reverting race log-based finish mark passing "+originalMarkPassing+" to "+finishMarkPassingToUse+ + " because no finishing time found anymore for that competitor in race log"); + neededToCreateOrUpdateFinishMarkPassing = true; + } + } + if (finishMarkPassingToUse != null) { + copyOfMarkPassings.add(finishMarkPassingToUse); + } + } + } + if (!foundFinishMarkPassing && competitorResult != null && competitorResult.getFinishingTime() != null) { + // need to create a synthetic finish mark passing based on the race log-provided finishing time + final MarkPassingFromRaceLogProvidedFinishingTimeImpl finishMarkPassingToUse = new MarkPassingFromRaceLogProvidedFinishingTimeImpl( + competitorResult.getFinishingTime(), finish, competitor, + /* no original finish mark passing exists; synthetic finish mark passing */ null); + copyOfMarkPassings.add(finishMarkPassingToUse); + logger.info(getRace().getName()+": Created "+finishMarkPassingToUse+" based on finishing time provided in race log"); + neededToCreateOrUpdateFinishMarkPassing = true; + } + return neededToCreateOrUpdateFinishMarkPassing ? copyOfMarkPassings : markPassings; + } + + private Map getResultsFromRaceLogs() { + final Map result = new HashMap<>(); + CompetitorResults results = null; + for (final RaceLog raceLog : attachedRaceLogs.values()) { + results = new ConfirmedFinishPositioningListFinder(raceLog).analyze(); + if (results != null) { + for (CompetitorResult cr : results) { + result.put(getRace().getCompetitorById(cr.getCompetitorId()), cr); + } + break; + } + } + return result; + } + + /** + * Updates the {@code markPassings} into the {@link #getMarkPassing(Competitor, Waypoint) mark passing data + * structure for the waypoints passed} and the {@link #getMarkPassings(Competitor) mark passing data structure for + * the competitor}. The mark passings are use as-is, without considering any + * {@link CompetitorResult#getFinishingTime() finishing times} for competitors coming from any {@link RaceLog}. + * See also {@link #updateMarkPassings(Competitor, Iterable)} which does consider those. + */ + private void updateMarkPassingsNotConsideringFinishingTimesFromRaceLog(Competitor competitor, Iterable markPassings) { LockUtil.lockForRead(getSerializationLock()); // keep serializer from reading the mark passings collections try { Map oldMarkPassings = new HashMap(); @@ -574,6 +725,36 @@ DynamicTrackedRace, GPSTrackListener { } } + /** + * The {@link CompetitorResults} from the race log as cached in {@link #competitorResultsFromRaceLog} may optionally + * set a finishing time for competitors. Also, depending on how the race log has been modified (e.g., a new pass + * could have been started or a {@link RaceLogFinishPositioningConfirmedEvent} could have been revoked) it may be + * possible that a finishing time previously set from the race log now has to be reset to its original state as + * coming from the tracking provider. This can either mean resetting the mark passing to its + * {@link MarkPassing#getOriginal() original} version or removing it in case the {@link MarkPassing#getOriginal()} + * method delivers {@code null}, meaning that this mark passing was solely based on the race log information which + * now would have disappeared. + */ + private void updateFinishingTimesFromRaceLog() { + final Waypoint finish = getRace().getCourse().getLastWaypoint(); + if (finish != null) { // can't do anything for an empty course + for (final Competitor competitor : getRace().getCompetitors()) { + final CompetitorResult competitorResult = competitorResultsFromRaceLog.get(competitor); + final NavigableSet markPassings = getMarkPassings(competitor); + final Iterable markPassingsToUse; + lockForRead(markPassings); + try { + markPassingsToUse = createOrUpdateFinishMarkPassingIfRequired(competitor, markPassings, competitorResult); + } finally { + unlockAfterRead(markPassings); + } + if (markPassingsToUse != markPassings) { + updateMarkPassingsNotConsideringFinishingTimesFromRaceLog(competitor, markPassingsToUse); + } + } + } + } + @Override public void lockForRead(Iterable markPassings) { getRace().getCourse().lockForRead(); @@ -758,8 +939,8 @@ DynamicTrackedRace, GPSTrackListener { @Override public void attachRaceLog(RaceLog raceLog) { - super.attachRaceLog(raceLog); logListener.addTo(raceLog); + super.attachRaceLog(raceLog); } @Override @@ -829,4 +1010,5 @@ DynamicTrackedRace, GPSTrackListener { public DynamicGPSFixTrack getTrack(Mark mark) { return (DynamicGPSFixTrack) super.getTrack(mark); } + } diff --git a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/impl/DynamicTrackedRaceLogListener.java b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/impl/DynamicTrackedRaceLogListener.java index a88bd5419e5..5abcfdd225a 100755 --- a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/impl/DynamicTrackedRaceLogListener.java +++ b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/impl/DynamicTrackedRaceLogListener.java @@ -9,6 +9,7 @@ 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.RaceLogFinishPositioningConfirmedEvent; import com.sap.sailing.domain.abstractlog.race.RaceLogFixedMarkPassingEvent; import com.sap.sailing.domain.abstractlog.race.RaceLogFlagEvent; import com.sap.sailing.domain.abstractlog.race.RaceLogPassChangeEvent; @@ -122,6 +123,7 @@ public class DynamicTrackedRaceLogListener extends BaseRaceLogEventVisitor { if (markPassingUpdateListener != null) { removeMarkPassingEvents(); } + trackedRace.updateMarkPassingsAfterRaceLogChanges(); } } @@ -157,6 +159,7 @@ public class DynamicTrackedRaceLogListener extends BaseRaceLogEventVisitor { markPassingDataFinder = new MarkPassingDataFinder(raceLog); analyzeMarkPassings(); } + trackedRace.updateMarkPassingsAfterRaceLogChanges(); } private void analyseTrackingTimes(RaceLog raceLog) { @@ -237,6 +240,7 @@ public class DynamicTrackedRaceLogListener extends BaseRaceLogEventVisitor { // previous pass was aborted; notify TracTrac trackedRace.onAbortedByRaceCommittee(abortingFlag.getUpperFlag()); } + trackedRace.updateMarkPassingsAfterRaceLogChanges(); } @Override @@ -249,6 +253,16 @@ public class DynamicTrackedRaceLogListener extends BaseRaceLogEventVisitor { analyzeCourseDesign(event.getCourseDesign()); } + /** + * We don't know whether this event is the one that is now valid; it could have a priority too low, or it could have + * a time point too early and thus superseded by a later event of the same type. There may also be other race logs. + * Therefore, re-evaluate the current situation "from scratch." + */ + @Override + public void visit(RaceLogFinishPositioningConfirmedEvent event) { + trackedRace.updateMarkPassingsAfterRaceLogChanges(); + } + @Override public void visit(RaceLogWindFixEvent event) { Wind wind = new RaceLogWindFixDeclinationHelper().getOptionallyDeclinationCorrectedWind(event); diff --git a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/impl/MarkPassingImpl.java b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/impl/MarkPassingImpl.java index 0c7ba574bab..8fbc636e24c 100755 --- a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/impl/MarkPassingImpl.java +++ b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/impl/MarkPassingImpl.java @@ -38,4 +38,9 @@ public class MarkPassingImpl implements MarkPassing { return ""+getTimePoint()+": "+getCompetitor()+" passed "+getWaypoint(); } + @Override + public MarkPassing getOriginal() { + return this; + } + } diff --git a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/impl/TrackedRaceImpl.java b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/impl/TrackedRaceImpl.java index b9d964fc98e..a18e6b488f9 100644 --- a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/impl/TrackedRaceImpl.java +++ b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/impl/TrackedRaceImpl.java @@ -6,7 +6,6 @@ import java.io.ObjectOutputStream; import java.io.Serializable; import java.util.ArrayList; import java.util.Arrays; -import java.util.Collection; import java.util.Collections; import java.util.Comparator; import java.util.ConcurrentModificationException; @@ -34,11 +33,6 @@ 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.MultiLogAnalyzer; -import com.sap.sailing.domain.abstractlog.MultiLogAnalyzer.AnalyzerFactory; -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.RaceLogDependentStartTimeEvent; import com.sap.sailing.domain.abstractlog.race.RaceLogEndOfTrackingEvent; @@ -53,9 +47,8 @@ import com.sap.sailing.domain.abstractlog.race.impl.RaceLogGateLineOpeningTimeEv import com.sap.sailing.domain.abstractlog.race.state.ReadonlyRaceState; import com.sap.sailing.domain.abstractlog.race.state.impl.RaceStateImpl; import com.sap.sailing.domain.abstractlog.race.state.racingprocedure.ReadonlyRacingProcedure; -import com.sap.sailing.domain.abstractlog.race.tracking.analyzing.impl.RaceLogDefinedMarkFinder; import com.sap.sailing.domain.abstractlog.regatta.RegattaLog; -import com.sap.sailing.domain.abstractlog.shared.analyzing.DeviceMarkMappingFinder; +import com.sap.sailing.domain.abstractlog.regatta.tracking.analyzing.impl.RegattaLogDefinedMarkAnalyzer; import com.sap.sailing.domain.base.BoatClass; import com.sap.sailing.domain.base.Competitor; import com.sap.sailing.domain.base.Course; @@ -118,7 +111,6 @@ import com.sap.sailing.domain.polars.NotEnoughDataHasBeenAddedException; import com.sap.sailing.domain.polars.PolarDataService; import com.sap.sailing.domain.racelog.tracking.EmptyGPSFixStore; import com.sap.sailing.domain.racelog.tracking.GPSFixStore; -import com.sap.sailing.domain.racelogtracking.DeviceMapping; import com.sap.sailing.domain.ranking.OneDesignRankingMetric; import com.sap.sailing.domain.ranking.RankingMetric; import com.sap.sailing.domain.ranking.RankingMetric.RankingInfo; @@ -662,13 +654,6 @@ public abstract class TrackedRaceImpl extends TrackedRaceWithWindEssentials impl } } - @Override - public synchronized void waitForLoadingFromGPSFixStoreToFinishRunning(RaceLog fromRaceLog) throws InterruptedException { - while (!attachedRaceLogs.containsKey(fromRaceLog.getId()) || loadingFromGPSFixStore) { - wait(); - } - } - @Override public synchronized void waitForLoadingFromGPSFixStoreToFinishRunning(RegattaLog fromRegattaLog) throws InterruptedException { while (!attachedRegattaLogs.containsKey(fromRegattaLog.getId()) || loadingFromGPSFixStore) { @@ -1838,10 +1823,6 @@ public abstract class TrackedRaceImpl extends TrackedRaceWithWindEssentials impl } private void loadGPSFixesForExtendedTimeRange(final TimePoint start, final TimePoint end, final boolean waitForGPSFixesToLoad) { - for (final RaceLog raceLog : attachedRaceLogs.values()) { - loadFixesForLog(raceLog, /* no need to addLogToMap because log has already been added during attachRaceLog */ null, - /* startOfTimeWindowToLoad */ start, /* endOfTimeWindowToLoad */ end, waitForGPSFixesToLoad); - } for (final RegattaLog regattaLog : attachedRegattaLogs.values()) { loadFixesForLog(regattaLog, /* no need to addLogToMap because log has already been added during attachRaceLog */ null, /* startOfTimeWindowToLoad */ start, /* endOfTimeWindowToLoad */ end, waitForGPSFixesToLoad); @@ -3205,8 +3186,8 @@ public abstract class TrackedRaceImpl extends TrackedRaceWithWindEssentials impl * waiters on this object are notified when done with adding the log to * addLogToMap. */ - private , EventT extends AbstractLogEvent, VisitorT> void loadFixesForLog( - final LogT log, ConcurrentHashMap addLogToMap, final boolean waitForGPSFixesToLoad) { + private void loadFixesForLog( + final RegattaLog log, ConcurrentHashMap addLogToMap, final boolean waitForGPSFixesToLoad) { if (log != null) { // Use the new log, that possibly contains device mappings, to load GPSFix tracks from the DB // When this tracked race is to be serialized, wait for the loading from stores to complete. @@ -3237,8 +3218,8 @@ public abstract class TrackedRaceImpl extends TrackedRaceWithWindEssentials impl * the time to use to crop the end of the time range for which to load fixes; if null, * the end of the time range will be restricted only by the device mapping intervals */ - private , EventT extends AbstractLogEvent, VisitorT> void loadFixesForLog(final LogT log, - ConcurrentHashMap addLogToMap, final TimePoint startOfTimeWindowToLoad, + private void loadFixesForLog(final RegattaLog log, + ConcurrentHashMap addLogToMap, final TimePoint startOfTimeWindowToLoad, final TimePoint endOfTimeWindowToLoad, final boolean waitForGPSFixesToLoad) { Thread t = new Thread("Mongo mark and competitor track loader for tracked race " + getRace().getName() + ", log " + log.getId()+" from "+startOfTimeWindowToLoad+" to "+endOfTimeWindowToLoad) { @@ -3266,7 +3247,7 @@ public abstract class TrackedRaceImpl extends TrackedRaceWithWindEssentials impl } logger.info("Finished loading competitor tracks for " + getRace().getName()); logger.info("Started loading mark tracks for " + getRace().getName()); - for (Mark mark : getMarksFromRaceAndLogs()) { + for (Mark mark : getMarksFromRegattaLogs()) { try { gpsFixStore.loadMarkTrack((DynamicGPSFixTrack) getOrCreateTrack(mark), log, mark, startOfTimeWindowToLoad, endOfTimeWindowToLoad); @@ -3314,20 +3295,11 @@ public abstract class TrackedRaceImpl extends TrackedRaceWithWindEssentials impl return loadingFromGPSFixStore; } - /** - * This can trigger fixes to be loaded, if there are {@link DeviceMapping}s in the {@code RaceLog}. - * If multiple race logs are attached, the threads that are spawned to load fixes will do so one - * after another, as they acquire a write lock on the {@link #loadingFromGPSFixStoreLock}. - */ @Override - public void attachRaceLog(final RaceLog raceLog) { - loadFixesForLog(raceLog, attachedRaceLogs, /* wait for fixes to load */ false); - try { - // The log is attached to the tracked race by a background thread; this method wants - // to guarantee that the log is at least really attached to the TrackedRace before returning: - waitForLoadingFromGPSFixStoreToFinishRunning(raceLog); - } catch (InterruptedException e) { - logger.log(Level.WARNING, "Interrupted while waiting for race log being attached", e); + public void attachRaceLog(RaceLog raceLog) { + synchronized (TrackedRaceImpl.this) { + attachedRaceLogs.put(raceLog.getId(), raceLog); + notifyAll(); } } @@ -3923,19 +3895,11 @@ public abstract class TrackedRaceImpl extends TrackedRaceWithWindEssentials impl } @Override - public Iterable getMarksFromRaceAndLogs() { - final List> allLogs = new ArrayList>(); - final List> raceLogs = new ArrayList<>(); - raceLogs.addAll(attachedRaceLogs.values()); - allLogs.addAll(raceLogs); - allLogs.addAll(attachedRegattaLogs.values()); - final Map>> markMappings = new MultiLogAnalyzer<>(new DeviceMarkMappingFinder.Factory(), - new MapWithValueCollectionReducer<>(), allLogs).analyze(); + public Iterable getMarksFromRegattaLogs() { final Set result = new HashSet<>(); - result.addAll(markMappings.keySet()); - final AnalyzerFactory> analyzerFactory = new RaceLogDefinedMarkFinder.Factory(); - Set marksDefinedInRaceLog = new MultiLogAnalyzer<>(analyzerFactory, new SetReducer(), raceLogs).analyze(); - result.addAll(marksDefinedInRaceLog); + for (RegattaLog log : attachedRegattaLogs.values()) { + result.addAll(new RegattaLogDefinedMarkAnalyzer(log).analyze()); + } return result; } } diff --git a/java/com.sap.sailing.gwt.ui.test/src/com/sap/sailing/gwt/home/shared/dispatch/CacheDispatchTest.java b/java/com.sap.sailing.gwt.ui.test/src/com/sap/sailing/gwt/home/shared/dispatch/CacheDispatchTest.java index ddbd6b0d13b..63b53bfacac 100644 --- a/java/com.sap.sailing.gwt.ui.test/src/com/sap/sailing/gwt/home/shared/dispatch/CacheDispatchTest.java +++ b/java/com.sap.sailing.gwt.ui.test/src/com/sap/sailing/gwt/home/shared/dispatch/CacheDispatchTest.java @@ -11,7 +11,7 @@ import org.junit.Test; import com.google.gwt.user.client.rpc.AsyncCallback; import com.sap.sse.gwt.dispatch.client.Action; -import com.sap.sse.gwt.dispatch.client.DispatchAsync; +import com.sap.sse.gwt.dispatch.client.DispatchSystemAsync; import com.sap.sse.gwt.dispatch.client.DispatchContext; import com.sap.sse.gwt.dispatch.client.Result; import com.sap.sse.gwt.dispatch.client.caching.CachingDispatch; @@ -263,7 +263,7 @@ public class CacheDispatchTest { } } - private class DispatchMock implements DispatchAsync { + private class DispatchMock implements DispatchSystemAsync { @Override public > void execute(A action, AsyncCallback callback) throws DispatchException { diff --git a/java/com.sap.sailing.gwt.ui.test/src/com/sap/sailing/gwt/ui/test/MockedTrackedRace.java b/java/com.sap.sailing.gwt.ui.test/src/com/sap/sailing/gwt/ui/test/MockedTrackedRace.java index 5d721c9a944..2367fbbc243 100755 --- a/java/com.sap.sailing.gwt.ui.test/src/com/sap/sailing/gwt/ui/test/MockedTrackedRace.java +++ b/java/com.sap.sailing.gwt.ui.test/src/com/sap/sailing/gwt/ui/test/MockedTrackedRace.java @@ -685,10 +685,6 @@ public class MockedTrackedRace implements DynamicTrackedRace { return null; } - @Override - public void waitForLoadingFromGPSFixStoreToFinishRunning(RaceLog rorRaceLog) throws InterruptedException { - } - @Override public void addRaceAbortedListener(RaceAbortedListener listener) { } @@ -790,4 +786,8 @@ public class MockedTrackedRace implements DynamicTrackedRace { public IsManagedByCache resolve(SharedDomainFactory domainFactory) { return this; } + + @Override + public void updateMarkPassingsAfterRaceLogChanges() { + } } diff --git a/java/com.sap.sailing.gwt.ui.test/src/com/sap/sailing/gwt/ui/test/PingMarkViaRaceLogTest.java b/java/com.sap.sailing.gwt.ui.test/src/com/sap/sailing/gwt/ui/test/PingMarkViaRegattaLogTest.java similarity index 88% rename from java/com.sap.sailing.gwt.ui.test/src/com/sap/sailing/gwt/ui/test/PingMarkViaRaceLogTest.java rename to java/com.sap.sailing.gwt.ui.test/src/com/sap/sailing/gwt/ui/test/PingMarkViaRegattaLogTest.java index 28fbb9b2c89..8809a8d1916 100644 --- a/java/com.sap.sailing.gwt.ui.test/src/com/sap/sailing/gwt/ui/test/PingMarkViaRaceLogTest.java +++ b/java/com.sap.sailing.gwt.ui.test/src/com/sap/sailing/gwt/ui/test/PingMarkViaRegattaLogTest.java @@ -15,13 +15,14 @@ import com.sap.sailing.domain.base.impl.SeriesImpl; import com.sap.sailing.domain.common.Position; import com.sap.sailing.domain.common.RankingMetrics; import com.sap.sailing.domain.common.impl.DegreePosition; +import com.sap.sailing.domain.common.racelog.tracking.DoesNotHaveRegattaLogException; import com.sap.sailing.domain.leaderboard.RegattaLeaderboard; import com.sap.sailing.domain.leaderboard.impl.HighPoint; import com.sap.sailing.domain.ranking.RankingMetricsFactory; import com.sap.sailing.gwt.ui.shared.MarkDTO; import com.sap.sailing.server.RacingEventService; -public class PingMarkViaRaceLogTest { +public class PingMarkViaRegattaLogTest { private SailingServiceImplMock sailingService; private RacingEventService service; private final String columnName = "column"; @@ -34,7 +35,7 @@ public class PingMarkViaRaceLogTest { } @Test - public void testPinging() { + public void testPinging() throws DoesNotHaveRegattaLogException { service.getMongoObjectFactory().getDatabase().dropDatabase(); Series series = new SeriesImpl("series", false, Collections.singletonList(fleet), Collections.singletonList(columnName), service); @@ -47,6 +48,6 @@ public class PingMarkViaRaceLogTest { MarkDTO mark = new MarkDTO("mark", "mark"); Position position = new DegreePosition(30, 40); - sailingService.pingMarkViaRaceLogTracking(leaderboard.getName(), columnName, fleet.getName(), mark, position); + sailingService.pingMark(leaderboard.getName(), mark, position); } } diff --git a/java/com.sap.sailing.gwt.ui/AdminConsole.html b/java/com.sap.sailing.gwt.ui/AdminConsole.html index 182b6efdd40..d170f37244a 100644 --- a/java/com.sap.sailing.gwt.ui/AdminConsole.html +++ b/java/com.sap.sailing.gwt.ui/AdminConsole.html @@ -41,6 +41,73 @@ + + + @@ -61,5 +128,10 @@ +

+

SAP Sailing Analytics

+

Loading, please wait...

+
+
diff --git a/java/com.sap.sailing.gwt.ui/EmbeddedMapAndWindChart.html b/java/com.sap.sailing.gwt.ui/EmbeddedMapAndWindChart.html index 440a01f45c2..7d41e6e92cc 100644 --- a/java/com.sap.sailing.gwt.ui/EmbeddedMapAndWindChart.html +++ b/java/com.sap.sailing.gwt.ui/EmbeddedMapAndWindChart.html @@ -24,6 +24,73 @@ + + + @@ -36,6 +103,11 @@ in order for this application to display correctly. - + +
+

SAP Sailing Analytics

+

Loading, please wait...

+
+
diff --git a/java/com.sap.sailing.gwt.ui/Home.html b/java/com.sap.sailing.gwt.ui/Home.html index e4172f8e8a0..549a7c2e720 100644 --- a/java/com.sap.sailing.gwt.ui/Home.html +++ b/java/com.sap.sailing.gwt.ui/Home.html @@ -15,8 +15,8 @@ - - + + diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/server/servlets/DispatchRPCServletImpl.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/server/servlets/DispatchRPCServletImpl.java index 69d15784fc4..e9f4778a01f 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/server/servlets/DispatchRPCServletImpl.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/server/servlets/DispatchRPCServletImpl.java @@ -1,6 +1,5 @@ package com.sap.sailing.gwt.home.server.servlets; -import java.util.UUID; import java.util.logging.Level; import java.util.logging.Logger; @@ -15,11 +14,11 @@ import com.sap.sailing.news.EventNewsService; import com.sap.sailing.server.RacingEventService; import com.sap.sse.gwt.dispatch.client.Action; import com.sap.sse.gwt.dispatch.client.Result; -import com.sap.sse.gwt.dispatch.client.ResultWrapper; import com.sap.sse.gwt.dispatch.client.exceptions.DispatchException; import com.sap.sse.gwt.dispatch.client.exceptions.ServerDispatchException; import com.sap.sse.gwt.dispatch.client.rpcimpl.DispatchRPC; import com.sap.sse.gwt.dispatch.client.rpcimpl.RequestWrapper; +import com.sap.sse.gwt.dispatch.client.rpcimpl.ResultWrapper; import com.sap.sse.util.ServiceTrackerFactory; public class DispatchRPCServletImpl extends ProxiedRemoteServiceServlet implements DispatchRPC { @@ -52,9 +51,9 @@ public class DispatchRPCServletImpl extends ProxiedRemoteServiceServlet implemen logger.log(Level.WARNING, "Server exception", d); throw d; } catch (Throwable t) { - String serverExceptionUUID = UUID.randomUUID().toString(); - logger.log(Level.SEVERE, "Uncaught server exception id: " + serverExceptionUUID, t); - throw new ServerDispatchException(serverExceptionUUID, t); + ServerDispatchException dispatchException = new ServerDispatchException(t); + logger.log(Level.SEVERE, "Uncaught server exception id: " + dispatchException.getExceptionId(), t); + throw dispatchException; } finally { long duration = System.currentTimeMillis() - start; final Level logLevel; diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/server/HomeServiceUtil.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/server/HomeServiceUtil.java index 05865420423..84aec3f51f1 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/server/HomeServiceUtil.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/server/HomeServiceUtil.java @@ -11,6 +11,8 @@ import java.util.Locale; import java.util.Map.Entry; import java.util.Random; import java.util.UUID; +import java.util.logging.Level; +import java.util.logging.Logger; import javax.servlet.http.HttpServletRequest; @@ -51,6 +53,8 @@ import com.sap.sse.shared.media.MediaDescriptor; import com.sap.sse.shared.media.VideoDescriptor; public final class HomeServiceUtil { + private static final Logger logger = Logger.getLogger(HomeServiceUtil.class.getName()); + public interface EventVisitor { void visit(EventBase event, boolean onRemoteServer, URL baseURL); } @@ -533,7 +537,9 @@ public final class HomeServiceUtil { try { return new URL(url.getProtocol(), url.getHost(), url.getPort(), /* file */""); } catch (MalformedURLException e) { - throw new ServerDispatchException(e); + ServerDispatchException dispatchException = new ServerDispatchException(e); + logger.log(Level.SEVERE, "Uncaught server exception id: " + dispatchException.getExceptionId(), e); + throw dispatchException; } } diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/AbstractCompetitorRegistrationsDialog.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/AbstractCompetitorRegistrationsDialog.java index dc97fa861dc..6c6369bab91 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/AbstractCompetitorRegistrationsDialog.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/AbstractCompetitorRegistrationsDialog.java @@ -1,17 +1,15 @@ package com.sap.sailing.gwt.ui.adminconsole; -import java.util.ArrayList; -import java.util.Collection; import java.util.HashSet; -import java.util.List; import java.util.Set; import com.google.gwt.core.client.Callback; import com.google.gwt.event.dom.client.ClickEvent; import com.google.gwt.event.dom.client.ClickHandler; -import com.google.gwt.user.client.rpc.AsyncCallback; +import com.google.gwt.user.client.Window; import com.google.gwt.user.client.ui.Button; import com.google.gwt.user.client.ui.CaptionPanel; +import com.google.gwt.user.client.ui.CheckBox; import com.google.gwt.user.client.ui.FlowPanel; import com.google.gwt.user.client.ui.HasVerticalAlignment; import com.google.gwt.user.client.ui.HorizontalPanel; @@ -30,10 +28,14 @@ public abstract class AbstractCompetitorRegistrationsDialog extends DataEntryDia protected CompetitorTableWrapper> allCompetitorsTable; protected CompetitorTableWrapper> registeredCompetitorsTable; protected final boolean filterByLeaderBoardInitially = false; - private final StringMessages stringMessages; + final StringMessages stringMessages; protected final SailingServiceAsync sailingService; final ErrorReporter errorReporter; private boolean editable; + private Button registerBtn; + private Button unregisterBtn; + private CheckBox showOnlyCompetitorsOfLogCheckBox; + private String boatClass; protected String leaderboardName; @@ -46,9 +48,9 @@ public abstract class AbstractCompetitorRegistrationsDialog extends DataEntryDia */ public AbstractCompetitorRegistrationsDialog(final SailingServiceAsync sailingService, final StringMessages stringMessages, final ErrorReporter errorReporter, boolean editable, - DialogCallback> callback, String leaderboardName, String boatClass) { - super(stringMessages.registerCompetitors(), /* messsage */null, stringMessages.save(), stringMessages.cancel(), /* validator */ - null, callback); + DialogCallback> callback, String leaderboardName, String boatClass, + com.sap.sse.gwt.client.dialog.DataEntryDialog.Validator> validator) { + super(stringMessages.registerCompetitors(), /* messsage */null, stringMessages.save(), stringMessages.cancel(), validator, callback); this.stringMessages = stringMessages; this.sailingService = sailingService; this.errorReporter = errorReporter; @@ -59,21 +61,13 @@ public abstract class AbstractCompetitorRegistrationsDialog extends DataEntryDia @Override protected Widget getAdditionalWidget() { - FlowPanel mainPanel = new FlowPanel(); - - Button addCompetitorButton = new Button(stringMessages.add(stringMessages.competitor())); + final FlowPanel mainPanel = new FlowPanel(); + final HorizontalPanel buttonPanel = new HorizontalPanel(); + final Button addCompetitorButton = new Button(stringMessages.add(stringMessages.competitor())); addCompetitorButton.addClickHandler(new ClickHandler() { @Override public void onClick(ClickEvent event) { - openAddCompetitorDialog(); - } - }); - - Button editCompetitorButton = new Button(stringMessages.edit(stringMessages.competitor())); - editCompetitorButton.addClickHandler(new ClickHandler() { - @Override - public void onClick(ClickEvent event) { - openEditCompetitorDialog(); + registeredCompetitorsTable.openEditCompetitorDialog(new CompetitorDTOImpl(), boatClass); } }); @@ -82,16 +76,14 @@ public abstract class AbstractCompetitorRegistrationsDialog extends DataEntryDia @Override public void onClick(ClickEvent event) { Set competitors = registeredCompetitorsTable.getSelectionModel().getSelectedSet(); - CompetitorInvitationHelper helper = new CompetitorInvitationHelper(sailingService, stringMessages, errorReporter); helper.inviteCompetitors(competitors, leaderboardName); } }); - - HorizontalPanel competitorRegistrationPanel = new HorizontalPanel(); - CaptionPanel allCompetitorsPanel = new CaptionPanel(stringMessages.competitorPool()); - CaptionPanel registeredCompetitorsPanel = new CaptionPanel(stringMessages.registeredCompetitors()); + final HorizontalPanel competitorRegistrationPanel = new HorizontalPanel(); + final CaptionPanel allCompetitorsPanel = new CaptionPanel(stringMessages.competitorPool()); + final CaptionPanel registeredCompetitorsPanel = new CaptionPanel(stringMessages.registeredCompetitors()); allCompetitorsTable = new CompetitorTableWrapper<>(sailingService, stringMessages, errorReporter, /* multiSelection */ true, /* enablePager */true); registeredCompetitorsTable = new CompetitorTableWrapper<>(sailingService, stringMessages, errorReporter, /* multiSelection */ @@ -99,8 +91,8 @@ public abstract class AbstractCompetitorRegistrationsDialog extends DataEntryDia allCompetitorsPanel.add(allCompetitorsTable); registeredCompetitorsPanel.add(registeredCompetitorsTable); VerticalPanel movePanel = new VerticalPanel(); - Button registerBtn = new Button("<"); - Button unregisterBtn = new Button(">"); + registerBtn = new Button("<"); + unregisterBtn = new Button(">"); registerBtn.setEnabled(editable); unregisterBtn.setEnabled(editable); movePanel.add(registerBtn); @@ -121,110 +113,80 @@ public abstract class AbstractCompetitorRegistrationsDialog extends DataEntryDia competitorRegistrationPanel.add(movePanel); competitorRegistrationPanel.setCellVerticalAlignment(movePanel, HasVerticalAlignment.ALIGN_MIDDLE); competitorRegistrationPanel.add(allCompetitorsPanel); - - refreshCompetitors(); - - mainPanel.add(addCompetitorButton); - mainPanel.add(editCompetitorButton); - mainPanel.add(inviteCompetitorsButton); + buttonPanel.add(addCompetitorButton); + buttonPanel.add(inviteCompetitorsButton); + mainPanel.add(buttonPanel); + showOnlyCompetitorsOfLogCheckBox = new CheckBox(stringMessages.showOnlyCompetitorsOfLog()); + showOnlyCompetitorsOfLogCheckBox.setValue(false); + showOnlyCompetitorsOfLogCheckBox.addClickHandler(new ClickHandler() { + @Override + public void onClick(ClickEvent event) { + if (Window.confirm(stringMessages.confirmLosingCompetitorEditsWhenTogglingLogBasedView())) { + refreshCompetitors(); + } else { + showOnlyCompetitorsOfLogCheckBox.setValue(!showOnlyCompetitorsOfLogCheckBox.getValue()); + } + } + }); + mainPanel.add(showOnlyCompetitorsOfLogCheckBox); + addAdditionalWidgets(mainPanel); mainPanel.add(competitorRegistrationPanel); - + refreshCompetitors(); return mainPanel; } - void move(CompetitorTableWrapper from, CompetitorTableWrapper to, Collection toMove) { - if (!toMove.isEmpty()) { - List newFromList = new ArrayList<>(); - Util.addAll(from.getFilterField().getAll(), newFromList); - newFromList.removeAll(toMove); - from.getFilterField().updateAll(newFromList); - List newToList = new ArrayList<>(); - Util.addAll(to.getFilterField().getAll(), newToList); - newToList.addAll(toMove); - to.getFilterField().updateAll(newToList); - } + public abstract void addAdditionalWidgets(FlowPanel mainPanel); + + protected void move(CompetitorTableWrapper from, CompetitorTableWrapper to, Iterable toMove) { + from.getFilterField().removeAll(toMove); + to.getFilterField().addAll(toMove); } private void moveSelected(CompetitorTableWrapper> from, CompetitorTableWrapper> to) { move(from, to, from.getSelectionModel().getSelectedSet()); } - - private void openAddCompetitorDialog() { - new CompetitorEditDialog(stringMessages, new CompetitorDTOImpl(), - new DataEntryDialog.DialogCallback() { - @Override - public void ok(CompetitorDTO competitor) { - sailingService.addOrUpdateCompetitor(competitor, new AsyncCallback() { - @Override - public void onFailure(Throwable caught) { - errorReporter.reportError("Error trying to add competitor: " + caught.getMessage()); - } - - @Override - public void onSuccess(CompetitorDTO updatedCompetitor) { - registeredCompetitorsTable.getFilterField().add(updatedCompetitor); - } - }); - } - - @Override - public void cancel() { - } - }, boatClass).show(); - } - - private void openEditCompetitorDialog() { - // get currently selected competitor - if (registeredCompetitorsTable.getSelectionModel().getSelectedSet().size() != 1) { - // show some warning - } else { - final CompetitorDTO competitorToEdit = registeredCompetitorsTable.getSelectionModel().getSelectedSet() - .iterator().next(); - new CompetitorEditDialog(stringMessages, competitorToEdit, - new DataEntryDialog.DialogCallback() { - @Override - public void ok(CompetitorDTO competitor) { - sailingService.addOrUpdateCompetitor(competitor, new AsyncCallback() { - @Override - public void onFailure(Throwable caught) { - errorReporter.reportError("Error trying to add competitor: " + caught.getMessage()); - } - - @Override - public void onSuccess(CompetitorDTO updatedCompetitor) { - int editedCompetitorIndex = registeredCompetitorsTable.getDataProvider().getList() - .indexOf(competitorToEdit); - registeredCompetitorsTable.getDataProvider().getList().remove(competitorToEdit); - registeredCompetitorsTable.getDataProvider().getList() - .add(editedCompetitorIndex, updatedCompetitor); - registeredCompetitorsTable.getDataProvider().refresh(); - } - }); - } - - @Override - public void cancel() { - } - }, /* boatClass */null).show(); - } + + protected boolean showOnlyCompetitorsOfLog(){ + return showOnlyCompetitorsOfLogCheckBox.getValue(); } protected void refreshCompetitors() { - registeredCompetitorsTable.getDataProvider().getList().clear(); + registeredCompetitorsTable.getFilterField().removeAll(); + allCompetitorsTable.getFilterField().removeAll(); + setRegisterableCompetitorsAndRegisteredCompetitors(); + } + + protected abstract void setRegisteredCompetitors(); + + private void setRegisterableCompetitorsAndRegisteredCompetitors() { allCompetitorsTable.refreshCompetitorList(null, new Callback, Throwable>() { @Override public void onSuccess(Iterable result) { setRegisteredCompetitors(); } - + @Override public void onFailure(Throwable reason) { } }); } - protected abstract void setRegisteredCompetitors(); + public void deactivateRegistrationButtons(String tooltip){ + registerBtn.setEnabled(false); + unregisterBtn.setEnabled(false); + registerBtn.setTitle(tooltip); + unregisterBtn.setTitle(tooltip); + validate(); + } + + public void activateRegistrationButtons(){ + registerBtn.setEnabled(true); + unregisterBtn.setEnabled(true); + registerBtn.setTitle(""); + unregisterBtn.setTitle(""); + validate(); + } @Override protected Set getResult() { diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/AbstractLogAddDeviceMappingDialog.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/AbstractLogAddDeviceMappingDialog.java deleted file mode 100644 index fc3353d32de..00000000000 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/AbstractLogAddDeviceMappingDialog.java +++ /dev/null @@ -1,205 +0,0 @@ -package com.sap.sailing.gwt.ui.adminconsole; - -import java.util.Date; -import java.util.List; - -import com.github.gwtbootstrap.datetimepicker.client.ui.base.HasViewMode.ViewMode; -import com.google.gwt.event.logical.shared.AttachEvent; -import com.google.gwt.event.logical.shared.AttachEvent.Handler; -import com.google.gwt.event.logical.shared.ValueChangeEvent; -import com.google.gwt.event.logical.shared.ValueChangeHandler; -import com.google.gwt.user.client.rpc.AsyncCallback; -import com.google.gwt.user.client.ui.CaptionPanel; -import com.google.gwt.user.client.ui.Grid; -import com.google.gwt.user.client.ui.HorizontalPanel; -import com.google.gwt.user.client.ui.Label; -import com.google.gwt.user.client.ui.ListBox; -import com.google.gwt.user.client.ui.TextBox; -import com.google.gwt.user.client.ui.VerticalPanel; -import com.google.gwt.user.client.ui.Widget; -import com.sap.sailing.domain.common.dto.CompetitorDTO; -import com.sap.sailing.domain.common.racelog.tracking.DeviceMappingConstants; -import com.sap.sailing.domain.common.racelog.tracking.MappableToDevice; -import com.sap.sailing.gwt.ui.adminconsole.ItemToMapToDeviceSelectionPanel.SelectionChangedHandler; -import com.sap.sailing.gwt.ui.client.SailingServiceAsync; -import com.sap.sailing.gwt.ui.client.StringMessages; -import com.sap.sailing.gwt.ui.shared.BetterDateTimeBox; -import com.sap.sailing.gwt.ui.shared.DeviceMappingDTO; -import com.sap.sailing.gwt.ui.shared.MarkDTO; -import com.sap.sse.gwt.client.ErrorReporter; -import com.sap.sse.gwt.client.dialog.DataEntryDialog; - -public abstract class AbstractLogAddDeviceMappingDialog extends DataEntryDialog { - protected final BetterDateTimeBox from; - protected final BetterDateTimeBox to; - protected final ListBox deviceType; - protected final TextBox deviceId; - protected final DeviceMappingQRCodeWidget qrWidget; - protected final StringMessages stringMessages; - protected MappableToDevice selectedItem; - protected final ItemToMapToDeviceSelectionPanel itemSelectionPanel; - protected final SailingServiceAsync sailingService; - protected Grid entryGrid; - - public AbstractLogAddDeviceMappingDialog(SailingServiceAsync sailingService, final ErrorReporter errorReporter, - final StringMessages stringMessages, DialogCallback callback, final DeviceMappingDTO mapping) { - super(stringMessages.add(stringMessages.deviceMappings()), stringMessages.add(stringMessages.deviceMappings()), - stringMessages.add(), stringMessages.cancel(), new DataEntryDialog.Validator() { - @Override - public String getErrorMessage(DeviceMappingDTO valueToValidate) { - String deviceType = valueToValidate.deviceIdentifier.deviceType; - String deviceId = valueToValidate.deviceIdentifier.deviceId; - if (deviceType == null || deviceType.isEmpty()) { - return stringMessages.pleaseEnterA(stringMessages.deviceType()); - } - if (deviceId == null || deviceId.isEmpty()) { - return stringMessages.pleaseEnterA(stringMessages.deviceId()); - } - if ((valueToValidate.from == null || valueToValidate.from.compareTo(new Date(Long.MIN_VALUE)) == 0) - && (valueToValidate.to == null || valueToValidate.to - .compareTo(new Date(Long.MAX_VALUE)) == 0)) { - return stringMessages.atMostOneEndOfTheTimeRangeMayBeOpen(); - } - if (valueToValidate.from != null && valueToValidate.to != null - && valueToValidate.to.before(valueToValidate.from)) { - return stringMessages.startOfTimeRangeMustLieBeforeEnd(); - } - - if (valueToValidate.mappedTo == null) { - return stringMessages.pleaseSelectAnItemToMapTo(); - } - return null; - } - }, true, callback); - - this.stringMessages = stringMessages; - this.sailingService = sailingService; - - from = initTimeBox(); - from.setValue(null); - to = initTimeBox(); - to.setValue(null); - - deviceType = createListBox(false); - sailingService.getDeserializableDeviceIdentifierTypes(new AsyncCallback>() { - @Override - public void onSuccess(List result) { - String typeToPreselect = mapping != null ? mapping.deviceIdentifier.deviceType : null; - int i = 0; - for (String type : result) { - deviceType.addItem(type); - if (type.equals(typeToPreselect)) { - deviceType.setSelectedIndex(i); - } - i++; - } - } - - @Override - public void onFailure(Throwable caught) { - errorReporter.reportError("Could not load deserializable device identifier types: " - + caught.getMessage()); - } - }); - - deviceId = createTextBox(""); - - itemSelectionPanel = new ItemToMapToDeviceSelectionPanel(sailingService, stringMessages, errorReporter, - new SelectionChangedHandler() { - @Override - public void onSelectionChange(MarkDTO mark) { - selectedItem = mark; - qrWidget.setMappedItem(DeviceMappingConstants.URL_MARK_ID_AS_STRING, mark.getIdAsString()); - validate(); - } - - @Override - public void onSelectionChange(CompetitorDTO competitor) { - selectedItem = competitor; - qrWidget.setMappedItem(DeviceMappingConstants.URL_COMPETITOR_ID_AS_STRING, - competitor.getIdAsString()); - validate(); - } - }, mapping != null ? mapping.mappedTo : null); - - if (mapping != null) { - deviceId.setValue(mapping.deviceIdentifier.deviceId); - from.setValue(mapping.from); - to.setValue(mapping.to); - } - - qrWidget = setupQRCodeWidget(); - qrWidget.generateQRCode(); - } - - protected abstract DeviceMappingQRCodeWidget setupQRCodeWidget(); - - protected abstract void loadCompetitorsAndMarks(); - - @Override - protected Widget getAdditionalWidget() { - HorizontalPanel panel = new HorizontalPanel(); - VerticalPanel leftSidePanel = new VerticalPanel(); - entryGrid = new Grid(4, 2); - CaptionPanel entryPanel = new CaptionPanel(stringMessages.mappingDetails()); - CaptionPanel qrPanel = new CaptionPanel(stringMessages.qrCode()); - - entryGrid.setWidget(0, 0, new Label(stringMessages.deviceType())); - entryGrid.setWidget(0, 1, deviceType); - entryGrid.setWidget(1, 0, new Label(stringMessages.deviceId())); - entryGrid.setWidget(1, 1, deviceId); - entryGrid.setWidget(2, 0, new Label(stringMessages.from())); - entryGrid.setWidget(2, 1, from); - entryGrid.setWidget(3, 0, new Label(stringMessages.to())); - entryGrid.setWidget(3, 1, to); - - VerticalPanel qrContentPanel = new VerticalPanel(); - Label explanation = new Label(stringMessages.deviceMappingQrCodeExplanation()); - explanation.setWidth("400px"); - qrContentPanel.add(explanation); - qrContentPanel.add(qrWidget); - - panel.add(leftSidePanel); - panel.add(itemSelectionPanel); - leftSidePanel.add(entryPanel); - leftSidePanel.add(qrPanel); - - entryPanel.setContentWidget(entryGrid); - qrPanel.setContentWidget(qrContentPanel); - - return panel; - } - - private BetterDateTimeBox initTimeBox() { - final BetterDateTimeBox timeBox = new BetterDateTimeBox(); - timeBox.addValueChangeHandler(new ValueChangeHandler() { - @Override - public void onValueChange(ValueChangeEvent event) { - validate(); - } - }); - timeBox.addAttachHandler(new Handler() { - @Override - public void onAttachOrDetach(AttachEvent event) { - if (event.isAttached()) { - addAutoHidePartner(timeBox.getPicker()); - } - } - }); - timeBox.setAutoClose(true); - timeBox.setStartView(ViewMode.HOUR); - timeBox.setFormat("dd/mm/yyyy hh:ii"); - return timeBox; - } - - @Override - protected boolean validate() { - if (super.validate()){ - qrWidget.generateQRCode(); - return true; - } else { - qrWidget.clear(); - return false; - } - } -} diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/AbstractLogTrackingDeviceMappingsDialog.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/AbstractLogTrackingDeviceMappingsDialog.java deleted file mode 100644 index 4a14ddb6a0e..00000000000 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/AbstractLogTrackingDeviceMappingsDialog.java +++ /dev/null @@ -1,228 +0,0 @@ -package com.sap.sailing.gwt.ui.adminconsole; - -import java.util.ArrayList; -import java.util.Date; -import java.util.List; - -import org.moxieapps.gwt.highcharts.client.Axis; -import org.moxieapps.gwt.highcharts.client.AxisTitle; -import org.moxieapps.gwt.highcharts.client.Chart; -import org.moxieapps.gwt.highcharts.client.Global; -import org.moxieapps.gwt.highcharts.client.Highcharts; -import org.moxieapps.gwt.highcharts.client.Legend; -import org.moxieapps.gwt.highcharts.client.Point; -import org.moxieapps.gwt.highcharts.client.Series; -import org.moxieapps.gwt.highcharts.client.ToolTip; -import org.moxieapps.gwt.highcharts.client.ToolTipData; -import org.moxieapps.gwt.highcharts.client.ToolTipFormatter; -import org.moxieapps.gwt.highcharts.client.events.PointMouseOverEvent; -import org.moxieapps.gwt.highcharts.client.events.PointMouseOverEventHandler; -import org.moxieapps.gwt.highcharts.client.plotOptions.SeriesPlotOptions; - -import com.google.gwt.cell.client.FieldUpdater; -import com.google.gwt.event.dom.client.ClickEvent; -import com.google.gwt.event.dom.client.ClickHandler; -import com.google.gwt.json.client.JSONObject; -import com.google.gwt.user.client.ui.Button; -import com.google.gwt.user.client.ui.FlowPanel; -import com.google.gwt.user.client.ui.HorizontalPanel; -import com.google.gwt.user.client.ui.Widget; -import com.google.gwt.view.client.CellPreviewEvent; -import com.sap.sailing.gwt.ui.adminconsole.DeviceMappingTableWrapper.FilterChangedHandler; -import com.sap.sailing.gwt.ui.client.SailingServiceAsync; -import com.sap.sailing.gwt.ui.client.StringMessages; -import com.sap.sailing.gwt.ui.common.client.DateAndTimeFormatterUtil; -import com.sap.sailing.gwt.ui.shared.DeviceMappingDTO; -import com.sap.sailing.gwt.ui.shared.MarkDTO; -import com.sap.sse.gwt.client.ErrorReporter; -import com.sap.sse.gwt.client.dialog.DataEntryDialog; - -public abstract class AbstractLogTrackingDeviceMappingsDialog extends DataEntryDialog { - public static final double PERCENTAGE_OF_TIMESPAN_TO_EXTEND_OPEN_ENDS = 0.1; - public static final String FIELD_INDEX = "index"; - public static final int CHART_WIDTH = 500; - public static final String SERIES_COLOR = "#fcb913"; - - protected ErrorReporter errorReporter; - protected SailingServiceAsync sailingService; - protected StringMessages stringMessages; - protected List mappings = new ArrayList(); - protected DeviceMappingTableWrapper deviceMappingTable; - - private Point[] data; - - private Date latest; - private Date earliest; - private Chart chart; - - - - public AbstractLogTrackingDeviceMappingsDialog(final SailingServiceAsync sailingService, final StringMessages stringMessages, - final ErrorReporter errorReporter, DialogCallback callback) { - super(stringMessages.mapDevices(), /*message*/ null, stringMessages.ok(), stringMessages.cancel(), /*validator*/ null, callback); - - this.stringMessages = stringMessages; - this.sailingService = sailingService; - this.errorReporter = errorReporter; - } - - @Override - protected Widget getAdditionalWidget() { - FlowPanel mainPanel = new FlowPanel(); - - HorizontalPanel buttonPanel = new HorizontalPanel(); - Button addMappingButton = new Button(stringMessages.add()); - addMappingButton.addClickHandler(new ClickHandler() { - @Override - public void onClick(ClickEvent event) { - addMapping(); - } - }); - buttonPanel.add(addMappingButton); - - Button importBtn = new Button(stringMessages.importFixes()); - importBtn.addClickHandler(new ClickHandler() { - @Override - public void onClick(ClickEvent event) { - importFixes(); - } - }); - buttonPanel.add(importBtn); - mainPanel.add(buttonPanel); - - deviceMappingTable = new DeviceMappingTableWrapper(sailingService, stringMessages, errorReporter); - - deviceMappingTable.addFilterChangedHandler(new FilterChangedHandler() { - @Override - public void onFilterChanged(List filteredList) { - mappings = filteredList; - updateChart(); - } - }); - deviceMappingTable.getTable().addCellPreviewHandler(new CellPreviewEvent.Handler() { - @Override - public void onCellPreview(CellPreviewEvent event) { - int i = mappings.indexOf(event.getValue()); - chart.getSeries()[0].getPoints()[i].select(true, false); - } - }); - ImagesBarColumn actionCol = - new ImagesBarColumn( - new RaceLogTrackingDeviceMappingsImagesBarCell(stringMessages)); - actionCol.setFieldUpdater(getActionColFieldUpdater()); - deviceMappingTable.getTable().addColumn(actionCol, stringMessages.actions()); - - HorizontalPanel deviceMappingPannel = new HorizontalPanel(); - mainPanel.add(deviceMappingPannel); - - chart = new Chart() - .setType(Series.Type.COLUMN_RANGE) - .setChartTitleText(stringMessages.deviceMappings()) - .setLegend(new Legend().setEnabled(false)) - .setInverted(true); - - chart.setSeriesPlotOptions(new SeriesPlotOptions().setPointMouseOverEventHandler(new PointMouseOverEventHandler() { - @Override - public boolean onMouseOver(PointMouseOverEvent pointMouseOverEvent) { - int i = (int) pointMouseOverEvent.getXAsLong(); - deviceMappingTable.getSelectionModel().setSelected(mappings.get(i), true); - chart.getSeries()[0].getPoints()[i].select(true, false); - return true; - } - }).setColor(SERIES_COLOR)); - - Highcharts.setOptions( - new Highcharts.Options().setGlobal( - new Global() - .setUseUTC(false) - )); - - chart.getXAxis().setOption("labels/enabled", false) - .setGridLineWidth(0) - .setMinorGridLineWidth(0); - - chart.getYAxis() - .setAxisTitle(new AxisTitle().setText(stringMessages.time())) - .setType(Axis.Type.DATE_TIME) - .setGridLineWidth(0) - .setMinorGridLineWidth(0); - - chart.setWidth(CHART_WIDTH + "px"); - chart.setHeight("400px"); - - chart.setToolTip(new ToolTip().setFormatter(new ToolTipFormatter() { - @Override - public String format(ToolTipData toolTipData) { - int index = (int) toolTipData.getXAsLong(); - DeviceMappingDTO mapping = mappings.get(index); - String itemType = mapping.mappedTo instanceof MarkDTO ? stringMessages.mark() : stringMessages.competitor(); - - return "" + stringMessages.device() + ": " + mapping.deviceIdentifier.deviceType + " - " + mapping.deviceIdentifier.deviceId + "
" + - "" + stringMessages.mappedTo() + ": " + itemType + " - " + mapping.mappedTo + "
" + - "" + stringMessages.from() + ": " + DateAndTimeFormatterUtil.formatDateAndTime(mapping.from) + "
" + - "" + stringMessages.to() + ": " + DateAndTimeFormatterUtil.formatDateAndTime(mapping.to); - } - })); - - deviceMappingPannel.add(chart); - deviceMappingPannel.add(deviceMappingTable); - - return mainPanel; - } - - protected abstract FieldUpdater getActionColFieldUpdater(); - - void updateChart() { - earliest = new Date(Long.MAX_VALUE); - latest = new Date(Long.MIN_VALUE); - for (DeviceMappingDTO mapping : mappings) { - updateExtremes(mapping); - } - - data = new Point[mappings.size()]; - long earliestMillis = earliest.getTime(); - long latestMillis = latest.getTime(); - long range = latestMillis - earliestMillis; - long extension = (long) (range * PERCENTAGE_OF_TIMESPAN_TO_EXTEND_OPEN_ENDS); - long yMin = earliestMillis - extension; - long yMax = latestMillis + extension; - - int i = 0; - for (DeviceMappingDTO mapping : mappings) { - JSONObject userData = new JSONObject(); - userData.put(FIELD_INDEX, userData); - - long from = mapping.from == null ? yMin - range : mapping.from.getTime(); - long to = mapping.to == null ? yMax + range : mapping.to.getTime(); - - data[i] = new Point(i, from, to); - - i++; - } - - chart.removeAllSeries(false); - - chart.addSeries(chart.createSeries() - .setName(stringMessages.deviceMappings()) - .setPoints(data)); - - chart.getYAxis().setExtremes(yMin, yMax); - } - - private void updateExtremes(DeviceMappingDTO mapping) { - if (mapping.from != null && earliest.after(mapping.from)) earliest = mapping.from; - if (mapping.to != null && latest.before(mapping.to)) latest = mapping.to; - if (mapping.to != null && earliest.after(mapping.to)) earliest = mapping.to; - if (mapping.from != null && latest.before(mapping.from)) latest = mapping.from; - } - - protected abstract void refresh(); - - protected abstract void showAddMappingDialog(DeviceMappingDTO mapping); - - private void addMapping() { - showAddMappingDialog(null); - } - - protected abstract void importFixes(); -} diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/CompetitorPanel.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/CompetitorPanel.java index 79570bfeb05..6df107211ff 100755 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/CompetitorPanel.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/CompetitorPanel.java @@ -1,15 +1,9 @@ package com.sap.sailing.gwt.ui.adminconsole; -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; import java.util.Set; -import com.google.gwt.cell.client.FieldUpdater; import com.google.gwt.event.dom.client.ClickEvent; import com.google.gwt.event.dom.client.ClickHandler; -import com.google.gwt.user.client.Window; -import com.google.gwt.user.client.rpc.AsyncCallback; import com.google.gwt.user.client.ui.Button; import com.google.gwt.user.client.ui.HorizontalPanel; import com.google.gwt.user.client.ui.SimplePanel; @@ -20,10 +14,8 @@ import com.sap.sailing.domain.common.dto.CompetitorDTO; import com.sap.sailing.domain.common.dto.CompetitorDTOImpl; import com.sap.sailing.gwt.ui.client.SailingServiceAsync; import com.sap.sailing.gwt.ui.client.StringMessages; -import com.sap.sse.common.Util; import com.sap.sse.gwt.client.ErrorReporter; import com.sap.sse.gwt.client.celltable.RefreshableMultiSelectionModel; -import com.sap.sse.gwt.client.dialog.DataEntryDialog.DialogCallback; /** * Allows an administrator to view and edit the set of competitors currently maintained by the server. @@ -32,9 +24,6 @@ import com.sap.sse.gwt.client.dialog.DataEntryDialog.DialogCallback; * */ public class CompetitorPanel extends SimplePanel { - private final SailingServiceAsync sailingService; - private final StringMessages stringMessages; - private final ErrorReporter errorReporter; private final CompetitorTableWrapper> competitorTable; private final RefreshableMultiSelectionModel refreshableCompetitorSelectionModel; private final String leaderboardName; @@ -47,9 +36,6 @@ public class CompetitorPanel extends SimplePanel { public CompetitorPanel(final SailingServiceAsync sailingService, final String leaderboardName, final StringMessages stringMessages, final ErrorReporter errorReporter) { super(); - this.sailingService = sailingService; - this.stringMessages = stringMessages; - this.errorReporter = errorReporter; this.leaderboardName = leaderboardName; this.competitorTable = new CompetitorTableWrapper<>(sailingService, stringMessages, errorReporter, /* multiSelection */ true, /* enablePager */ false); this.refreshableCompetitorSelectionModel = (RefreshableMultiSelectionModel) competitorTable.getSelectionModel(); @@ -74,7 +60,7 @@ public class CompetitorPanel extends SimplePanel { allowReloadButton.addClickHandler(new ClickHandler() { @Override public void onClick(ClickEvent event) { - allowUpdate(refreshableCompetitorSelectionModel.getSelectedSet()); + competitorTable.allowUpdate(refreshableCompetitorSelectionModel.getSelectedSet()); } }); buttonPanel.add(allowReloadButton); @@ -115,24 +101,8 @@ public class CompetitorPanel extends SimplePanel { } competitorsPanel.add(buttonPanel); - - // competitor table - ImagesBarColumn competitorActionColumn = new ImagesBarColumn( - new CompetitorConfigImagesBarCell(stringMessages)); - competitorActionColumn.setFieldUpdater(new FieldUpdater() { - @Override - public void update(int index, final CompetitorDTO competitor, String value) { - if (CompetitorConfigImagesBarCell.ACTION_EDIT.equals(value)) { - openEditCompetitorDialog(competitor); - } else if (CompetitorConfigImagesBarCell.ACTION_REFRESH.equals(value)) { - allowUpdate(Collections.singleton(competitor)); - } - } - - }); - - competitorTable.getTable().addColumn(competitorActionColumn, stringMessages.actions()); mainPanel.add(competitorTable); + refreshableCompetitorSelectionModel.addSelectionChangeHandler(new Handler() { @Override public void onSelectionChange(SelectionChangeEvent event) { @@ -146,52 +116,10 @@ public class CompetitorPanel extends SimplePanel { } } - private void allowUpdate(final Iterable competitors) { - List serializableSingletonList = new ArrayList(); - Util.addAll(competitors, serializableSingletonList); - sailingService.allowCompetitorResetToDefaults(serializableSingletonList, new AsyncCallback() { - @Override - public void onFailure(Throwable caught) { - errorReporter.reportError("Error trying to allow resetting competitors " + competitors - + " to defaults: " + caught.getMessage()); - } - - @Override - public void onSuccess(Void result) { - Window.alert(stringMessages.successfullyAllowedCompetitorReset(competitors.toString())); - } - }); - } - private void openAddCompetitorDialog() { - openEditCompetitorDialog(new CompetitorDTOImpl()); + competitorTable.openEditCompetitorDialog(new CompetitorDTOImpl(), /* boat class to be used from CompetitorDTO */ null); } - - private void openEditCompetitorDialog(CompetitorDTO competitor) { - final CompetitorEditDialog dialog = new CompetitorEditDialog(stringMessages, competitor, new DialogCallback() { - @Override - public void ok(CompetitorDTO competitor) { - sailingService.addOrUpdateCompetitor(competitor, new AsyncCallback() { - @Override - public void onFailure(Throwable caught) { - errorReporter.reportError("Error trying to update competitor: " + caught.getMessage()); - } - - @Override - public void onSuccess(CompetitorDTO updatedCompetitor) { - refreshCompetitorList(); - } - }); - } - - @Override - public void cancel() { - } - }, /* boat class to be used from CompetitorDTO */ null); - dialog.ensureDebugId("CompetitorEditDialog"); - dialog.show(); - } - + public void refreshCompetitorList() { competitorTable.refreshCompetitorList(leaderboardName); } diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/CompetitorTableWrapper.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/CompetitorTableWrapper.java index 8461846d12d..9008fa15aed 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/CompetitorTableWrapper.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/CompetitorTableWrapper.java @@ -1,9 +1,11 @@ package com.sap.sailing.gwt.ui.adminconsole; import java.util.ArrayList; +import java.util.Collections; import java.util.Comparator; import java.util.List; +import com.google.gwt.cell.client.FieldUpdater; import com.google.gwt.cell.client.SafeHtmlCell; import com.google.gwt.core.client.Callback; import com.google.gwt.resources.client.ImageResource; @@ -12,6 +14,7 @@ import com.google.gwt.safehtml.shared.SafeHtmlBuilder; import com.google.gwt.user.cellview.client.Column; import com.google.gwt.user.cellview.client.ColumnSortEvent.ListHandler; import com.google.gwt.user.cellview.client.TextColumn; +import com.google.gwt.user.client.Window; import com.google.gwt.user.client.rpc.AsyncCallback; import com.google.gwt.user.client.ui.ImageResourceRenderer; import com.google.gwt.user.client.ui.Label; @@ -21,10 +24,12 @@ import com.sap.sailing.gwt.ui.client.FlagImageResolver; import com.sap.sailing.gwt.ui.client.SailingServiceAsync; import com.sap.sailing.gwt.ui.client.StringMessages; import com.sap.sse.common.Color; +import com.sap.sse.common.Util; import com.sap.sse.common.util.NaturalComparator; import com.sap.sse.gwt.client.ErrorReporter; import com.sap.sse.gwt.client.celltable.EntityIdentityComparator; import com.sap.sse.gwt.client.celltable.RefreshableSelectionModel; +import com.sap.sse.gwt.client.dialog.DataEntryDialog.DialogCallback; import com.sap.sse.gwt.client.panels.LabeledAbstractFilterablePanel; public class CompetitorTableWrapper> extends TableWrapper { @@ -209,6 +214,22 @@ public class CompetitorTableWrapper competitorActionColumn = new ImagesBarColumn( + new CompetitorConfigImagesBarCell(stringMessages)); + competitorActionColumn.setFieldUpdater(new FieldUpdater() { + @Override + public void update(int index, final CompetitorDTO competitor, String value) { + if (CompetitorConfigImagesBarCell.ACTION_EDIT.equals(value)) { + openEditCompetitorDialog(competitor, competitor.getBoatClass().getName()); + } else if (CompetitorConfigImagesBarCell.ACTION_REFRESH.equals(value)) { + allowUpdate(Collections.singleton(competitor)); + } + } + + }); + mainPanel.insert(filterField, 0); table.addColumnSortHandler(competitorColumnListHandler); table.addColumn(sailIdColumn, stringMessages.sailNumber()); @@ -220,6 +241,7 @@ public class CompetitorTableWrapper, Throwable> callback) { - if(leaderboardName != null) { + if (leaderboardName != null) { sailingService.getCompetitorsOfLeaderboard(leaderboardName, new AsyncCallback>() { @Override public void onFailure(Throwable caught) { errorReporter.reportError("Remote Procedure Call getCompetitors() - Failure: " + caught.getMessage()); - if (callback != null) callback.onFailure(caught); + if (callback != null) { + callback.onFailure(caught); + } } @Override public void onSuccess(Iterable result) { refreshCompetitorList(result); - if (callback != null) callback.onSuccess(result); + if (callback != null) { + callback.onSuccess(result); + } } }); } else { @@ -263,14 +289,18 @@ public class CompetitorTableWrapper result) { getFilteredCompetitors(result); refreshCompetitorList(result); - if (callback != null) callback.onSuccess(result); + if (callback != null) { + callback.onSuccess(result); + } } }); } @@ -279,4 +309,56 @@ public class CompetitorTableWrapper result) { filterField.updateAll(result); } + + void openEditCompetitorDialog(final CompetitorDTO originalCompetitor, String boatClass) { + final CompetitorEditDialog dialog = new CompetitorEditDialog(stringMessages, originalCompetitor, new DialogCallback() { + @Override + public void ok(final CompetitorDTO competitor) { + sailingService.addOrUpdateCompetitor(competitor, new AsyncCallback() { + @Override + public void onFailure(Throwable caught) { + errorReporter.reportError("Error trying to update competitor: " + caught.getMessage()); + } + + @Override + public void onSuccess(CompetitorDTO updatedCompetitor) { + //only reload selected competitors reloading with refreshCompetitorList(leaderboardName) + //would not work in case the list is not based on a leaderboard e.g. AbstractCompetitorRegistrationDialog + int editedCompetitorIndex = getDataProvider().getList().indexOf(originalCompetitor); + getDataProvider().getList().remove(originalCompetitor); + if (editedCompetitorIndex >= 0){ + getDataProvider().getList().add(editedCompetitorIndex, updatedCompetitor); + } else { + //in case competitor was not present --> not edit, but create + getDataProvider().getList().add(updatedCompetitor); + } + getDataProvider().refresh(); + } + }); + } + + @Override + public void cancel() { + } + }, boatClass); + dialog.ensureDebugId("CompetitorEditDialog"); + dialog.show(); + } + + protected void allowUpdate(final Iterable competitors) { + List serializableSingletonList = new ArrayList(); + Util.addAll(competitors, serializableSingletonList); + sailingService.allowCompetitorResetToDefaults(serializableSingletonList, new AsyncCallback() { + @Override + public void onFailure(Throwable caught) { + errorReporter.reportError("Error trying to allow resetting competitors " + competitors + + " to defaults: " + caught.getMessage()); + } + + @Override + public void onSuccess(Void result) { + Window.alert(stringMessages.successfullyAllowedCompetitorReset(competitors.toString())); + } + }); + } } diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/CourseManagementWidget.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/CourseManagementWidget.java index 5c402d443b9..d63cbf39034 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/CourseManagementWidget.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/CourseManagementWidget.java @@ -74,6 +74,13 @@ public abstract class CourseManagementWidget implements IsWidget { marks = new MarkTableWrapper>( /* multiSelection */ true, sailingService, stringMessages, errorReporter); + marks.getSelectionModel().addSelectionChangeHandler(new SelectionChangeEvent.Handler() { + @Override + public void onSelectionChange(SelectionChangeEvent event) { + markSelectionChanged(); + } + }); + CaptionPanel waypointsPanel = new CaptionPanel(stringMessages.waypoints()); CaptionPanel controlPointsPanel = new CaptionPanel(stringMessages.twoMarkControlPoint()); CaptionPanel marksPanel = new CaptionPanel(stringMessages.mark()); @@ -156,6 +163,9 @@ public abstract class CourseManagementWidget implements IsWidget { controlPointsBtnsPanel.add(addControlPoint); } + protected void markSelectionChanged() { + } + private void removeWaypoint(WaypointDTO waypoint) { waypoints.getDataProvider().getList().remove(waypoint); } diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/DeviceMappingTableWrapper.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/DeviceMappingTableWrapper.java index 0cd91bd17bb..27de2c2800d 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/DeviceMappingTableWrapper.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/DeviceMappingTableWrapper.java @@ -17,7 +17,6 @@ import com.sap.sailing.gwt.ui.client.StringMessages; import com.sap.sailing.gwt.ui.common.client.DateAndTimeFormatterUtil; import com.sap.sailing.gwt.ui.shared.DeviceMappingDTO; import com.sap.sse.gwt.client.ErrorReporter; -import com.sap.sse.gwt.client.celltable.EntityIdentityComparator; import com.sap.sse.gwt.client.celltable.RefreshableSingleSelectionModel; public class DeviceMappingTableWrapper extends TableWrapper> { @@ -32,17 +31,9 @@ public class DeviceMappingTableWrapper extends TableWrapper() { - @Override - public boolean representSameEntity(DeviceMappingDTO dto1, DeviceMappingDTO dto2) { - return dto1.deviceIdentifier.deviceId.equals(dto2.deviceIdentifier.deviceId) && - dto1.mappedTo.getIdAsString().equals(dto2.mappedTo.getIdAsString()); - } - @Override - public int hashCode(DeviceMappingDTO t) { - return t.deviceIdentifier.deviceId.concat(t.mappedTo.getIdAsString()).hashCode(); - } - }); + /* leaving EntityIdentityComparator null, reducing comparison to equals/hashCode which is well + * defined on DeviceMappingDTO + */ null); showPingMappingsCb = new CheckBox(stringMessages.showPingMarkMappings()); showPingMappingsCb.addValueChangeHandler(new ValueChangeHandler() { @Override diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/RaceLogAddDeviceMappingDialog.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/RaceLogAddDeviceMappingDialog.java deleted file mode 100644 index 44dc0cee952..00000000000 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/RaceLogAddDeviceMappingDialog.java +++ /dev/null @@ -1,73 +0,0 @@ -package com.sap.sailing.gwt.ui.adminconsole; - -import com.sap.sailing.domain.common.racelog.tracking.DeviceMappingConstants; -import com.sap.sailing.domain.common.racelog.tracking.QRCodeURLCreationException; -import com.sap.sailing.gwt.ui.client.GwtUrlHelper; -import com.sap.sailing.gwt.ui.client.SailingServiceAsync; -import com.sap.sailing.gwt.ui.client.StringMessages; -import com.sap.sailing.gwt.ui.shared.DeviceIdentifierDTO; -import com.sap.sailing.gwt.ui.shared.DeviceMappingDTO; -import com.sap.sse.gwt.client.ErrorReporter; - -public class RaceLogAddDeviceMappingDialog extends AbstractLogAddDeviceMappingDialog{ - private final String leaderboardName; - private final String fleetName; - private final String raceColumnName; - - public RaceLogAddDeviceMappingDialog(SailingServiceAsync sailingService, final ErrorReporter errorReporter, - final StringMessages stringMessages, final String leaderboardName, final String raceColumnName, - final String fleetName, DialogCallback callback, final DeviceMappingDTO mapping) { - super(sailingService, errorReporter, stringMessages, callback, mapping); - this.leaderboardName = leaderboardName; - this.fleetName = fleetName; - this.raceColumnName = raceColumnName; - - loadCompetitorsAndMarks(); - } - - @Override - protected DeviceMappingDTO getResult() { - String deviceTypeS = deviceType.getSelectedIndex() < 0 ? null : deviceType.getValue(deviceType - .getSelectedIndex()); - DeviceIdentifierDTO deviceIdentifier = new DeviceIdentifierDTO(deviceTypeS, deviceId.getValue()); - return new DeviceMappingDTO(deviceIdentifier, from.getValue(), to.getValue(), selectedItem, null); - } - - @Override - protected DeviceMappingQRCodeWidget setupQRCodeWidget() { - return new DeviceMappingQRCodeWidget(stringMessages, new DeviceMappingQRCodeWidget.URLFactory() { - @SuppressWarnings("deprecation") - @Override - public String createURL(String baseUrlWithoutTrailingSlash, String mappedItemType, String mappedItemId) - throws QRCodeURLCreationException { - if (from.getValue() == null && to.getValue() == null) { - throw new QRCodeURLCreationException(stringMessages.atMostOneEndOfTheTimeRangeMayBeOpen()); - } - - Long fromMillis = null; - if (from.getValue() != null){ - fromMillis = from.getValue().getTime(); - } - - Long toMillis = null; - if (to.getValue() != null) { - toMillis = to.getValue().getTime(); - } - - return DeviceMappingConstants.getDeviceMappingForRaceLogUrl(baseUrlWithoutTrailingSlash, - leaderboardName, raceColumnName, fleetName, mappedItemType, mappedItemId, fromMillis, toMillis, - GwtUrlHelper.INSTANCE); - } - }); - } - - @Override - protected void loadCompetitorsAndMarks() { - sailingService.getCompetitorRegistrationsFromLogHierarchy(leaderboardName, - itemSelectionPanel.getSetCompetitorsCallback()); - - sailingService.getMarksInRaceLog(leaderboardName, raceColumnName, fleetName, - itemSelectionPanel.getSetMarksCallback()); - } - -} \ No newline at end of file diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/RaceLogCompetitorRegistrationDialog.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/RaceLogCompetitorRegistrationDialog.java index 2f4ef0be68e..2f2055151d9 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/RaceLogCompetitorRegistrationDialog.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/RaceLogCompetitorRegistrationDialog.java @@ -1,35 +1,123 @@ package com.sap.sailing.gwt.ui.adminconsole; import java.util.Collection; +import java.util.Collections; import java.util.Set; +import com.google.gwt.event.dom.client.ClickEvent; +import com.google.gwt.event.dom.client.ClickHandler; import com.google.gwt.user.client.rpc.AsyncCallback; +import com.google.gwt.user.client.ui.CheckBox; +import com.google.gwt.user.client.ui.FlowPanel; import com.sap.sailing.domain.common.dto.CompetitorDTO; import com.sap.sailing.gwt.ui.client.SailingServiceAsync; import com.sap.sailing.gwt.ui.client.StringMessages; import com.sap.sse.gwt.client.ErrorReporter; +import com.sap.sse.gwt.client.dialog.DataEntryDialog; public class RaceLogCompetitorRegistrationDialog extends AbstractCompetitorRegistrationsDialog { - private String leaderboardName; private String fleetName; private String raceColumnName; + private CheckBox competitorRegistrationInRaceLogCheckBox; + + private static class Validator implements com.sap.sse.gwt.client.dialog.DataEntryDialog.Validator> { + private CheckBox competitorRegistrationInRaceLogCheckBox; + private final StringMessages stringMessages; + + public Validator(StringMessages stringMessages) { + this.stringMessages = stringMessages; + } - public RaceLogCompetitorRegistrationDialog(String boatClass, SailingServiceAsync sailingService, StringMessages stringMessages, - ErrorReporter errorReporter, boolean editable, String leaderboardName, String raceColumnName, String fleetName, + @Override + public String getErrorMessage(Set valueToValidate) { + final String result; + if (getCompetitorRegistrationInRaceLogCheckBox() != null && !getCompetitorRegistrationInRaceLogCheckBox().getValue()) { + result = stringMessages.competitorRegistrationsOnRaceDisabled(); + } else { + result = null; + } + return result; + } + + public CheckBox getCompetitorRegistrationInRaceLogCheckBox() { + return competitorRegistrationInRaceLogCheckBox; + } + + public void setCompetitorRegistrationInRaceLogCheckBox(CheckBox competitorRegistrationInRaceLogCheckBox) { + this.competitorRegistrationInRaceLogCheckBox = competitorRegistrationInRaceLogCheckBox; + } + } + + public RaceLogCompetitorRegistrationDialog(String boatClass, SailingServiceAsync sailingService, + StringMessages stringMessages, ErrorReporter errorReporter, boolean editable, String leaderboardName, + String raceColumnName, String fleetName, com.sap.sse.gwt.client.dialog.DataEntryDialog.DialogCallback> callback) { - super(sailingService, stringMessages, errorReporter, editable, callback, leaderboardName, boatClass); + this(sailingService, stringMessages, errorReporter, editable, callback, leaderboardName, boatClass, + raceColumnName, fleetName, new Validator(stringMessages)); + } + + public RaceLogCompetitorRegistrationDialog(SailingServiceAsync sailingService, StringMessages stringMessages, + ErrorReporter errorReporter, boolean editable, + com.sap.sse.gwt.client.dialog.DataEntryDialog.DialogCallback> callback, + String leaderboardName, String boatClass, String raceColumnName, String fleetName, Validator validator) { + super(sailingService, stringMessages, errorReporter, editable, callback, leaderboardName, boatClass, validator); this.raceColumnName = raceColumnName; this.fleetName = fleetName; + competitorRegistrationInRaceLogCheckBox = new CheckBox(stringMessages.registerCompetitorsOnRace()); + validator.setCompetitorRegistrationInRaceLogCheckBox(competitorRegistrationInRaceLogCheckBox); + setupCompetitorRegistationsOnRaceCheckbox(); } @Override protected void setRegisteredCompetitors() { - sailingService.getCompetitorRegistrationsOnRaceLog(leaderboardName, raceColumnName, fleetName, - new AsyncCallback>() { + if (showOnlyCompetitorsOfLog()) { + sailingService.getCompetitorRegistrationsInRaceLog(leaderboardName, raceColumnName, fleetName, + new AsyncCallback>() { + @Override + public void onSuccess(Collection registeredCompetitors) { + move(allCompetitorsTable, registeredCompetitorsTable, registeredCompetitors); + } + + @Override + public void onFailure(Throwable reason) { + errorReporter.reportError("Could not load already registered competitors: " + + reason.getMessage()); + } + }); + } else { + sailingService.getCompetitorRegistrationsForRace(leaderboardName, raceColumnName, fleetName, + new AsyncCallback>() { + @Override + public void onSuccess(Collection registeredCompetitors) { + move(allCompetitorsTable, registeredCompetitorsTable, registeredCompetitors); + } + + @Override + public void onFailure(Throwable reason) { + errorReporter.reportError("Could not load already registered competitors: " + + reason.getMessage()); + } + }); + } + } + + @Override + public void addAdditionalWidgets(FlowPanel mainPanel) { + mainPanel.add(competitorRegistrationInRaceLogCheckBox); + } + + private void setupCompetitorRegistationsOnRaceCheckbox() { + sailingService.areCompetitorRegistrationsEnabledForRace(leaderboardName, raceColumnName, fleetName, + new AsyncCallback() { @Override - public void onSuccess(Collection registeredCompetitors) { - move(allCompetitorsTable, registeredCompetitorsTable, registeredCompetitors); + public void onSuccess(Boolean isEnabled) { + competitorRegistrationInRaceLogCheckBox.setValue(isEnabled); + if (isEnabled) { + activateRegistrationButtons(); + } else { + deactivateRegistrationButtons(stringMessages.competitorRegistrationsOnRaceDisabled()); + } } @Override @@ -38,6 +126,81 @@ public class RaceLogCompetitorRegistrationDialog extends AbstractCompetitorRegis + reason.getMessage()); } }); + competitorRegistrationInRaceLogCheckBox.addClickHandler(new ClickHandler() { + @Override + public void onClick(ClickEvent event) { + final String title; + final String message; + if (competitorRegistrationInRaceLogCheckBox.getValue()) { + title = stringMessages.doYouWantToRegisterCompetitorsDirectlyOnTheRace(); + message = stringMessages.warningDirectCompetitorRegistration(); + } else { + title = stringMessages.doYouWantToDisableCompetitorsRegistrationsOnTheRace(); + message = stringMessages.warningRegattaCompetitorRegistration(); + } + new DataEntryDialog(title, message, stringMessages.ok(), stringMessages.cancel(), null, false, + new DialogCallback() { + @Override + public void ok(Void editedObject) { + if (competitorRegistrationInRaceLogCheckBox.getValue()) { + sailingService.enableCompetitorRegistrationsForRace(leaderboardName, + raceColumnName, fleetName, new AsyncCallback() { + @Override + public void onSuccess(Void isEnabled) { + competitorRegistrationInRaceLogCheckBox.setValue(true); + activateRegistrationButtons(); + refreshCompetitors(); + } + + @Override + public void onFailure(Throwable reason) { + errorReporter + .reportError("Could not enable competitor registrations for race: " + + reason.getMessage()); + } + }); + + } else { + sailingService.disableCompetitorRegistrationsForRace(leaderboardName, + raceColumnName, fleetName, new AsyncCallback() { + @Override + public void onSuccess(Void isEnabled) { + competitorRegistrationInRaceLogCheckBox.setValue(false); + deactivateRegistrationButtons(stringMessages + .competitorRegistrationsOnRaceDisabled()); + refreshCompetitors(); + } + + @Override + public void onFailure(Throwable reason) { + errorReporter + .reportError("Could not deactivate competitor registrations for race: " + + reason.getMessage()); + } + }); + } + } + + @Override + public void cancel() { + competitorRegistrationInRaceLogCheckBox.setValue(!competitorRegistrationInRaceLogCheckBox.getValue()); + } + }) { + @Override + protected Void getResult() { + return null; + } + }.show(); + } + }); } + @Override + protected Set getResult() { + if (competitorRegistrationInRaceLogCheckBox.getValue()) { + return super.getResult(); + } else { + return Collections.emptySet(); + } + } } diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/RaceLogCourseManagementWidget.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/RaceLogCourseManagementWidget.java index d46c306e936..906ce52d397 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/RaceLogCourseManagementWidget.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/RaceLogCourseManagementWidget.java @@ -12,6 +12,7 @@ import com.sap.sailing.gwt.ui.client.SailingServiceAsync; import com.sap.sailing.gwt.ui.client.StringMessages; import com.sap.sailing.gwt.ui.shared.MarkDTO; import com.sap.sailing.gwt.ui.shared.RaceCourseDTO; +import com.sap.sse.common.Util.Pair; import com.sap.sse.gwt.client.ErrorReporter; import com.sap.sse.gwt.client.dialog.DataEntryDialog; @@ -19,6 +20,7 @@ public class RaceLogCourseManagementWidget extends CourseManagementWidget { protected final String leaderboardName; protected final String raceColumnName; protected final String fleetName; + private Button removeMark; public RaceLogCourseManagementWidget(final SailingServiceAsync sailingService, final ErrorReporter errorReporter, final StringMessages stringMessages, final String leaderboardName, final String raceColumnName, @@ -29,7 +31,7 @@ public class RaceLogCourseManagementWidget extends CourseManagementWidget { this.raceColumnName = raceColumnName; this.fleetName = fleetName; - Button addMark = new Button(stringMessages.add(stringMessages.mark())); + Button addMark = new Button(stringMessages.addMarkToRegatta()); addMark.addClickHandler(new ClickHandler() { @Override public void onClick(ClickEvent event) { @@ -37,18 +39,17 @@ public class RaceLogCourseManagementWidget extends CourseManagementWidget { new DataEntryDialog.DialogCallback() { @Override public void ok(MarkDTO mark) { - sailingService.addMarkToRaceLog(leaderboardName, raceColumnName, fleetName, mark, - new AsyncCallback() { - @Override - public void onSuccess(Void result) { - refresh(); - } + sailingService.addMarkToRegattaLog(leaderboardName, mark, new AsyncCallback() { + @Override + public void onSuccess(Void result) { + refresh(); + } - @Override - public void onFailure(Throwable caught) { - errorReporter.reportError("Could not add mark: " + caught.getMessage()); - } - }); + @Override + public void onFailure(Throwable caught) { + errorReporter.reportError("Could not add mark: " + caught.getMessage()); + } + }); } @Override @@ -59,15 +60,15 @@ public class RaceLogCourseManagementWidget extends CourseManagementWidget { }); marksBtnsPanel.add(addMark); - Button removeMark = new Button(stringMessages.remove(stringMessages.mark())); + removeMark = new Button(stringMessages.remove(stringMessages.mark())); removeMark.addClickHandler(new ClickHandler() { @Override public void onClick(ClickEvent event) { Set marksToRemove = marks.getSelectionModel().getSelectedSet(); - for (MarkDTO markToRemove : marksToRemove) { - sailingService.revokeMarkDefinitionEventInRaceLog(leaderboardName, raceColumnName, fleetName, - markToRemove, new AsyncCallback() { + for (final MarkDTO markToRemove : marksToRemove) { + sailingService.revokeMarkDefinitionEventInRegattaLog(leaderboardName, markToRemove, + new AsyncCallback() { @Override public void onSuccess(Void result) { @@ -76,11 +77,14 @@ public class RaceLogCourseManagementWidget extends CourseManagementWidget { @Override public void onFailure(Throwable caught) { + errorReporter.reportError("Removing mark failed: "+caught.getMessage()); } }); } } }); + + removeMark.setEnabled(false); marksBtnsPanel.add(removeMark); ImagesBarColumn actionColumn = new ImagesBarColumn( @@ -93,8 +97,8 @@ public class RaceLogCourseManagementWidget extends CourseManagementWidget { new DataEntryDialog.DialogCallback() { @Override public void ok(Position position) { - sailingService.pingMarkViaRaceLogTracking(leaderboardName, raceColumnName, - fleetName, markDTO, position, new AsyncCallback() { + sailingService.pingMark(leaderboardName, markDTO, position, + new AsyncCallback() { @Override public void onSuccess(Void result) { @@ -118,6 +122,29 @@ public class RaceLogCourseManagementWidget extends CourseManagementWidget { }); marks.getTable().addColumn(actionColumn); } + + @Override + protected void markSelectionChanged() { + Set marksToRemove = marks.getSelectionModel().getSelectedSet(); + sailingService.checkIfMarksAreUsedInOtherRaceLogs(leaderboardName, raceColumnName, fleetName, marksToRemove, + new AsyncCallback>() { + @Override + public void onSuccess(Pair result) { + if (result.getA()) { + removeMark.setEnabled(false); + removeMark.setTitle(stringMessages.removalOfMarkDisabledMayBeUsedInRaces(result.getB())); + } else { + removeMark.setEnabled(true); + removeMark.setTitle(""); + } + } + + @Override + public void onFailure(Throwable caught) { + errorReporter.reportError("Could not load course: " + caught.getMessage()); + } + }); + } @Override public void refresh() { @@ -134,19 +161,16 @@ public class RaceLogCourseManagementWidget extends CourseManagementWidget { } }); - sailingService.getMarksInRaceLog(leaderboardName, raceColumnName, fleetName, - new AsyncCallback>() { - @Override - public void onSuccess(Iterable result) { - marks.refresh(result); - } + sailingService.getMarksInRegattaLog(leaderboardName, new AsyncCallback>() { + @Override + public void onSuccess(Iterable result) { + marks.refresh(result); + } - @Override - public void onFailure(Throwable caught) { - errorReporter.reportError( - stringMessages.errorTryingToObtainTheMarksOfTheRace( - caught.getMessage())); - } - }); + @Override + public void onFailure(Throwable caught) { + errorReporter.reportError("Could not load marks: " + caught.getMessage()); + } + }); } } \ No newline at end of file diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/RaceLogImportFixesAndAddMappingsDialog.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/RaceLogImportFixesAndAddMappingsDialog.java deleted file mode 100644 index 45076f8b76f..00000000000 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/RaceLogImportFixesAndAddMappingsDialog.java +++ /dev/null @@ -1,62 +0,0 @@ -package com.sap.sailing.gwt.ui.adminconsole; - -import java.util.Collection; - -import com.google.gwt.user.client.rpc.AsyncCallback; -import com.sap.sailing.domain.common.dto.CompetitorDTO; -import com.sap.sailing.gwt.ui.client.SailingServiceAsync; -import com.sap.sailing.gwt.ui.client.StringMessages; -import com.sap.sailing.gwt.ui.shared.DeviceMappingDTO; -import com.sap.sailing.gwt.ui.shared.MarkDTO; -import com.sap.sse.gwt.client.ErrorReporter; - -public class RaceLogImportFixesAndAddMappingsDialog extends AbstractLogImportFixesAndAddMappingsDialog { - private String leaderboardName; - private String raceColumnName; - private String fleetName; - - - public RaceLogImportFixesAndAddMappingsDialog(SailingServiceAsync sailingService, final ErrorReporter errorReporter, - final StringMessages stringMessages, String leaderboardName, String raceColumnName, String fleetName, - DialogCallback> callback) { - super(sailingService,errorReporter, stringMessages, callback); - - this.leaderboardName = leaderboardName; - this.raceColumnName = raceColumnName; - this.fleetName = fleetName; - - getCompetitorRegistrations(sailingService, errorReporter); - getMarks(sailingService, errorReporter); - } - - @Override - void getMarks(SailingServiceAsync sailingService, final ErrorReporter errorReporter) { - sailingService.getMarksInRaceLog(leaderboardName, raceColumnName, fleetName, new AsyncCallback>() { - @Override - public void onSuccess(Iterable result) { - markTable.refresh(result); - } - - @Override - public void onFailure(Throwable caught) { - errorReporter.reportError("Could not load marks: " + caught.getMessage()); - } - }); - } - - @Override - void getCompetitorRegistrations(SailingServiceAsync sailingService, final ErrorReporter errorReporter) { - sailingService.getCompetitorRegistrationsFromLogHierarchy(leaderboardName, new AsyncCallback>() { - @Override - public void onSuccess(Collection result) { - competitorTable.refreshCompetitorList(result); - } - - @Override - public void onFailure(Throwable caught) { - errorReporter.reportError("Could not load competitors: " + caught.getMessage()); - } - }); - } - -} diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/RaceLogTrackingDeviceMappingsDialog.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/RaceLogTrackingDeviceMappingsDialog.java deleted file mode 100644 index a9fb9d3246b..00000000000 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/RaceLogTrackingDeviceMappingsDialog.java +++ /dev/null @@ -1,163 +0,0 @@ -package com.sap.sailing.gwt.ui.adminconsole; - -import java.util.Collection; -import java.util.List; - -import com.google.gwt.cell.client.FieldUpdater; -import com.google.gwt.user.client.rpc.AsyncCallback; -import com.sap.sailing.gwt.ui.client.SailingServiceAsync; -import com.sap.sailing.gwt.ui.client.StringMessages; -import com.sap.sailing.gwt.ui.shared.DeviceMappingDTO; -import com.sap.sse.gwt.client.ErrorReporter; -import com.sap.sse.gwt.client.dialog.DataEntryDialog; - -public class RaceLogTrackingDeviceMappingsDialog extends AbstractLogTrackingDeviceMappingsDialog { - protected String leaderboardName; - protected String raceColumnName; - protected String fleetName; - - public RaceLogTrackingDeviceMappingsDialog(final SailingServiceAsync sailingService, - final StringMessages stringMessages, final ErrorReporter errorReporter, final String leaderboardName, - final String raceColumnName, final String fleetName, DialogCallback callback) { - - super(sailingService, stringMessages, errorReporter, callback); - - this.leaderboardName = leaderboardName; - this.raceColumnName = raceColumnName; - this.fleetName = fleetName; - - refresh(); - } - - @Override - protected void refresh() { - sailingService.getDeviceMappingsFromLogHierarchy(leaderboardName, raceColumnName, fleetName, - new AsyncCallback>() { - @Override - public void onSuccess(List result) { - mappings = result; - - updateChart(); - deviceMappingTable.refresh(mappings); - } - - @Override - public void onFailure(Throwable caught) { - errorReporter.reportError("Could not load mappings for marks: " + caught.getMessage()); - } - }); - } - - @Override - protected void showAddMappingDialog(DeviceMappingDTO mapping) { - new RaceLogAddDeviceMappingDialog(sailingService, errorReporter, stringMessages, leaderboardName, - raceColumnName, fleetName, new DataEntryDialog.DialogCallback() { - @Override - public void ok(final DeviceMappingDTO mapping) { - sailingService.addDeviceMappingToRaceLog(leaderboardName, raceColumnName, fleetName, mapping, - new AsyncCallback() { - @Override - public void onSuccess(Void result) { - refresh(); - } - - @Override - public void onFailure(Throwable caught) { - showAddMappingDialog(mapping); - errorReporter.reportError("Could not add mapping: " + caught.getMessage()); - } - }); - } - - @Override - public void cancel() { - refresh(); - } - }, mapping).show(); - } - - @Override - protected void importFixes() { - new RaceLogImportFixesAndAddMappingsDialog(sailingService, errorReporter, stringMessages, leaderboardName, - raceColumnName, fleetName, new DataEntryDialog.DialogCallback>() { - - @Override - public void ok(Collection editedObject) { - for (DeviceMappingDTO mapping : editedObject) { - sailingService.addDeviceMappingToRaceLog(leaderboardName, raceColumnName, fleetName, - mapping, new AsyncCallback() { - @Override - public void onSuccess(Void result) { - refresh(); - } - - @Override - public void onFailure(Throwable caught) { - errorReporter.reportError(caught.getMessage()); - } - }); - } - } - - @Override - public void cancel() { - } - }).show(); - } - - @Override - protected FieldUpdater getActionColFieldUpdater() { - - return new FieldUpdater() { - - @Override - public void update(int index, final DeviceMappingDTO dto, String value) { - if (RaceLogTrackingDeviceMappingsImagesBarCell.ACTION_CLOSE.equals(value)) { - new SetTimePointDialog(stringMessages, stringMessages.setClosingTimePoint(), - new DataEntryDialog.DialogCallback() { - @Override - public void ok(java.util.Date editedObject) { - sailingService.closeOpenEndedDeviceMapping(leaderboardName, raceColumnName, - fleetName, dto, editedObject, new AsyncCallback() { - @Override - public void onSuccess(Void result) { - refresh(); - } - - @Override - public void onFailure(Throwable caught) { - errorReporter.reportError("Could not close open ended mapping: " - + caught.getMessage()); - } - }); - } - - @Override - public void cancel() { - } - }).show(); - } else if (RaceLogTrackingDeviceMappingsImagesBarCell.ACTION_REMOVE.equals(value)) { - sailingService.revokeRaceAndRegattaLogEvents(leaderboardName, raceColumnName, fleetName, - dto.originalRaceLogEventIds, new AsyncCallback() { - @Override - public void onFailure(Throwable caught) { - errorReporter.reportError("Could not remove mappings: " + caught.getMessage()); - } - - @Override - public void onSuccess(Void result) { - refresh(); - } - - }); - } - - } - }; - } - - @Override - protected Void getResult() { - return null; - } -} \ No newline at end of file diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/RaceLogTrackingEventManagementRaceImagesBarCell.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/RaceLogTrackingEventManagementRaceImagesBarCell.java index 9a2f6d69373..8e5a28b8b71 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/RaceLogTrackingEventManagementRaceImagesBarCell.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/RaceLogTrackingEventManagementRaceImagesBarCell.java @@ -13,7 +13,6 @@ public class RaceLogTrackingEventManagementRaceImagesBarCell extends ImagesBarCe public final static String ACTION_REMOVE_DENOTATION = "ACTION_REMOVE_DENOTATION"; public final static String ACTION_COMPETITOR_REGISTRATIONS = "ACTION_COMPETITOR_REGISTRATIONS"; public final static String ACTION_DEFINE_COURSE = "ACTION_DEFINE_COURSE"; - public final static String ACTION_MAP_DEVICES = "ACTION_MAP_DEVICES"; public final static String ACTION_COPY = "ACTION_COPY"; public final static String ACTION_EDIT = "ACTION_EDIT"; public final static String ACTION_REFRESH_RACELOG = "ACTION_REFRESH_RACE_LOG"; @@ -40,7 +39,6 @@ public class RaceLogTrackingEventManagementRaceImagesBarCell extends ImagesBarCe result.add(new ImageSpec(ACTION_REMOVE_DENOTATION, stringMessages.removeDenotation(), makeImagePrototype(resources.unDenoteForRaceLogTracking()))); result.add(new ImageSpec(ACTION_COMPETITOR_REGISTRATIONS, stringMessages.competitorRegistrations(), makeImagePrototype(resources.competitorRegistrations()))); result.add(new ImageSpec(ACTION_DEFINE_COURSE, stringMessages.defineCourse(), makeImagePrototype(resources.defineCourse()))); - result.add(new ImageSpec(ACTION_MAP_DEVICES, stringMessages.mapDevices(), makeImagePrototype(resources.mapDevices()))); result.add(new ImageSpec(ACTION_COPY, stringMessages.copyCourseAndCompetitors(), makeImagePrototype(resources.copy()))); } result.add(new ImageSpec(ACTION_EDIT, stringMessages.actionEdit(), makeImagePrototype(resources.editIcon()))); diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/RegattaLogAddDeviceMappingDialog.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/RegattaLogAddDeviceMappingDialog.java index 141d8d96dc8..9336bd5cef2 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/RegattaLogAddDeviceMappingDialog.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/RegattaLogAddDeviceMappingDialog.java @@ -1,31 +1,149 @@ package com.sap.sailing.gwt.ui.adminconsole; import java.util.Collection; +import java.util.Date; +import java.util.List; +import com.github.gwtbootstrap.datetimepicker.client.ui.base.HasViewMode.ViewMode; import com.google.gwt.event.dom.client.ChangeEvent; import com.google.gwt.event.dom.client.ChangeHandler; +import com.google.gwt.event.logical.shared.AttachEvent; +import com.google.gwt.event.logical.shared.AttachEvent.Handler; +import com.google.gwt.event.logical.shared.ValueChangeEvent; +import com.google.gwt.event.logical.shared.ValueChangeHandler; import com.google.gwt.user.client.rpc.AsyncCallback; +import com.google.gwt.user.client.ui.CaptionPanel; +import com.google.gwt.user.client.ui.Grid; +import com.google.gwt.user.client.ui.HorizontalPanel; import com.google.gwt.user.client.ui.Label; +import com.google.gwt.user.client.ui.ListBox; +import com.google.gwt.user.client.ui.TextBox; +import com.google.gwt.user.client.ui.VerticalPanel; import com.google.gwt.user.client.ui.Widget; +import com.sap.sailing.domain.common.dto.CompetitorDTO; import com.sap.sailing.domain.common.racelog.tracking.DeviceMappingConstants; +import com.sap.sailing.domain.common.racelog.tracking.MappableToDevice; import com.sap.sailing.domain.common.racelog.tracking.QRCodeURLCreationException; +import com.sap.sailing.gwt.ui.adminconsole.ItemToMapToDeviceSelectionPanel.SelectionChangedHandler; import com.sap.sailing.gwt.ui.client.GwtUrlHelper; import com.sap.sailing.gwt.ui.client.SailingServiceAsync; import com.sap.sailing.gwt.ui.client.StringMessages; +import com.sap.sailing.gwt.ui.shared.BetterDateTimeBox; import com.sap.sailing.gwt.ui.shared.DeviceIdentifierDTO; import com.sap.sailing.gwt.ui.shared.DeviceMappingDTO; import com.sap.sailing.gwt.ui.shared.EventDTO; +import com.sap.sailing.gwt.ui.shared.MarkDTO; import com.sap.sse.gwt.client.ErrorReporter; import com.sap.sse.gwt.client.controls.GenericListBox; import com.sap.sse.gwt.client.controls.GenericListBox.ValueBuilder; +import com.sap.sse.gwt.client.dialog.DataEntryDialog; -public class RegattaLogAddDeviceMappingDialog extends AbstractLogAddDeviceMappingDialog { +public class RegattaLogAddDeviceMappingDialog extends DataEntryDialog { private final String leaderboardName; private final GenericListBox events; + protected final BetterDateTimeBox from; + protected final BetterDateTimeBox to; + protected final ListBox deviceType; + protected final TextBox deviceId; + protected final DeviceMappingQRCodeWidget qrWidget; + protected final StringMessages stringMessages; + protected MappableToDevice selectedItem; + protected final ItemToMapToDeviceSelectionPanel itemSelectionPanel; + protected final SailingServiceAsync sailingService; + protected Grid entryGrid; + public RegattaLogAddDeviceMappingDialog(SailingServiceAsync sailingService, final ErrorReporter errorReporter, - final StringMessages stringMessages, final String leaderboardName, DialogCallback callback, final DeviceMappingDTO mapping) { - super(sailingService, errorReporter, stringMessages, callback, mapping); + final StringMessages stringMessages, String leaderboardName, DialogCallback callback, + final DeviceMappingDTO mapping) { + super(stringMessages.add(stringMessages.deviceMappings()), stringMessages.add(stringMessages.deviceMappings()), + stringMessages.add(), stringMessages.cancel(), new DataEntryDialog.Validator() { + @Override + public String getErrorMessage(DeviceMappingDTO valueToValidate) { + String deviceType = valueToValidate.deviceIdentifier.deviceType; + String deviceId = valueToValidate.deviceIdentifier.deviceId; + if (deviceType == null || deviceType.isEmpty()) { + return stringMessages.pleaseEnterA(stringMessages.deviceType()); + } + if (deviceId == null || deviceId.isEmpty()) { + return stringMessages.pleaseEnterA(stringMessages.deviceId()); + } + if ((valueToValidate.from == null || valueToValidate.from.compareTo(new Date(Long.MIN_VALUE)) == 0) + && (valueToValidate.to == null || valueToValidate.to + .compareTo(new Date(Long.MAX_VALUE)) == 0)) { + return stringMessages.atMostOneEndOfTheTimeRangeMayBeOpen(); + } + if (valueToValidate.from != null && valueToValidate.to != null + && valueToValidate.to.before(valueToValidate.from)) { + return stringMessages.startOfTimeRangeMustLieBeforeEnd(); + } + + if (valueToValidate.mappedTo == null) { + return stringMessages.pleaseSelectAnItemToMapTo(); + } + return null; + } + }, true, callback); + + this.stringMessages = stringMessages; + this.sailingService = sailingService; + + from = initTimeBox(); + from.setValue(null); + to = initTimeBox(); + to.setValue(null); + + deviceType = createListBox(false); + sailingService.getDeserializableDeviceIdentifierTypes(new AsyncCallback>() { + @Override + public void onSuccess(List result) { + String typeToPreselect = mapping != null ? mapping.deviceIdentifier.deviceType : null; + int i = 0; + for (String type : result) { + deviceType.addItem(type); + if (type.equals(typeToPreselect)) { + deviceType.setSelectedIndex(i); + } + i++; + } + } + + @Override + public void onFailure(Throwable caught) { + errorReporter.reportError("Could not load deserializable device identifier types: " + + caught.getMessage()); + } + }); + + deviceId = createTextBox(""); + + itemSelectionPanel = new ItemToMapToDeviceSelectionPanel(sailingService, stringMessages, errorReporter, + new SelectionChangedHandler() { + @Override + public void onSelectionChange(MarkDTO mark) { + selectedItem = mark; + qrWidget.setMappedItem(DeviceMappingConstants.URL_MARK_ID_AS_STRING, mark.getIdAsString()); + validate(); + } + + @Override + public void onSelectionChange(CompetitorDTO competitor) { + selectedItem = competitor; + qrWidget.setMappedItem(DeviceMappingConstants.URL_COMPETITOR_ID_AS_STRING, + competitor.getIdAsString()); + validate(); + } + }, mapping != null ? mapping.mappedTo : null); + + if (mapping != null) { + deviceId.setValue(mapping.deviceIdentifier.deviceId); + from.setValue(mapping.from); + to.setValue(mapping.to); + } + + qrWidget = setupQRCodeWidget(); + qrWidget.generateQRCode(); + this.leaderboardName = leaderboardName; loadCompetitorsAndMarks(); @@ -56,20 +174,73 @@ public class RegattaLogAddDeviceMappingDialog extends AbstractLogAddDeviceMappin } }); } - + @Override protected Widget getAdditionalWidget() { - Widget panel = super.getAdditionalWidget(); - + HorizontalPanel panel = new HorizontalPanel(); + VerticalPanel leftSidePanel = new VerticalPanel(); + entryGrid = new Grid(4, 2); + CaptionPanel entryPanel = new CaptionPanel(stringMessages.mappingDetails()); + CaptionPanel qrPanel = new CaptionPanel(stringMessages.qrCode()); + entryGrid.setWidget(0, 0, new Label(stringMessages.deviceType())); + entryGrid.setWidget(0, 1, deviceType); + entryGrid.setWidget(1, 0, new Label(stringMessages.deviceId())); + entryGrid.setWidget(1, 1, deviceId); + entryGrid.setWidget(2, 0, new Label(stringMessages.from())); + entryGrid.setWidget(2, 1, from); + entryGrid.setWidget(3, 0, new Label(stringMessages.to())); + entryGrid.setWidget(3, 1, to); + VerticalPanel qrContentPanel = new VerticalPanel(); + Label explanation = new Label(stringMessages.deviceMappingQrCodeExplanation()); + explanation.setWidth("400px"); + qrContentPanel.add(explanation); + qrContentPanel.add(qrWidget); + panel.add(leftSidePanel); + panel.add(itemSelectionPanel); + leftSidePanel.add(entryPanel); + leftSidePanel.add(qrPanel); + entryPanel.setContentWidget(entryGrid); + qrPanel.setContentWidget(qrContentPanel); entryGrid.insertRow(0); entryGrid.setWidget(0, 0, new Label(stringMessages.event())); entryGrid.setWidget(0, 1, events); - return panel; } + private BetterDateTimeBox initTimeBox() { + final BetterDateTimeBox timeBox = new BetterDateTimeBox(); + timeBox.addValueChangeHandler(new ValueChangeHandler() { + @Override + public void onValueChange(ValueChangeEvent event) { + validate(); + } + }); + timeBox.addAttachHandler(new Handler() { + @Override + public void onAttachOrDetach(AttachEvent event) { + if (event.isAttached()) { + addAutoHidePartner(timeBox.getPicker()); + } + } + }); + timeBox.setAutoClose(true); + timeBox.setStartView(ViewMode.HOUR); + timeBox.setFormat("dd/mm/yyyy hh:ii"); + return timeBox; + } + @Override - protected DeviceMappingQRCodeWidget setupQRCodeWidget() { + protected boolean validate() { + if (super.validate()){ + qrWidget.generateQRCode(); + return true; + } else { + qrWidget.clear(); + return false; + } + } + + private DeviceMappingQRCodeWidget setupQRCodeWidget() { return new DeviceMappingQRCodeWidget(stringMessages, new DeviceMappingQRCodeWidget.URLFactory() { @Override public String createURL(String baseUrlWithoutTrailingSlash, String mappedItemType, String mappedItemId) @@ -92,12 +263,8 @@ public class RegattaLogAddDeviceMappingDialog extends AbstractLogAddDeviceMappin return new DeviceMappingDTO(deviceIdentifier, from.getValue(), to.getValue(), selectedItem, null); } - @Override - protected void loadCompetitorsAndMarks() { - sailingService.getCompetitorRegistrationsFromLogHierarchy(leaderboardName, itemSelectionPanel.getSetCompetitorsCallback()); - // fetching marks definitions from the race logs; note that currently there are no mark *definitions* - // on regatta logs although there can be mark/device assignments on a regatta log which then gives the - // mark a position that applies across all races in the regatta-like thing - sailingService.getMarksInRaceLogsAndTrackedRaces(leaderboardName, itemSelectionPanel.getSetMarksCallback()); + private void loadCompetitorsAndMarks() { + sailingService.getCompetitorRegistrationsInRegattaLog(leaderboardName, itemSelectionPanel.getSetCompetitorsCallback()); + sailingService.getMarksInRegattaLog(leaderboardName, itemSelectionPanel.getSetMarksCallback()); } } \ No newline at end of file diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/RegattaLogCompetitorRegistrationDialog.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/RegattaLogCompetitorRegistrationDialog.java index 73cb1f1e157..f7518529006 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/RegattaLogCompetitorRegistrationDialog.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/RegattaLogCompetitorRegistrationDialog.java @@ -4,6 +4,7 @@ import java.util.Collection; import java.util.Set; import com.google.gwt.user.client.rpc.AsyncCallback; +import com.google.gwt.user.client.ui.FlowPanel; import com.sap.sailing.domain.common.dto.CompetitorDTO; import com.sap.sailing.gwt.ui.client.SailingServiceAsync; import com.sap.sailing.gwt.ui.client.StringMessages; @@ -11,27 +12,47 @@ import com.sap.sse.gwt.client.ErrorReporter; public class RegattaLogCompetitorRegistrationDialog extends AbstractCompetitorRegistrationsDialog { - public RegattaLogCompetitorRegistrationDialog(String boatClass, SailingServiceAsync sailingService, StringMessages stringMessages, - ErrorReporter errorReporter, boolean editable, String leaderboardName, + public RegattaLogCompetitorRegistrationDialog(String boatClass, SailingServiceAsync sailingService, + StringMessages stringMessages, ErrorReporter errorReporter, boolean editable, String leaderboardName, com.sap.sse.gwt.client.dialog.DataEntryDialog.DialogCallback> callback) { - super(sailingService, stringMessages, errorReporter, editable, callback, leaderboardName, boatClass); + super(sailingService, stringMessages, errorReporter, editable, callback, leaderboardName, boatClass, /* validator */ null); } @Override protected void setRegisteredCompetitors() { - sailingService.getCompetitorRegistrationsInRegattaLog(leaderboardName, - new AsyncCallback>() { - @Override - public void onSuccess(Collection registeredCompetitors) { - move(allCompetitorsTable, registeredCompetitorsTable, registeredCompetitors); - } + if (showOnlyCompetitorsOfLog()) { + sailingService.getCompetitorRegistrationsInRegattaLog(leaderboardName, + new AsyncCallback>() { + @Override + public void onSuccess(Collection registeredCompetitors) { + move(allCompetitorsTable, registeredCompetitorsTable, registeredCompetitors); + } - @Override - public void onFailure(Throwable reason) { - errorReporter.reportError("Could not load already registered competitors: " - + reason.getMessage()); - } - }); + @Override + public void onFailure(Throwable reason) { + errorReporter.reportError("Could not load already registered competitors: " + + reason.getMessage()); + } + }); + + } else { + sailingService.getCompetitorRegistrationsForLeaderboard(leaderboardName, + new AsyncCallback>() { + @Override + public void onSuccess(Collection registeredCompetitors) { + move(allCompetitorsTable, registeredCompetitorsTable, registeredCompetitors); + } + + @Override + public void onFailure(Throwable reason) { + errorReporter.reportError("Could not load already registered competitors: " + + reason.getMessage()); + } + }); + } } + @Override + public void addAdditionalWidgets(FlowPanel mainPanel) { + } } diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/RegattaLogTrackingDeviceMappingsDialog.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/RegattaLogTrackingDeviceMappingsDialog.java index be18983bff0..7224931137e 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/RegattaLogTrackingDeviceMappingsDialog.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/RegattaLogTrackingDeviceMappingsDialog.java @@ -1,31 +1,219 @@ package com.sap.sailing.gwt.ui.adminconsole; +import java.util.ArrayList; import java.util.Collection; +import java.util.Date; import java.util.List; +import org.moxieapps.gwt.highcharts.client.Axis; +import org.moxieapps.gwt.highcharts.client.AxisTitle; +import org.moxieapps.gwt.highcharts.client.Chart; +import org.moxieapps.gwt.highcharts.client.Global; +import org.moxieapps.gwt.highcharts.client.Highcharts; +import org.moxieapps.gwt.highcharts.client.Legend; +import org.moxieapps.gwt.highcharts.client.Point; +import org.moxieapps.gwt.highcharts.client.Series; +import org.moxieapps.gwt.highcharts.client.ToolTip; +import org.moxieapps.gwt.highcharts.client.ToolTipData; +import org.moxieapps.gwt.highcharts.client.ToolTipFormatter; +import org.moxieapps.gwt.highcharts.client.events.PointMouseOverEvent; +import org.moxieapps.gwt.highcharts.client.events.PointMouseOverEventHandler; +import org.moxieapps.gwt.highcharts.client.plotOptions.SeriesPlotOptions; + import com.google.gwt.cell.client.FieldUpdater; +import com.google.gwt.event.dom.client.ClickEvent; +import com.google.gwt.event.dom.client.ClickHandler; +import com.google.gwt.json.client.JSONObject; import com.google.gwt.user.client.rpc.AsyncCallback; +import com.google.gwt.user.client.ui.Button; +import com.google.gwt.user.client.ui.FlowPanel; +import com.google.gwt.user.client.ui.HorizontalPanel; +import com.google.gwt.user.client.ui.Widget; +import com.google.gwt.view.client.CellPreviewEvent; +import com.sap.sailing.gwt.ui.adminconsole.DeviceMappingTableWrapper.FilterChangedHandler; import com.sap.sailing.gwt.ui.client.SailingServiceAsync; import com.sap.sailing.gwt.ui.client.StringMessages; +import com.sap.sailing.gwt.ui.common.client.DateAndTimeFormatterUtil; import com.sap.sailing.gwt.ui.shared.DeviceMappingDTO; +import com.sap.sailing.gwt.ui.shared.MarkDTO; import com.sap.sse.gwt.client.ErrorReporter; import com.sap.sse.gwt.client.dialog.DataEntryDialog; -public class RegattaLogTrackingDeviceMappingsDialog extends AbstractLogTrackingDeviceMappingsDialog { +public class RegattaLogTrackingDeviceMappingsDialog extends DataEntryDialog { protected final String leaderboardName; + public static final double PERCENTAGE_OF_TIMESPAN_TO_EXTEND_OPEN_ENDS = 0.1; + public static final String FIELD_INDEX = "index"; + public static final int CHART_WIDTH = 500; + public static final String SERIES_COLOR = "#fcb913"; + + private final ErrorReporter errorReporter; + private final SailingServiceAsync sailingService; + private final StringMessages stringMessages; + private List mappings = new ArrayList<>(); + private DeviceMappingTableWrapper deviceMappingTable; + + private Point[] data; + + private Date latest; + private Date earliest; + private Chart chart; + public RegattaLogTrackingDeviceMappingsDialog(final SailingServiceAsync sailingService, final StringMessages stringMessages, final ErrorReporter errorReporter, final String leaderboardName, DialogCallback callback) { - - super(sailingService, stringMessages, errorReporter, callback); + super(stringMessages.mapDevices(), /*message*/ null, stringMessages.ok(), stringMessages.cancel(), /*validator*/ null, callback); + this.stringMessages = stringMessages; + this.sailingService = sailingService; + this.errorReporter = errorReporter; this.leaderboardName = leaderboardName; - refresh(); } - + @Override - protected void refresh() { - sailingService.getDeviceMappingsFromLogHierarchy(leaderboardName, new AsyncCallback>() { + protected Widget getAdditionalWidget() { + FlowPanel mainPanel = new FlowPanel(); + HorizontalPanel buttonPanel = new HorizontalPanel(); + Button addMappingButton = new Button(stringMessages.add()); + addMappingButton.addClickHandler(new ClickHandler() { + @Override + public void onClick(ClickEvent event) { + addMapping(); + } + }); + buttonPanel.add(addMappingButton); + Button importBtn = new Button(stringMessages.importFixes()); + importBtn.addClickHandler(new ClickHandler() { + @Override + public void onClick(ClickEvent event) { + importFixes(); + } + }); + buttonPanel.add(importBtn); + mainPanel.add(buttonPanel); + + deviceMappingTable = new DeviceMappingTableWrapper(sailingService, stringMessages, errorReporter); + deviceMappingTable.addFilterChangedHandler(new FilterChangedHandler() { + @Override + public void onFilterChanged(List filteredList) { + mappings = filteredList; + updateChart(); + } + }); + deviceMappingTable.getTable().addCellPreviewHandler(new CellPreviewEvent.Handler() { + @Override + public void onCellPreview(CellPreviewEvent event) { + int i = mappings.indexOf(event.getValue()); + chart.getSeries()[0].getPoints()[i].select(true, false); + } + }); + final ImagesBarColumn actionCol = + new ImagesBarColumn( + new RaceLogTrackingDeviceMappingsImagesBarCell(stringMessages)); + actionCol.setFieldUpdater(getActionColFieldUpdater()); + deviceMappingTable.getTable().addColumn(actionCol, stringMessages.actions()); + + final HorizontalPanel deviceMappingPannel = new HorizontalPanel(); + mainPanel.add(deviceMappingPannel); + + chart = new Chart() + .setType(Series.Type.COLUMN_RANGE) + .setChartTitleText(stringMessages.deviceMappings()) + .setLegend(new Legend().setEnabled(false)) + .setInverted(true); + chart.setSeriesPlotOptions(new SeriesPlotOptions().setPointMouseOverEventHandler(new PointMouseOverEventHandler() { + @Override + public boolean onMouseOver(PointMouseOverEvent pointMouseOverEvent) { + int i = (int) pointMouseOverEvent.getXAsLong(); + deviceMappingTable.getSelectionModel().setSelected(mappings.get(i), true); + chart.getSeries()[0].getPoints()[i].select(true, false); + return true; + } + }).setColor(SERIES_COLOR)); + Highcharts.setOptions( + new Highcharts.Options().setGlobal( + new Global() + .setUseUTC(false) + )); + chart.getXAxis().setOption("labels/enabled", false) + .setGridLineWidth(0) + .setMinorGridLineWidth(0); + chart.getYAxis() + .setAxisTitle(new AxisTitle().setText(stringMessages.time())) + .setType(Axis.Type.DATE_TIME) + .setGridLineWidth(0) + .setMinorGridLineWidth(0); + chart.setWidth(CHART_WIDTH + "px"); + chart.setHeight("400px"); + chart.setToolTip(new ToolTip().setFormatter(new ToolTipFormatter() { + @Override + public String format(ToolTipData toolTipData) { + int index = (int) toolTipData.getXAsLong(); + DeviceMappingDTO mapping = mappings.get(index); + String itemType = mapping.mappedTo instanceof MarkDTO ? stringMessages.mark() : stringMessages.competitor(); + + return "" + stringMessages.device() + ": " + mapping.deviceIdentifier.deviceType + " - " + mapping.deviceIdentifier.deviceId + "
" + + "" + stringMessages.mappedTo() + ": " + itemType + " - " + mapping.mappedTo + "
" + + "" + stringMessages.from() + ": " + DateAndTimeFormatterUtil.formatDateAndTime(mapping.from) + "
" + + "" + stringMessages.to() + ": " + DateAndTimeFormatterUtil.formatDateAndTime(mapping.to); + } + })); + + deviceMappingPannel.add(chart); + deviceMappingPannel.add(deviceMappingTable); + + return mainPanel; + } + + void updateChart() { + earliest = new Date(Long.MAX_VALUE); + latest = new Date(Long.MIN_VALUE); + for (DeviceMappingDTO mapping : mappings) { + updateExtremes(mapping); + } + data = new Point[mappings.size()]; + long earliestMillis = earliest.getTime(); + long latestMillis = latest.getTime(); + long range = latestMillis - earliestMillis; + long extension = (long) (range * PERCENTAGE_OF_TIMESPAN_TO_EXTEND_OPEN_ENDS); // TODO bug 3426: open intervals dominate the chart too badly + long yMin = earliestMillis - extension; + long yMax = latestMillis + extension; + int i = 0; + for (DeviceMappingDTO mapping : mappings) { + JSONObject userData = new JSONObject(); + userData.put(FIELD_INDEX, userData); + long from = mapping.from == null ? yMin - range : mapping.from.getTime(); + long to = mapping.to == null ? yMax + range : mapping.to.getTime(); + data[i] = new Point(i, from, to); + i++; + } + chart.removeAllSeries(false); + chart.addSeries(chart.createSeries() + .setName(stringMessages.deviceMappings()) + .setPoints(data)); + chart.getYAxis().setExtremes(yMin, yMax); + } + + private void updateExtremes(DeviceMappingDTO mapping) { + if (mapping.from != null && earliest.after(mapping.from)) { + earliest = mapping.from; + } + if (mapping.to != null && latest.before(mapping.to)) { + latest = mapping.to; + } + if (mapping.to != null && earliest.after(mapping.to)) { + earliest = mapping.to; + } + if (mapping.from != null && latest.before(mapping.from)) { + latest = mapping.from; + } + } + + private void addMapping() { + showAddMappingDialog(null); + } + + private void refresh() { + sailingService.getDeviceMappings(leaderboardName, new AsyncCallback>() { @Override public void onSuccess(List result) { mappings = result; @@ -40,8 +228,7 @@ public class RegattaLogTrackingDeviceMappingsDialog extends AbstractLogTrackingD }); } - @Override - protected void showAddMappingDialog(DeviceMappingDTO mapping) { + private void showAddMappingDialog(DeviceMappingDTO mapping) { new RegattaLogAddDeviceMappingDialog(sailingService, errorReporter, stringMessages, leaderboardName, new DataEntryDialog.DialogCallback() { @Override @@ -68,8 +255,7 @@ public class RegattaLogTrackingDeviceMappingsDialog extends AbstractLogTrackingD }, mapping).show(); } - @Override - protected void importFixes() { + private void importFixes() { new RegattaLogImportFixesAndAddMappingsDialog(sailingService, errorReporter, stringMessages, leaderboardName, new DataEntryDialog.DialogCallback>() { @@ -97,11 +283,8 @@ public class RegattaLogTrackingDeviceMappingsDialog extends AbstractLogTrackingD }).show(); } - @Override - protected FieldUpdater getActionColFieldUpdater() { - + private FieldUpdater getActionColFieldUpdater() { return new FieldUpdater() { - @Override public void update(int index, final DeviceMappingDTO dto, String value) { if (RaceLogTrackingDeviceMappingsImagesBarCell.ACTION_CLOSE.equals(value)) { diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/SmartphoneTrackingEventManagementPanel.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/SmartphoneTrackingEventManagementPanel.java index 4fa6138fc50..192d29f6167 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/SmartphoneTrackingEventManagementPanel.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/SmartphoneTrackingEventManagementPanel.java @@ -276,17 +276,6 @@ public class SmartphoneTrackingEventManagementPanel extends AbstractLeaderboardC }); } }).show(); - - } else if (RaceLogTrackingEventManagementRaceImagesBarCell.ACTION_MAP_DEVICES.equals(value)) { - new RaceLogTrackingDeviceMappingsDialog(sailingService, stringMessages, errorReporter, leaderboardName, raceColumnName, fleetName, new DialogCallback() { - @Override - public void ok(Void editedObject) { - } - - @Override - public void cancel() { - } - }).show(); } else if (RaceLogTrackingEventManagementRaceImagesBarCell.ACTION_COPY.equals(value)) { List races = new ArrayList<>(raceColumnTable.getDataProvider().getList()); @@ -580,8 +569,8 @@ public class SmartphoneTrackingEventManagementPanel extends AbstractLeaderboardC final String result; RegattaDTO regatta = null; if (getSelectedLeaderboard().regattaName != null) { - if (allRegattas != null) { - for (RegattaDTO i : allRegattas) { + if (allRegattas != null) { + for (RegattaDTO i : allRegattas) { if (getSelectedLeaderboard().regattaName.equals(i.getName())) { regatta = i; break; @@ -597,7 +586,7 @@ public class SmartphoneTrackingEventManagementPanel extends AbstractLeaderboardC new AsyncCallback>() { @Override public void onFailure(Throwable caught) { - GWT.log("Error while searching BoatClass."); + GWT.log("Error while searching boat class"); showWithBoatClass.showWithBoatClass(null); } diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/TableWrapper.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/TableWrapper.java index f4c8bc05f49..65d7549a29a 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/TableWrapper.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/TableWrapper.java @@ -30,6 +30,7 @@ public abstract class TableWrapper> im protected VerticalPanel mainPanel; protected final SailingServiceAsync sailingService; protected final ErrorReporter errorReporter; + protected final StringMessages stringMessages; private final AdminConsoleTableResources tableRes = GWT.create(AdminConsoleTableResources.class); private final ListHandler columnSortHandler; @@ -48,6 +49,7 @@ public abstract class TableWrapper> im boolean multiSelection, boolean enablePager, EntityIdentityComparator entityIdentityComparator) { this.sailingService = sailingService; this.errorReporter = errorReporter; + this.stringMessages = stringMessages; table = new FlushableCellTable(10000, tableRes); table.ensureDebugId("WrappedTable"); this.dataProvider = new ListDataProvider(); diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/SailingService.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/SailingService.java old mode 100755 new mode 100644 index 75ec7c32609..0802b3d2b72 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/SailingService.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/SailingService.java @@ -17,6 +17,7 @@ import com.sap.sailing.domain.common.LeaderboardType; import com.sap.sailing.domain.common.LegIdentifier; import com.sap.sailing.domain.common.MaxPointsReason; import com.sap.sailing.domain.common.NoWindException; +import com.sap.sailing.domain.common.NotFoundException; import com.sap.sailing.domain.common.PassingInstruction; import com.sap.sailing.domain.common.PolarSheetsXYDiagramData; import com.sap.sailing.domain.common.Position; @@ -25,6 +26,7 @@ import com.sap.sailing.domain.common.RankingMetrics; import com.sap.sailing.domain.common.RegattaAndRaceIdentifier; import com.sap.sailing.domain.common.RegattaIdentifier; import com.sap.sailing.domain.common.ScoringSchemeType; +import com.sap.sailing.domain.common.UnableToCloseDeviceMappingException; import com.sap.sailing.domain.common.WindSource; import com.sap.sailing.domain.common.abstractlog.NotRevokableException; import com.sap.sailing.domain.common.configuration.DeviceConfigurationMatcherType; @@ -37,6 +39,7 @@ import com.sap.sailing.domain.common.dto.RaceColumnInSeriesDTO; import com.sap.sailing.domain.common.dto.RaceDTO; import com.sap.sailing.domain.common.dto.RegattaCreationParametersDTO; import com.sap.sailing.domain.common.racelog.RacingProcedureType; +import com.sap.sailing.domain.common.racelog.tracking.CompetitorRegistrationOnRaceLogDisabledException; import com.sap.sailing.domain.common.racelog.tracking.DoesNotHaveRegattaLogException; import com.sap.sailing.domain.common.racelog.tracking.NotDenotedForRaceLogTrackingException; import com.sap.sailing.domain.common.racelog.tracking.TransformationException; @@ -454,10 +457,11 @@ public interface SailingService extends RemoteService, FileStorageManagementGwtS /** * Revoke the {@link RaceLogDenoteForTrackingEvent}. This does not affect an existing {@code RaceLogRaceTracker} * or {@link TrackedRace} for this {@code RaceLog}. + * @throws NotFoundException * * @see RaceLogTrackingAdapter#removeDenotationForRaceLogTracking */ - void removeDenotationForRaceLogTracking(String leaderboardName, String raceColumnName, String fleetName); + void removeDenotationForRaceLogTracking(String leaderboardName, String raceColumnName, String fleetName) throws NotFoundException; void denoteForRaceLogTracking(String leaderboardName) throws Exception; @@ -470,48 +474,32 @@ public interface SailingService extends RemoteService, FileStorageManagementGwtS void startRaceLogTracking(String leaderboardName, String raceColumnName, String fleetName, boolean trackWind, boolean correctWindByDeclination) throws NotDenotedForRaceLogTrackingException, Exception; - void setCompetitorRegistrationsInRaceLog(String leaderboardName, String raceColumnName, String fleetName, Set competitors); - - /** - * Get the competitors registered in this leaderboard. Does not automatically include the competitors - * {@link #getCompetitorRegistrationsInRaceLog(String, String, String) registered for the racelog}. - */ - Collection getCompetitorRegistrationsInRegattaLog(String leaderboardName) throws DoesNotHaveRegattaLogException; - - void addMarkToRaceLog(String leaderboardName, String raceColumnName, String fleetName, MarkDTO markDTO); - - Iterable getMarksInRaceLog(String leaderboardName, String raceColumnName, String fleetName); + void setCompetitorRegistrationsInRaceLog(String leaderboardName, String raceColumnName, String fleetName, Set competitors) throws CompetitorRegistrationOnRaceLogDisabledException, NotFoundException; /** * Adds the course definition to the racelog, while trying to reuse existing marks, controlpoints and waypoints * from the previous course definition in the racelog. + * @throws NotFoundException */ - void addCourseDefinitionToRaceLog(String leaderboardName, String raceColumnName, String fleetName, List> course); + void addCourseDefinitionToRaceLog(String leaderboardName, String raceColumnName, String fleetName, List> course) throws NotFoundException; - RaceCourseDTO getLastCourseDefinitionInRaceLog(String leaderboardName, String raceColumnName, String fleetName); + RaceCourseDTO getLastCourseDefinitionInRaceLog(String leaderboardName, String raceColumnName, String fleetName) throws NotFoundException; /** * Adds a fix to the {@link GPSFixStore}, and creates a mapping with a virtual device for exactly the current timepoint. + * @throws DoesNotHaveRegattaLogException */ - void pingMarkViaRaceLogTracking(String leaderboardName, String raceColumnName, String fleetName, MarkDTO mark, Position position); - - void addDeviceMappingToRaceLog(String leaderboardName, String raceColumnName, String fleetName, DeviceMappingDTO mapping) - throws TransformationException; - - List getDeviceMappingsFromRaceLog(String leaderboardName, String raceColumnName, String fleetName) - throws TransformationException; + void pingMark(String leaderboardName, MarkDTO mark, Position position) throws DoesNotHaveRegattaLogException; List getDeserializableDeviceIdentifierTypes(); - void closeOpenEndedDeviceMapping(String leaderboardName, String raceColumnName, String fleetName, DeviceMappingDTO mapping, - Date closingTimePoint) throws NoCorrespondingServiceRegisteredException, TransformationException; - /** * Revoke the events in the {@code RaceLog} that are identified by the {@code eventIds}. * This only affects such events that implement {@link Revokable}. + * @throws NotFoundException */ void revokeRaceAndRegattaLogEvents(String leaderboardName, String raceColumnName, String fleetName, List eventIds) - throws NotRevokableException; + throws NotRevokableException, NotFoundException; Collection getGPSFixImporterTypes(); @@ -543,7 +531,7 @@ public interface SailingService extends RemoteService, FileStorageManagementGwtS Date dateOfMarkPassing, CompetitorDTO competitorDTO); void setCompetitorRegistrationsInRegattaLog(String leaderboardName, Set competitors) - throws DoesNotHaveRegattaLogException; + throws DoesNotHaveRegattaLogException, NotFoundException; /** * A leaderboard may be situated under multiple events (connected via a leaderboardgroup). @@ -563,25 +551,21 @@ public interface SailingService extends RemoteService, FileStorageManagementGwtS Integer getStructureImportOperationProgress(); - List getDeviceMappingsFromLogHierarchy(String leaderboardName, String raceColumnName, - String fleetName) throws TransformationException; void inviteCompetitorsForTrackingViaEmail(String serverUrlWithoutTrailingSlash, EventDTO event, String leaderboardName, Collection competitors, String localeInfo) throws MailException; - Iterable getMarksInRaceLogsAndTrackedRaces(String leaderboardName); - void inviteBuoyTenderViaEmail(String serverUrlWithoutTrailingSlash, EventDTO eventDto, String leaderboardName, String emails, String localeInfoName) throws MailException; ArrayList getLeaderboardGroupsByEventId(UUID id); - Iterable getMarksInRegattaLog(String leaderboardName); + Iterable getMarksInRegattaLog(String leaderboardName) throws DoesNotHaveRegattaLogException; - List getDeviceMappingsFromLogHierarchy(String leaderboardName) throws TransformationException; + List getDeviceMappings(String leaderboardName) throws DoesNotHaveRegattaLogException, TransformationException; void revokeRaceAndRegattaLogEvents(String leaderboardName, List eventIds) throws NotRevokableException, DoesNotHaveRegattaLogException; - void closeOpenEndedDeviceMapping(String leaderboardName, DeviceMappingDTO mappingDto, Date closingTimePoint) throws TransformationException; + void closeOpenEndedDeviceMapping(String leaderboardName, DeviceMappingDTO mappingDto, Date closingTimePoint) throws TransformationException, DoesNotHaveRegattaLogException, UnableToCloseDeviceMappingException; void addDeviceMappingToRegattaLog(String leaderboardName, DeviceMappingDTO dto) throws NoCorrespondingServiceRegisteredException, TransformationException, DoesNotHaveRegattaLogException; @@ -589,34 +573,51 @@ public interface SailingService extends RemoteService, FileStorageManagementGwtS boolean doesRegattaLogContainCompetitors(String name) throws DoesNotHaveRegattaLogException; RegattaAndRaceIdentifier getRaceIdentifier(String regattaLikeName, String raceColumnName, String fleetName); - void setTrackingTimes(RaceLogSetTrackingTimesDTO dto); + void setTrackingTimes(RaceLogSetTrackingTimesDTO dto) throws NotFoundException; - Pair getTrackingTimes(String leaderboardName, String raceColumnName, String fleetName); - - void revokeMarkDefinitionEventInRaceLog(String leaderboardName, String raceColumnName, String fleetName, - MarkDTO markDTO); - - Collection getCompetitorRegistrationsFromLogHierarchy(String leaderboardName); + Pair getTrackingTimes(String leaderboardName, String raceColumnName, String fleetName) throws NotFoundException; /** * @param raceLogFrom identifies the race log to copy from by its leaderboard name, race column name and fleet name * @param raceLogsTo identifies the race log to copy from by their leaderboard name, race column name and fleet name + * @throws NotFoundException */ void copyCompetitorsToOtherRaceLogs(Triple fromTriple, - Set> toTriples); + Set> toTriples) throws NotFoundException; /** * @param raceLogFrom identifies the race log to copy from by its leaderboard name, race column name and fleet name * @param raceLogsTo identifies the race log to copy from by their leaderboard name, race column name and fleet name + * @throws NotFoundException */ void copyCourseToOtherRaceLogs(Triple fromTriple, - Set> toTriples); + Set> toTriples) throws NotFoundException; /** - * Get the competitors registered in this racelog. Does not automatically include the competitors - * {@link #getCompetitorRegistrationsOnRaceLog(String) registered for the leaderboard}. + * Get the competitors registered for a certain race. This automatically checks, whether competitors are registered + * in the raceLog (in case of e.g. splitFleets) or in the RegattaLog (default) + * @throws NotFoundException */ - Collection getCompetitorRegistrationsOnRaceLog(String leaderboardName, String raceColumnName, - String fleetName); + Collection getCompetitorRegistrationsForRace(String leaderboardName, String raceColumnName, + String fleetName) throws DoesNotHaveRegattaLogException, NotFoundException; + void addMarkToRegattaLog(String leaderboardName, MarkDTO mark) throws DoesNotHaveRegattaLogException; + + void revokeMarkDefinitionEventInRegattaLog(String leaderboardName, MarkDTO markDTO) throws DoesNotHaveRegattaLogException; + + Collection getCompetitorRegistrationsInRegattaLog(String leaderboardName) throws DoesNotHaveRegattaLogException, NotFoundException; + + Boolean areCompetitorRegistrationsEnabledForRace(String leaderboardName, String raceColumnName, String fleetName) throws NotFoundException; + + void disableCompetitorRegistrationsForRace(String leaderboardName, String raceColumnName, String fleetName) throws NotRevokableException, NotFoundException; + + void enableCompetitorRegistrationsForRace(String leaderboardName, String raceColumnName, String fleetName) throws IllegalArgumentException, NotFoundException; + + Pair checkIfMarksAreUsedInOtherRaceLogs(String leaderboardName, String raceColumnName, + String fleetName, Set marksToRemove) throws NotFoundException; + + Collection getCompetitorRegistrationsInRaceLog(String leaderboardName, String raceColumnName, + String fleetName) throws NotFoundException; + + Collection getCompetitorRegistrationsForLeaderboard(String leaderboardName) throws NotFoundException; } diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/SailingServiceAsync.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/SailingServiceAsync.java old mode 100755 new mode 100644 index fb9d13f85af..b09ff4c76e2 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/SailingServiceAsync.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/SailingServiceAsync.java @@ -639,41 +639,20 @@ public interface SailingServiceAsync extends ServerInfoRetriever, FileStorageMan void setCompetitorRegistrationsInRegattaLog(String leaderboardName, Set competitors, AsyncCallback callback); - void getCompetitorRegistrationsOnRaceLog(String leaderboardName, String raceColumnName, String fleetName, + void getCompetitorRegistrationsForRace(String leaderboardName, String raceColumnName, String fleetName, AsyncCallback> callback); - void addMarkToRaceLog(String leaderboardName, String raceColumnName, String fleetName, MarkDTO markDTO, - AsyncCallback callback); - - void getMarksInRaceLog(String leaderboardName, String raceColumnName, String fleetName, - AsyncCallback> callback); - void addCourseDefinitionToRaceLog(String leaderboardName, String raceColumnName, String fleetName, List> course, AsyncCallback callback); void getLastCourseDefinitionInRaceLog(String leaderboardName, String raceColumnName, String fleetName, AsyncCallback callback); - void pingMarkViaRaceLogTracking(String leaderboardName, String raceColumnName, String fleetName, MarkDTO mark, + void pingMark(String leaderboardName, MarkDTO mark, Position position, AsyncCallback callback); void getDeserializableDeviceIdentifierTypes(AsyncCallback> callback); - /** - * Do not only use the racelog, but also other logs (e.g. RegattaLogs) in the hierarchy of the race. - */ - void getDeviceMappingsFromLogHierarchy(String leaderboardName, String raceColumnName, String fleetName, - AsyncCallback> callback); - - void getDeviceMappingsFromRaceLog(String leaderboardName, String raceColumnName, String fleetName, - AsyncCallback> callback); - - void addDeviceMappingToRaceLog(String leaderboardName, String raceColumnName, String fleetName, - DeviceMappingDTO mapping, AsyncCallback callback); - - void closeOpenEndedDeviceMapping(String leaderboardName, String raceColumnName, String fleetName, - DeviceMappingDTO mapping, Date closingTimePoint, AsyncCallback callback); - void revokeRaceAndRegattaLogEvents(String leaderboardName, String raceColumnName, String fleetName, List eventIds, AsyncCallback callback); @@ -722,8 +701,6 @@ public interface SailingServiceAsync extends ServerInfoRetriever, FileStorageMan String leaderboardName, Collection competitors, String localeInfo, AsyncCallback callback); - void getMarksInRaceLogsAndTrackedRaces(String leaderboardName, AsyncCallback> callback); - void inviteBuoyTenderViaEmail(String serverUrlWithoutTrailingSlash, EventDTO eventDto, String leaderboardName, String emails, String localeInfoName, AsyncCallback callback); @@ -731,11 +708,8 @@ public interface SailingServiceAsync extends ServerInfoRetriever, FileStorageMan void getMarksInRegattaLog(String leaderboardName, AsyncCallback> callback); - void getDeviceMappingsFromLogHierarchy(String leaderboardName, AsyncCallback> asyncCallback); - - void getCompetitorRegistrationsInRegattaLog(String leaderboardName, - AsyncCallback> asyncCallback); - + void getDeviceMappings(String leaderboardName, AsyncCallback> asyncCallback); + void revokeRaceAndRegattaLogEvents(String leaderboardName, List eventIds, AsyncCallback callback); void closeOpenEndedDeviceMapping(String leaderboardName, DeviceMappingDTO mappingDto, Date closingTimePoint, @@ -753,16 +727,42 @@ public interface SailingServiceAsync extends ServerInfoRetriever, FileStorageMan void getTrackingTimes(String leaderboardName, String raceColumnName, String fleetName, AsyncCallback> callback); - void revokeMarkDefinitionEventInRaceLog(String leaderboardName, String raceColumnName, String fleetName, - MarkDTO markDTO, AsyncCallback callback); - - void getCompetitorRegistrationsFromLogHierarchy(String leaderboardName, - AsyncCallback> setCompetitorsCallback); - + /** + * Copies one race's competitor set to other races. + * @param fromTriple + * leaderboard name, race column name, and fleet name identifying the race from which to copy the + * competitors + * @param toTriples leaderboard name, race column name, and fleet name identifying the races to which to copy the + * competitors + */ void copyCompetitorsToOtherRaceLogs(Triple fromTriple, Set> toTriples, AsyncCallback callback); void copyCourseToOtherRaceLogs(Triple fromTriple, Set> toTriples, AsyncCallback callback); + void addMarkToRegattaLog(String leaderboardName, MarkDTO mark, AsyncCallback asyncCallback); + + void revokeMarkDefinitionEventInRegattaLog(String leaderboardName, MarkDTO markDTO, AsyncCallback callback); + + void getCompetitorRegistrationsInRegattaLog(String leaderboardName, + AsyncCallback> setCompetitorsCallback); + + void areCompetitorRegistrationsEnabledForRace(String leaderboardName, String raceColumnName, String fleetName, + AsyncCallback asyncCallback); + + void disableCompetitorRegistrationsForRace(String leaderboardName, String raceColumnName, String fleetName, + AsyncCallback asyncCallback); + + void enableCompetitorRegistrationsForRace(String leaderboardName, String raceColumnName, String fleetName, + AsyncCallback asyncCallback); + + void checkIfMarksAreUsedInOtherRaceLogs(String leaderboardName, String raceColumnName, String fleetName, + Set marksToRemove, AsyncCallback> asyncCallback); + + void getCompetitorRegistrationsInRaceLog(String leaderboardName, String raceColumnName, String fleetName, + AsyncCallback> callback); + + void getCompetitorRegistrationsForLeaderboard(String leaderboardName, + AsyncCallback> callback); } diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages.java index a7f66f1ff9b..4e4422ca7e3 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages.java @@ -1447,6 +1447,13 @@ public interface StringMessages extends com.sap.sse.gwt.client.StringMessages, c String couldNotRetrieveImageSizeYet(); @Override String pleaseOnlyUploadContentYouHaveAllUsageRightsFor(); + String registerCompetitorsOnRace(); + String doYouWantToRegisterCompetitorsDirectlyOnTheRace(); + String doYouWantToDisableCompetitorsRegistrationsOnTheRace(); + String warningDirectCompetitorRegistration(); + String warningRegattaCompetitorRegistration(); + String competitorRegistrationsOnRaceDisabled(); + String addMarkToRegatta(); String selectALeaderboardGroup(); @Override String pleaseSelect(); @@ -1457,4 +1464,7 @@ public interface StringMessages extends com.sap.sse.gwt.client.StringMessages, c String transparentBufferLineOnHover(); String bufferLineStrokeWeight(); String profile(); + String showOnlyCompetitorsOfLog(); + String confirmLosingCompetitorEditsWhenTogglingLogBasedView(); + String removalOfMarkDisabledMayBeUsedInRaces(String raceNames); } diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages.properties b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages.properties index 4fce9a0389f..06e41287176 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages.properties +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages.properties @@ -1,5 +1,5 @@ manage2Sail=Manage2Sail -raceCommitteeApp=Race Committee App +raceCommitteeApp=Race Manager App tracTracEvents=TracTrac Events swissTimingEvents=SwissTiming Events trackedBefore=History of tracked events @@ -1415,6 +1415,13 @@ noImagesDefinedYet=No images defined yet imageSizeError=The size of the {0} image does not fit. The width should be between {1} and {2} px and the height between {3} and {4} px. couldNotRetrieveImageSizeYet=The width and height of the image could not be retrieved yet. pleaseOnlyUploadContentYouHaveAllUsageRightsFor=Please only upload content you have all usage rights for. Remember that content may be cropped. +registerCompetitorsOnRace=Register Competitors on Race (e.g. for split-fleet racing) +doYouWantToRegisterCompetitorsDirectlyOnTheRace=Do you want to register competitors directly on the Race? +doYouWantToDisableCompetitorsRegistrationsOnTheRace=Do you want to disable competitor registrations on the Race? +warningDirectCompetitorRegistration=Warning! This setting will lead to competitors for this race being registered on a per race basis. Competitors will not be automatically registered for this race, when registering them on the corresponding regatta. +warningRegattaCompetitorRegistration=Warning! This will reactivate competior registrations on the regatta. All competitor registrations from the regatta will automatically be used as competitor registration for this race. +competitorRegistrationsOnRaceDisabled=Competitor Registrations are disabled for this race. Enable by checking the checkbox to the left. +addMarkToRegatta=Add Mark to Regatta selectALeaderboardGroup=Select a leaderboard group... pleaseSelect=Please select requiresValidRegatta=This page requires a valid regatta, race column and fleet name to identify the race to show. @@ -1424,3 +1431,6 @@ topN=Top {0} transparentBufferLineOnHover=Transparent buffer lines on hover of helplines bufferLineStrokeWeight=Buffer line stroke weight profile=Profile +showOnlyCompetitorsOfLog=Show only competitors registered in Log +confirmLosingCompetitorEditsWhenTogglingLogBasedView=This will reset your current, unsaved changes to the competitors.\nDo you really want to continue? +removalOfMarkDisabledMayBeUsedInRaces=Removal deavticated, marks are used in races {0} \ No newline at end of file diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages_de.properties b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages_de.properties index 3807a1807d8..c6923860cff 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages_de.properties +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages_de.properties @@ -1,5 +1,5 @@ manage2Sail=Manage2Sail -raceCommitteeApp=Wettfahrtleiter App +raceCommitteeApp=Race Manager App createNewEvent=Create New EventtracTracEvents=TracTrac Events swissTimingEvents=SwissTiming Events trackedBefore=Historie verfolgter Events @@ -1402,6 +1402,13 @@ noImagesDefinedYet=Noch keine Bilder vorhanden imageSizeError=Die Größe des {0}-Bildes ist unpassend. Die Breite sollte zwischen {1} und {2} px und die Höhe zwischen {3} und {4} px sein. couldNotRetrieveImageSizeYet=Bildgröße konnte noch nicht ermittelt werden. pleaseOnlyUploadContentYouHaveAllUsageRightsFor=Bitte nur Inhalte hochladen, für die alle Verwendungsrechte vorliegen. Bitte beachten: Bilder können verändert wiedergegeben werden. +registerCompetitorsOnRace=Teilnehmer auf dem Rennen registrieren (z.B. für Split-Fleets) +doYouWantToRegisterCompetitorsDirectlyOnTheRace=Wollen Sie Teilnehmer direkt auf dem Rennen registrieren? +warningDirectCompetitorRegistration=Warnung! Diese Einstellung führt dazu, dass Teilnehmer dieses Rennens sich von nunan auf Rennebene registriert werden müssen. Dies ist nur sinnvoll, wenn sich die Teilnehmer verschiedener Rennen einer Regatta unterscheiden. +warningRegattaCompetitorRegistration=Warnung! Diese Einstellung reaktiviert die Teilnehmerregistrierung auf Regatta-Ebene. Alle Teilnehmer der zu diesem Rennen gehörenden Regatta werden automatisch Teilnehmer dieses Rennens. +doYouWantToDisableCompetitorsRegistrationsOnTheRace=Wollen Sie Teilnehmer auf Regatta- statt Rennebene registrieren? +competitorRegistrationsOnRaceDisabled=Teilnehmeranmeldung ist für dieses Rennen auf Rennebene deaktiviert. Aktivieren durch selektieren der CheckBox auf der linken Seite. +addMarkToRegatta=Tonne zu Regatta hinzufügen selectALeaderboardGroup=Bitte eine Ranglisten-Gruppe auswählen... pleaseSelect=Bitte auswählen requiresValidRegatta=Diese Seite benötigt eine gültige Regatta, Rennspalte und einen gültigen Gruppennamen um die anzuzeigende Wettfahrt zu identifizieren. @@ -1411,6 +1418,9 @@ topN=Top {0} transparentBufferLineOnHover=Transparente Pufferlinien bei Maus über Hilfslinien bufferLineStrokeWeight=Linienbreite der Pufferlinien profile=Profil +showOnlyCompetitorsOfLog=Nur Teilnehmer aus Log anzeigen +confirmLosingCompetitorEditsWhenTogglingLogBasedView=Damit werden alle aktuellen, noch nicht gespeicherten\nÄnderungen an der Teilnehmerliste zurückgesetzt. Wirklich fortfahren? +removalOfMarkDisabledMayBeUsedInRaces=Löschung deaktiviert, Bahnmarke wird in folgenden anderen Wettfahrten benutzt: {0} scoringSchemeHighPointFirstGetsTwelveOrEight=High-Point System 12 Punkte scoringSchemeHighPointFirstGetsTwelveOrEightDescription=Scores als Punkte. Der Gewinner bekommt 12 Punkte. scoringSchemeHighPointEssOverall12=High Point System ESS Gesamtwertung (12) diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages_ru.properties b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages_ru.properties index 069f5cada2f..c88e4a48fc8 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages_ru.properties +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages_ru.properties @@ -1,6 +1,6 @@ # If you want new properties translated then sent this over GMR (Mark Angell ) manage2Sail=Manage2Sail -raceCommitteeApp=Race Committee App +raceCommitteeApp=Race Manager App tracTracEvents=События Трак Трак swissTimingEvents=События Swiss Timing trackedBefore=Ранее Отслеженные @@ -1350,6 +1350,8 @@ topN=Top {0} transparentBufferLineOnHover=Transparent buffer lines on hover of helplines bufferLineStrokeWeight=Buffer line stroke weight profile=профиль +confirmLosingCompetitorEditsWhenTogglingLogBasedView=This will reset your current, unsaved changes to the competitors.\nDo you really want to continue? +removalOfMarkDisabledMayBeUsedInRaces=Removal deavticated, marks are used in races {0} scoringSchemeHighPointFirstGetsTwelveOrEight=High Point, winner gets 12 points (or 8) scoringSchemeHighPointFirstGetsTwelveOrEightDescription=Score in points. Winner scores 12 points, 2nd - 11 points, .... A tie is broken in favour of the competitor having won most races, if tie remains then tie is broken by the rank in the last race scored. scoringSchemeHighPointEssOverall12=High Point System ESS Overall (12) diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages_zh.properties b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages_zh.properties index 8458330ae32..052fce364b6 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages_zh.properties +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages_zh.properties @@ -1,5 +1,5 @@ manage2Sail=Manage2Sail -raceCommitteeApp=Race Committee App +raceCommitteeApp=Race Manager App enableRaceFilter=Enable filter finishLine=终点线 raceLabel=比赛轮次 @@ -1365,6 +1365,8 @@ topN=Top {0} transparentBufferLineOnHover=Transparent buffer lines on hover of helplines bufferLineStrokeWeight=Buffer line stroke weight profile=簡介 +confirmLosingCompetitorEditsWhenTogglingLogBasedView=This will reset your current, unsaved changes to the competitors.\nDo you really want to continue? +removalOfMarkDisabledMayBeUsedInRaces=Removal deavticated, marks are used in races {0} scoringSchemeHighPointFirstGetsTwelveOrEight=High Point, winner gets 12 points (or 8) scoringSchemeHighPointFirstGetsTwelveOrEightDescription=Score in points. Winner scores 12 points, 2nd - 11 points, .... A tie is broken in favour of the competitor having won most races, if tie remains then tie is broken by the rank in the last race scored. scoringSchemeHighPointEssOverall12=High Point System ESS Overall (12) diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/server/SailingServiceImpl.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/server/SailingServiceImpl.java index a1a6d909094..670ee2e6b03 100755 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/server/SailingServiceImpl.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/server/SailingServiceImpl.java @@ -59,7 +59,6 @@ import org.osgi.util.tracker.ServiceTracker; import com.sap.sailing.domain.abstractlog.AbstractLog; import com.sap.sailing.domain.abstractlog.AbstractLogEvent; -import com.sap.sailing.domain.abstractlog.MultiLogAnalyzer; import com.sap.sailing.domain.abstractlog.impl.AllEventsOfTypeFinder; import com.sap.sailing.domain.abstractlog.impl.LogEventAuthorImpl; import com.sap.sailing.domain.abstractlog.race.RaceLog; @@ -74,7 +73,6 @@ import com.sap.sailing.domain.abstractlog.race.analyzing.impl.TrackingTimesFinde import com.sap.sailing.domain.abstractlog.race.impl.RaceLogCourseDesignChangedEventImpl; import com.sap.sailing.domain.abstractlog.race.impl.RaceLogEndOfTrackingEventImpl; import com.sap.sailing.domain.abstractlog.race.impl.RaceLogFixedMarkPassingEventImpl; -import com.sap.sailing.domain.abstractlog.race.impl.RaceLogRevokeEventImpl; import com.sap.sailing.domain.abstractlog.race.impl.RaceLogStartOfTrackingEventImpl; import com.sap.sailing.domain.abstractlog.race.impl.RaceLogSuppressedMarkPassingsEventImpl; import com.sap.sailing.domain.abstractlog.race.state.ReadonlyRaceState; @@ -82,24 +80,19 @@ import com.sap.sailing.domain.abstractlog.race.state.impl.ReadonlyRaceStateImpl; import com.sap.sailing.domain.abstractlog.race.state.racingprocedure.FlagPoleState; import com.sap.sailing.domain.abstractlog.race.state.racingprocedure.gate.ReadonlyGateStartRacingProcedure; import com.sap.sailing.domain.abstractlog.race.state.racingprocedure.rrs26.ReadonlyRRS26RacingProcedure; -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.analyzing.impl.RaceLogDefinedMarkFinder; -import com.sap.sailing.domain.abstractlog.race.tracking.analyzing.impl.RaceLogOpenEndedDeviceMappingCloser; 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.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.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.RegattaLogRegisterCompetitorEvent; +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.RegattaLogRevokeEventImpl; +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.abstractlog.regatta.tracking.analyzing.impl.RegattaLogOpenEndedDeviceMappingCloser; -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.base.Boat; import com.sap.sailing.domain.base.BoatClass; import com.sap.sailing.domain.base.Competitor; @@ -160,6 +153,7 @@ import com.sap.sailing.domain.common.LegType; import com.sap.sailing.domain.common.ManeuverType; import com.sap.sailing.domain.common.MaxPointsReason; import com.sap.sailing.domain.common.NoWindException; +import com.sap.sailing.domain.common.NotFoundException; import com.sap.sailing.domain.common.PassingInstruction; import com.sap.sailing.domain.common.PolarSheetsXYDiagramData; import com.sap.sailing.domain.common.Position; @@ -179,6 +173,7 @@ import com.sap.sailing.domain.common.ScoringSchemeType; import com.sap.sailing.domain.common.Speed; import com.sap.sailing.domain.common.SpeedWithBearing; import com.sap.sailing.domain.common.Tack; +import com.sap.sailing.domain.common.UnableToCloseDeviceMappingException; import com.sap.sailing.domain.common.Wind; import com.sap.sailing.domain.common.WindSource; import com.sap.sailing.domain.common.WindSourceType; @@ -214,8 +209,10 @@ import com.sap.sailing.domain.common.racelog.FlagPole; import com.sap.sailing.domain.common.racelog.Flags; import com.sap.sailing.domain.common.racelog.RaceLogRaceStatus; import com.sap.sailing.domain.common.racelog.RacingProcedureType; +import com.sap.sailing.domain.common.racelog.tracking.CompetitorRegistrationOnRaceLogDisabledException; import com.sap.sailing.domain.common.racelog.tracking.DoesNotHaveRegattaLogException; import com.sap.sailing.domain.common.racelog.tracking.MappableToDevice; +import com.sap.sailing.domain.common.racelog.tracking.NotDenotableForRaceLogTrackingException; import com.sap.sailing.domain.common.racelog.tracking.NotDenotedForRaceLogTrackingException; import com.sap.sailing.domain.common.racelog.tracking.RaceLogTrackingState; import com.sap.sailing.domain.common.racelog.tracking.TransformationException; @@ -252,7 +249,6 @@ import com.sap.sailing.domain.racelogtracking.impl.DeviceMappingImpl; import com.sap.sailing.domain.ranking.RankingMetric.RankingInfo; import com.sap.sailing.domain.ranking.RankingMetricsFactory; import com.sap.sailing.domain.regattalike.HasRegattaLike; -import com.sap.sailing.domain.regattalike.IsRegattaLike; import com.sap.sailing.domain.regattalike.LeaderboardThatHasRegattaLike; import com.sap.sailing.domain.regattalog.RegattaLogStore; import com.sap.sailing.domain.swisstimingadapter.StartList; @@ -2440,12 +2436,12 @@ public class SailingServiceImpl extends ProxiedRemoteServiceServlet implements S raceColumn instanceof RaceColumnInSeries ? ((RaceColumnInSeries) raceColumn).getRegatta().getName() : null, raceColumn instanceof RaceColumnInSeries ? ((RaceColumnInSeries) raceColumn).getSeries().getName() : null, fleetDTO, raceColumn.isMedalRace(), raceIdentifier, raceDTO, raceColumn instanceof MetaLeaderboardColumn); - RaceLog raceLog = raceColumn.getRaceLog(fleet); - RaceLogTrackingState raceLogTrackingState = raceLog == null ? RaceLogTrackingState.NOT_A_RACELOG_TRACKED_RACE : + final RaceLog raceLog = raceColumn.getRaceLog(fleet); + final RaceLogTrackingState raceLogTrackingState = raceLog == null ? RaceLogTrackingState.NOT_A_RACELOG_TRACKED_RACE : new RaceLogTrackingStateAnalyzer(raceLog).analyze(); - boolean raceLogTrackerExists = raceLog == null ? false : getService().getRaceTrackerById(raceLog.getId()) != null; - boolean competitorRegistrationsExist = raceLog == null ? false : !new RegisteredCompetitorsAnalyzer<>(raceLog).analyze().isEmpty(); - RaceLogTrackingInfoDTO raceLogTrackingInfo = new RaceLogTrackingInfoDTO(raceLogTrackerExists, + final boolean raceLogTrackerExists = raceLog == null ? false : getService().getRaceTrackerById(raceLog.getId()) != null; + final boolean competitorRegistrationsExist = raceLog == null ? false : !Util.isEmpty(raceColumn.getAllCompetitors(fleet)); + final RaceLogTrackingInfoDTO raceLogTrackingInfo = new RaceLogTrackingInfoDTO(raceLogTrackerExists, competitorRegistrationsExist, raceLogTrackingState); raceColumnDTO.setRaceLogTrackingInfo(fleetDTO, raceLogTrackingInfo); } @@ -4869,7 +4865,7 @@ public class SailingServiceImpl extends ProxiedRemoteServiceServlet implements S } @Override - public void setTrackingTimes(RaceLogSetTrackingTimesDTO dto) { + public void setTrackingTimes(RaceLogSetTrackingTimesDTO dto) throws NotFoundException { RaceLog raceLog = getRaceLog(dto.leaderboardName, dto.raceColumnName, dto.fleetName); // TODO If new is null and current is not, current should be revoked. if (!Util.equalsWithNull(dto.newStartOfTracking, dto.currentStartOfTracking)) { @@ -4885,7 +4881,7 @@ public class SailingServiceImpl extends ProxiedRemoteServiceServlet implements S } @Override - public Util.Pair getTrackingTimes(String leaderboardName, String raceColumnName, String fleetName) { + public Util.Pair getTrackingTimes(String leaderboardName, String raceColumnName, String fleetName) throws NotFoundException { final RaceLog raceLog = getRaceLog(leaderboardName, raceColumnName, fleetName); final Pair times = new TrackingTimesFinder(raceLog).analyze(); return times == null ? null : new Pair(times.getA(), times.getB()); @@ -5019,16 +5015,15 @@ public class SailingServiceImpl extends ProxiedRemoteServiceServlet implements S @Override public void denoteForRaceLogTracking(String leaderboardName, - String raceColumnName, String fleetName) throws Exception { - Leaderboard leaderboard = getService().getLeaderboardByName(leaderboardName); - RaceColumn raceColumn = getService().getLeaderboardByName(leaderboardName).getRaceColumnByName(raceColumnName); - Fleet fleet = raceColumn.getFleetByName(fleetName); - + String raceColumnName, String fleetName) throws NotFoundException, NotDenotableForRaceLogTrackingException { + Leaderboard leaderboard = getService().getLeaderboardByName(leaderboardName); + RaceColumn raceColumn = getRaceColumn(leaderboardName, raceColumnName); + Fleet fleet = getFleetByName(raceColumn, fleetName); getRaceLogTrackingAdapter().denoteRaceForRaceLogTracking(getService(), leaderboard, raceColumn, fleet, null); } @Override - public void removeDenotationForRaceLogTracking(String leaderboardName, String raceColumnName, String fleetName) { + public void removeDenotationForRaceLogTracking(String leaderboardName, String raceColumnName, String fleetName) throws NotFoundException { RaceLog raceLog = getRaceLog(leaderboardName, raceColumnName, fleetName); getRaceLogTrackingAdapter().removeDenotationForRaceLogTracking(getService(), raceLog); } @@ -5042,8 +5037,9 @@ public class SailingServiceImpl extends ProxiedRemoteServiceServlet implements S /** * @param triple leaderboard and racecolumn and fleet names * @return + * @throws NotFoundException */ - private RaceLog getRaceLog(com.sap.sse.common.Util.Triple triple) { + private RaceLog getRaceLog(com.sap.sse.common.Util.Triple triple) throws NotFoundException { return getRaceLog(triple.getA(), triple.getB(), triple.getC()); } @@ -5055,9 +5051,9 @@ public class SailingServiceImpl extends ProxiedRemoteServiceServlet implements S return ((HasRegattaLike) l).getRegattaLike().getRegattaLog(); } - private RaceLog getRaceLog(String leaderboardName, String raceColumnName, String fleetName) { - RaceColumn raceColumn = getService().getLeaderboardByName(leaderboardName).getRaceColumnByName(raceColumnName); - Fleet fleet = raceColumn.getFleetByName(fleetName); + private RaceLog getRaceLog(String leaderboardName, String raceColumnName, String fleetName) throws NotFoundException { + RaceColumn raceColumn = getRaceColumn(leaderboardName, raceColumnName); + Fleet fleet = getFleetByName(raceColumn, fleetName); return raceColumn.getRaceLog(fleet); } @@ -5067,26 +5063,54 @@ public class SailingServiceImpl extends ProxiedRemoteServiceServlet implements S @Override public void setCompetitorRegistrationsInRaceLog(String leaderboardName, String raceColumnName, String fleetName, - Set competitorDTOs) { - RaceLog raceLog = getRaceLog(leaderboardName, raceColumnName, fleetName); - Set competitors = new HashSet(); + Set competitorDTOs) throws CompetitorRegistrationOnRaceLogDisabledException, NotFoundException { + Set competitorsToRegister = new HashSet(); for (CompetitorDTO dto : competitorDTOs) { - competitors.add(getCompetitor(dto)); + competitorsToRegister.add(getCompetitor(dto)); } - getRaceLogTrackingAdapter().registerCompetitors(getService(), raceLog, competitors); + RaceColumn raceColumn = getRaceColumn(leaderboardName, raceColumnName); + Fleet fleet = getFleetByName(raceColumn, fleetName); + Iterable competitorsToRemove = raceColumn.getCompetitorsRegisteredInRacelog(fleet); + HashSet competitorSetToRemove = new HashSet<>(); + Util.addAll(competitorsToRemove, competitorSetToRemove); + filterDuplicates(competitorsToRegister, competitorSetToRemove); + + raceColumn.deregisterCompetitors(competitorSetToRemove, fleet); + raceColumn.registerCompetitors(competitorsToRegister, fleet); } @Override public void setCompetitorRegistrationsInRegattaLog(String leaderboardName, Set competitorDTOs) - throws DoesNotHaveRegattaLogException { - RegattaLog regattaLog = getRegattaLogInternal(leaderboardName); - Set competitors = new HashSet(); - for (CompetitorDTO dto : competitorDTOs) { - competitors.add(getCompetitor(dto)); + throws DoesNotHaveRegattaLogException, NotFoundException { + Leaderboard leaderboard = getLeaderboardByName(leaderboardName); + if (!(leaderboard instanceof HasRegattaLike)){ + throw new DoesNotHaveRegattaLogException(); } - getRaceLogTrackingAdapter().registerCompetitors(getService(), regattaLog, competitors); + Set competitorsToRegister = new HashSet(); + for (CompetitorDTO dto : competitorDTOs) { + competitorsToRegister.add(getCompetitor(dto)); + } + + HasRegattaLike hasRegattaLike = (HasRegattaLike) leaderboard; + Iterable competitorsToRemove = leaderboard.getAllCompetitors(); + HashSet competitorSetToRemove = new HashSet<>(); + Util.addAll(competitorsToRemove, competitorSetToRemove); + filterDuplicates(competitorsToRegister, competitorSetToRemove); + + hasRegattaLike.deregisterCompetitors(competitorSetToRemove); + hasRegattaLike.registerCompetitors(competitorsToRegister); + } + + private HashSet filterDuplicates(Set competitorsToRegister, HashSet competitorSetToRemove) { + for (Iterator iterator = competitorSetToRemove.iterator(); iterator.hasNext();) { + Competitor competitor = iterator.next(); + if (competitorsToRegister.remove(competitor)) { + iterator.remove(); + } + } + return competitorSetToRemove; } private Mark convertToMark(MarkDTO dto, boolean resolve) { @@ -5101,88 +5125,53 @@ public class SailingServiceImpl extends ProxiedRemoteServiceServlet implements S } /** - * Also finds the last position of the marks, if set by pinging them + * Also finds the last position of the marks if set by pinging them as long as currently a {@link TrackedRace} exists + * whose tracking interval spans the current time. If at least a non-spanning {@link TrackedRace} can be found in the + * scope of the leaderboard, the time-wise closest position fix for the mark will be used as its position. + * If the mark has been pinged through the {@link RegattaLog} but no {@link TrackedRace} exists that has loaded that ping, + * the ping won't be visible to this API. */ - private Collection convertToMarkDTOs(LeaderboardThatHasRegattaLike leaderboard, RaceLog raceLog, Iterable marks) { - List dtos = new ArrayList(); + private MarkDTO convertToMarkDTO(LeaderboardThatHasRegattaLike leaderboard, Mark mark) { final TimePoint now = MillisecondsTimePoint.now(); - for (Mark mark : marks) { - final Position lastPos = getService().getMarkPosition(mark, leaderboard, now, raceLog); - dtos.add(convertToMarkDTO(mark, lastPos)); - } - return dtos; + final Position lastPos = getService().getMarkPosition(mark, leaderboard, now); + return convertToMarkDTO(mark, lastPos); } @Override - public void addMarkToRaceLog(String leaderboardName, String raceColumnName, String fleetName, MarkDTO markDTO) { + public void addMarkToRegattaLog(String leaderboardName, MarkDTO markDTO) throws DoesNotHaveRegattaLogException { Mark mark = convertToMark(markDTO, false); - RaceLog raceLog = getRaceLog(leaderboardName, raceColumnName, fleetName); - RaceLogEvent event = new RaceLogDefineMarkEventImpl(MillisecondsTimePoint.now(), - getService().getServerAuthor(), raceLog.getCurrentPassId(), mark); - raceLog.add(event); + + RegattaLog regattaLog = getRegattaLogInternal(leaderboardName); + RegattaLogDefineMarkEventImpl event = new RegattaLogDefineMarkEventImpl(MillisecondsTimePoint.now(), + getService().getServerAuthor(), MillisecondsTimePoint.now(), UUID.randomUUID(), mark); + regattaLog.add(event); } @Override - public void revokeMarkDefinitionEventInRaceLog(String leaderboardName, String raceColumnName, String fleetName, MarkDTO markDTO) { - RaceLog raceLog = getRaceLog(leaderboardName, raceColumnName, fleetName); + public void revokeMarkDefinitionEventInRegattaLog(String leaderboardName, MarkDTO markDTO) throws DoesNotHaveRegattaLogException { + RegattaLog regattaLog = getRegattaLogInternal(leaderboardName); - final List raceLogDeviceMarkMappingEvents = new AllEventsOfTypeFinder<>(raceLog, /* only unrevoked */ true, RaceLogDefineMarkEvent.class).analyze(); + final List regattaLogDeviceMarkMappingEvents = new AllEventsOfTypeFinder<>(regattaLog, /* only unrevoked */ true, RegattaLogDefineMarkEvent.class).analyze(); - RaceLogEvent eventToRevoke = null; - for (RaceLogEvent event : raceLogDeviceMarkMappingEvents) { - RaceLogDefineMarkEvent defineMarkEvent = (RaceLogDefineMarkEvent) event; + RegattaLogEvent eventToRevoke = null; + for (RegattaLogEvent event : regattaLogDeviceMarkMappingEvents) { + RegattaLogDefineMarkEvent defineMarkEvent = (RegattaLogDefineMarkEvent) event; if (defineMarkEvent.getMark().getId().toString().equals(markDTO.getIdAsString())){ eventToRevoke = event; } } if (eventToRevoke != null){ - RaceLogEvent event = new RaceLogRevokeEventImpl(getService().getServerAuthor(), raceLog.getCurrentPassId(), eventToRevoke, "Revoked by AdminConsole (RaceLogTracking)"); - raceLog.add(event); + RegattaLogEvent event = new RegattaLogRevokeEventImpl(getService().getServerAuthor(), eventToRevoke, "Revoked by AdminConsole (RaceLogTracking)"); + regattaLog.add(event); } else { - logger.warning("Could not revoke event for mark "+markDTO.getIdAsString()+". Mark not found in RaceLog."); + logger.warning("Could not revoke event for mark "+markDTO.getIdAsString()+". Mark not found in RegattaLog."); } } - - @Override - public Iterable getMarksInRaceLog(String leaderboardName, String raceColumnName, String fleetName) { - RaceLog raceLog = getRaceLog(leaderboardName, raceColumnName, fleetName); - Iterable marks = new RaceLogDefinedMarkFinder(raceLog).analyze(); - return convertToMarkDTOs((LeaderboardThatHasRegattaLike) getService().getLeaderboardByName(leaderboardName), raceLog, marks); - } - - @Override - public Iterable getMarksInRaceLogsAndTrackedRaces(String leaderboardName) { - Leaderboard leaderboard = getService().getLeaderboardByName(leaderboardName); - if (leaderboard == null) { - // TODO: implement proper Exception Handling - return null; - } - Set markDTOs = new HashSet<>(); - Map marksById = new HashMap<>(); - for (RaceColumn raceColumn : leaderboard.getRaceColumns()) { - for (Fleet fleet : raceColumn.getFleets()) { - RaceLog raceLog = raceColumn.getRaceLog(fleet); - TrackedRace trackedRace = raceColumn.getTrackedRace(fleet); //might not yet be attached - for (Mark markDefinitionFromRaceLog : new RaceLogDefinedMarkFinder(raceLog).analyze()) { - marksById.put(markDefinitionFromRaceLog.getId(), markDefinitionFromRaceLog); - } - if (trackedRace != null) { - for (Mark markFromTrackedRace : trackedRace.getMarks()) { - marksById.put(markFromTrackedRace.getId(), markFromTrackedRace); - } - } - Util.addAll(convertToMarkDTOs( - (LeaderboardThatHasRegattaLike) getService().getLeaderboardByName(leaderboardName), - raceLog, marksById.values()), markDTOs); - } - } - return markDTOs; - } @Override public void addCourseDefinitionToRaceLog(String leaderboardName, String raceColumnName, String fleetName, - List> courseDTO) { + List> courseDTO) throws NotFoundException { RaceLog raceLog = getRaceLog(leaderboardName, raceColumnName, fleetName); String name = String.format("Course for %s - %s - %s", leaderboardName, raceColumnName, fleetName); @@ -5251,7 +5240,7 @@ public class SailingServiceImpl extends ProxiedRemoteServiceServlet implements S } @Override - public RaceCourseDTO getLastCourseDefinitionInRaceLog(final String leaderboardName, String raceColumnName, String fleetName) { + public RaceCourseDTO getLastCourseDefinitionInRaceLog(final String leaderboardName, String raceColumnName, String fleetName) throws NotFoundException { final RaceLog raceLog = getRaceLog(leaderboardName, raceColumnName, fleetName); CourseBase lastPublishedCourse = new LastPublishedCourseDesignFinder(raceLog).analyze(); if (lastPublishedCourse == null) { @@ -5260,26 +5249,26 @@ public class SailingServiceImpl extends ProxiedRemoteServiceServlet implements S return convertToRaceCourseDTO(lastPublishedCourse, new MarkPositionFinder() { @Override public Position find(Mark mark, TimePoint at) { - return getService().getMarkPosition(mark, (LeaderboardThatHasRegattaLike) getService().getLeaderboardByName(leaderboardName), at, raceLog); + return getService().getMarkPosition(mark, (LeaderboardThatHasRegattaLike) getService().getLeaderboardByName(leaderboardName), at); } }, /* timePoint */ MillisecondsTimePoint.now()); } @Override - public void pingMarkViaRaceLogTracking(String leaderboardName, String raceColumnName, String fleetName, - MarkDTO markDTO, Position positionDTO) { - RaceLog raceLog = getRaceLog(leaderboardName, raceColumnName, fleetName); + public void pingMark(String leaderboardName, + MarkDTO markDTO, Position positionDTO) throws DoesNotHaveRegattaLogException { + RegattaLog regattaLog = getRegattaLogInternal(leaderboardName); Mark mark = convertToMark(markDTO, true); TimePoint time = MillisecondsTimePoint.now(); Position position = positionDTO; GPSFix fix = new GPSFixImpl(position, time); - getRaceLogTrackingAdapter().pingMark(raceLog, mark, fix, getService()); + getRaceLogTrackingAdapter().pingMark(regattaLog, mark, fix, getService()); } @Override public void copyCourseToOtherRaceLogs(com.sap.sse.common.Util.Triple fromTriple, - Set> toTriples) { + Set> toTriples) throws NotFoundException { RaceLog fromRaceLog = getRaceLog(fromTriple); Set toRaceLogs = new HashSet<>(); for (com.sap.sse.common.Util.Triple toTriple : toTriples) { @@ -5290,13 +5279,15 @@ public class SailingServiceImpl extends ProxiedRemoteServiceServlet implements S @Override public void copyCompetitorsToOtherRaceLogs(com.sap.sse.common.Util.Triple fromTriple, - Set> toTriples) { - RaceLog fromRaceLog = getRaceLog(fromTriple); - Set toRaceLogs = new HashSet<>(); + Set> toTriples) throws NotFoundException { + final RaceColumn raceColumn = getRaceColumn(fromTriple.getA(), fromTriple.getB()); + final Set> toRaces = new HashSet<>(); for (com.sap.sse.common.Util.Triple toTriple : toTriples) { - toRaceLogs.add(getRaceLog(toTriple)); + final RaceColumn toRaceColumn = getRaceColumn(toTriple.getA(), toTriple.getB()); + final Fleet toFleet = getFleetByName(toRaceColumn, toTriple.getC()); + toRaces.add(new Pair<>(toRaceColumn, toFleet)); } - getRaceLogTrackingAdapter().copyCompetitors(fromRaceLog, toRaceLogs, getService()); + getRaceLogTrackingAdapter().copyCompetitors(raceColumn, getFleetByName(raceColumn, fromTriple.getC()), toRaces); } private TypeBasedServiceFinder getDeviceIdentifierStringSerializerHandlerFinder( @@ -5352,7 +5343,7 @@ public class SailingServiceImpl extends ProxiedRemoteServiceServlet implements S } private List> getLogHierarchy(String leaderboardName, String raceColumnName, - String fleetName) { + String fleetName) throws NotFoundException { List> result = new ArrayList<>(); RaceLog raceLog = getRaceLog(leaderboardName, raceColumnName, fleetName); @@ -5360,28 +5351,22 @@ public class SailingServiceImpl extends ProxiedRemoteServiceServlet implements S result.add(raceLog); } - Leaderboard leaderboard = getService().getLeaderboardByName(leaderboardName); + Leaderboard leaderboard = getLeaderboardByName(leaderboardName); if (leaderboard instanceof HasRegattaLike) { result.add(((HasRegattaLike) leaderboard).getRegattaLike().getRegattaLog()); } return result; } - private List getDeviceMappingsFromLogs(List> logs) + private List getDeviceMappings(RegattaLog regattaLog) throws TransformationException { List result = new ArrayList(); - for (List> list : new MultiLogAnalyzer<>( - new DeviceCompetitorMappingFinder.Factory(), - new MultiLogAnalyzer.MapWithValueCollectionReducer, List>>(), - logs).analyze().values()) { + for (List> list : new RegattaLogDeviceCompetitorMappingFinder(regattaLog).analyze().values()) { for (DeviceMapping mapping : list) { result.add(convertToDeviceMappingDTO(mapping)); } } - for (List> list : new MultiLogAnalyzer<>( - new DeviceMarkMappingFinder.Factory(), - new MultiLogAnalyzer.MapWithValueCollectionReducer, List>>(), - logs).analyze().values()) { + for (List> list : new RegattaLogDeviceMarkMappingFinder(regattaLog).analyze().values()) { for (DeviceMapping mapping : list) { result.add(convertToDeviceMappingDTO(mapping)); } @@ -5389,43 +5374,6 @@ public class SailingServiceImpl extends ProxiedRemoteServiceServlet implements S return result; } - @Override - public List getDeviceMappingsFromLogHierarchy(String leaderboardName, String raceColumnName, - String fleetName) throws TransformationException { - return getDeviceMappingsFromLogs(getLogHierarchy(leaderboardName, raceColumnName, fleetName)); - } - - @Override - public List getDeviceMappingsFromRaceLog(String leaderboardName, String raceColumnName, - String fleetName) throws TransformationException { - RaceLog raceLog = getRaceLog(leaderboardName, raceColumnName, fleetName); - return getDeviceMappingsFromLogs(Collections.>singletonList(raceLog)); - } - - @Override - public void addDeviceMappingToRaceLog(String leaderboardName, String raceColumnName, String fleetName, - DeviceMappingDTO dto) throws NoCorrespondingServiceRegisteredException, TransformationException { - RaceLog raceLog = getRaceLog(leaderboardName, raceColumnName, fleetName); - DeviceMapping mapping = convertToDeviceMapping(dto); - TimePoint now = MillisecondsTimePoint.now(); - RaceLogEvent event = null; - TimePoint from = mapping.getTimeRange().hasOpenBeginning() ? null : mapping.getTimeRange().from(); - TimePoint to = mapping.getTimeRange().hasOpenEnd() ? null : mapping.getTimeRange().to(); - if (dto.mappedTo instanceof MarkDTO) { - Mark mark = convertToMark(((MarkDTO) dto.mappedTo), true); - event = new RaceLogDeviceMarkMappingEventImpl(now, getService().getServerAuthor(), - raceLog.getCurrentPassId(), mark, mapping.getDevice(), from, to); - } else if (dto.mappedTo instanceof CompetitorDTO) { - Competitor competitor = getService().getCompetitorStore().getExistingCompetitorByIdAsString( - ((CompetitorDTO) dto.mappedTo).getIdAsString()); - event = new RaceLogDeviceCompetitorMappingEventImpl(now, getService().getServerAuthor(), - raceLog.getCurrentPassId(), competitor, mapping.getDevice(), from, to); - } else { - throw new RuntimeException("Can only map devices to competitors or marks"); - } - raceLog.add(event); - } - @Override public void addDeviceMappingToRegattaLog(String leaderboardName, DeviceMappingDTO dto) throws NoCorrespondingServiceRegisteredException, TransformationException, DoesNotHaveRegattaLogException { @@ -5477,50 +5425,35 @@ public class SailingServiceImpl extends ProxiedRemoteServiceServlet implements S throw new RuntimeException("Can only map devices to competitors or marks"); } } - - @Override - public void closeOpenEndedDeviceMapping(String leaderboardName, String raceColumnName, String fleetName, - DeviceMappingDTO mappingDTO, Date closingTimePoint) throws NoCorrespondingServiceRegisteredException, TransformationException { - List> logHierarchy = getLogHierarchy(leaderboardName, raceColumnName, fleetName); - closeOpenEndedDeviceMapping(logHierarchy, mappingDTO, closingTimePoint); - } - private void closeOpenEndedDeviceMapping(List> logHierarchy, DeviceMappingDTO mappingDTO, Date closingTimePoint) throws TransformationException { - for (AbstractLog abstractLog : logHierarchy) { - //check if abstractLog is the correct log for the closingEvent - final AbstractLogEvent event; - abstractLog.lockForRead(); - try { - event = abstractLog.getEventById(mappingDTO.originalRaceLogEventIds.get(0)); - } finally { - abstractLog.unlockAfterRead(); - } + private void closeOpenEndedDeviceMapping(RegattaLog regattaLog, DeviceMappingDTO mappingDTO, Date closingTimePoint) throws TransformationException, UnableToCloseDeviceMappingException { + boolean successfullyClosed = false; + regattaLog.lockForRead(); + try { + RegattaLogEvent event = regattaLog.getEventById(mappingDTO.originalRaceLogEventIds.get(0)); + if (event != null) { + successfullyClosed = true; DeviceMapping mapping = convertToDeviceMapping(mappingDTO); - if (abstractLog instanceof RegattaLog) { - RegattaLog regattaLog = (RegattaLog) abstractLog; - List closingEvents = - new RegattaLogOpenEndedDeviceMappingCloser(regattaLog, mapping, getService().getServerAuthor(), - new MillisecondsTimePoint(closingTimePoint)).analyze(); - for (RegattaLogEvent closingEvent : closingEvents) { - regattaLog.add(closingEvent); - } - } else if (abstractLog instanceof RaceLog) { - RaceLog raceLog = (RaceLog) abstractLog; - List closingEvents = - new RaceLogOpenEndedDeviceMappingCloser(raceLog, mapping, getService().getServerAuthor(), - new MillisecondsTimePoint(closingTimePoint)).analyze(); - for (RaceLogEvent closingEvent : closingEvents) { - raceLog.add(closingEvent); - } + List closingEvents = + new RegattaLogOpenEndedDeviceMappingCloser(regattaLog, mapping, getService().getServerAuthor(), + new MillisecondsTimePoint(closingTimePoint)).analyze(); + for (RegattaLogEvent closingEvent : closingEvents) { + regattaLog.add(closingEvent); } } + } finally { + regattaLog.unlockAfterRead(); + } + + if (!successfullyClosed){ + throw new UnableToCloseDeviceMappingException(); } } @Override public void revokeRaceAndRegattaLogEvents(String leaderboardName, String raceColumnName, String fleetName, - List eventIds) throws NotRevokableException { + List eventIds) throws NotRevokableException, NotFoundException { List> logs = getLogHierarchy(leaderboardName, raceColumnName, fleetName); revokeEventsFromLogs(logs, eventIds); } @@ -5564,7 +5497,7 @@ public class SailingServiceImpl extends ProxiedRemoteServiceServlet implements S @Override public void startRaceLogTracking(String leaderboardName, String raceColumnName, String fleetName, final boolean trackWind, final boolean correctWindByDeclination) throws NotDenotedForRaceLogTrackingException, Exception { - Leaderboard leaderboard = getService().getLeaderboardByName(leaderboardName); + Leaderboard leaderboard = getLeaderboardByName(leaderboardName); RaceColumn raceColumn = leaderboard.getRaceColumnByName(raceColumnName); Fleet fleet = raceColumn.getFleetByName(fleetName); final RaceHandle raceHandle = getRaceLogTrackingAdapter().startTracking(getService(), leaderboard, raceColumn, fleet); @@ -5883,101 +5816,64 @@ public class SailingServiceImpl extends ProxiedRemoteServiceServlet implements S } return result; } - - @Override - public List getDeviceMappingsFromLogHierarchy(String leaderboardName) throws TransformationException { - List> logs = getLogHierarchy(leaderboardName); - return getDeviceMappingsFromLogs(logs); - } /** - * Gets all Marks defined in the RaceLogs of the RaceColumns corresponding to the leaderboard leaderboardName + * Gets all Marks defined in the RegattaLog and the trackedRace + * @throws DoesNotHaveRegattaLogException */ @Override - public Iterable getMarksInRegattaLog(String leaderboardName) { - Leaderboard leaderboard = getService().getLeaderboardByName(leaderboardName); - if (leaderboard == null) { - // TODO: implement proper Exception Handling - return null; + public Iterable getMarksInRegattaLog(String leaderboardName) throws DoesNotHaveRegattaLogException { + final Leaderboard l = getService().getLeaderboardByName(leaderboardName); + if (! (l instanceof HasRegattaLike)) { + throw new DoesNotHaveRegattaLogException(); } - - if (!(leaderboard instanceof IsRegattaLike)){ - return null; - } - - Set markDTOs = new HashSet<>(); - - Map marksById = new HashMap<>(); - for (RaceColumn raceColumn : leaderboard.getRaceColumns()) { - for (Fleet fleet : raceColumn.getFleets()) { - RaceLog raceLog = raceColumn.getRaceLog(fleet); - TrackedRace trackedRace = raceColumn.getTrackedRace(fleet); //might not yet be attached - - if (trackedRace != null) { - for (Mark markFromTrackedRace : trackedRace.getMarks()) { - marksById.put(markFromTrackedRace.getId(), markFromTrackedRace); - } - } - Util.addAll(convertToMarkDTOs( - (LeaderboardThatHasRegattaLike) getService().getLeaderboardByName(leaderboardName), - raceLog, marksById.values()), markDTOs); - } + final LeaderboardThatHasRegattaLike leaderboard = (LeaderboardThatHasRegattaLike) l; + final RegattaLog regattaLog = leaderboard.getRegattaLike().getRegattaLog(); + final Set markDTOs = new HashSet<>(); + final List markEvents = new AllEventsOfTypeFinder<>(regattaLog, /* only unrevoked */ true, RegattaLogDefineMarkEvent.class).analyze(); + for (RegattaLogEvent regattaLogEvent : markEvents) { + final RegattaLogDefineMarkEvent defineMarkEvent = (RegattaLogDefineMarkEvent) regattaLogEvent; + markDTOs.add(convertToMarkDTO(leaderboard, defineMarkEvent.getMark())); } return markDTOs; } @Override - public Collection getCompetitorRegistrationsInRegattaLog(String leaderboardName) throws DoesNotHaveRegattaLogException { - return convertToCompetitorDTOs( - new RegisteredCompetitorsAnalyzer<>( - getRegattaLogInternal(leaderboardName)).analyze()); + public void closeOpenEndedDeviceMapping(String leaderboardName, DeviceMappingDTO mappingDTO, Date closingTimePoint) throws TransformationException, DoesNotHaveRegattaLogException, UnableToCloseDeviceMappingException { + RegattaLog regattaLog = getRegattaLogInternal(leaderboardName); + closeOpenEndedDeviceMapping(regattaLog, mappingDTO, closingTimePoint); } - @Override - public void closeOpenEndedDeviceMapping(String leaderboardName, DeviceMappingDTO mappingDTO, Date closingTimePoint) throws TransformationException { - List> logs = getLogHierarchy(leaderboardName); - closeOpenEndedDeviceMapping(logs, mappingDTO, closingTimePoint); - } - - /** * Gets all the logs corresponding to a leaderboard. This includes all the RaceLogs of the leaderBoard's raceColumns * @param leaderboardName * @return */ private List> getLogHierarchy(String leaderboardName) { - List> result = new ArrayList<>(); - + final List> result; Leaderboard leaderboard = getService().getLeaderboardByName(leaderboardName); if (leaderboard == null) { - return null; - } - - if (leaderboard instanceof HasRegattaLike) { - result.add(((HasRegattaLike) leaderboard).getRegattaLike().getRegattaLog()); - } - - for (RaceColumn raceColumn : leaderboard.getRaceColumns()) { - for (Fleet fleet : raceColumn.getFleets()) { - RaceLog raceLog = raceColumn.getRaceLog(fleet); - result.add(raceLog); + result = null; + } else { + result = new ArrayList<>(); + if (leaderboard instanceof HasRegattaLike) { + result.add(((HasRegattaLike) leaderboard).getRegattaLike().getRegattaLog()); + } + for (RaceColumn raceColumn : leaderboard.getRaceColumns()) { + for (Fleet fleet : raceColumn.getFleets()) { + RaceLog raceLog = raceColumn.getRaceLog(fleet); + result.add(raceLog); + } } } - return result; } public boolean doesRegattaLogContainCompetitors(String leaderboardName) throws DoesNotHaveRegattaLogException { RegattaLog regattaLog = getRegattaLogInternal(leaderboardName); - - List markEvents = new AllEventsOfTypeFinder<>(regattaLog, /* only unrevoked */ true, RegattaLogRegisterCompetitorEvent.class) - .analyze(); - - if (markEvents.isEmpty()){ - return false; - } else { - return true; - } + List comeptitorRegistrationEvents = new AllEventsOfTypeFinder<>(regattaLog, + /* only unrevoked */ true, RegattaLogRegisterCompetitorEvent.class).analyze(); + return !comeptitorRegistrationEvents.isEmpty(); } @Override @@ -6000,24 +5896,129 @@ public class SailingServiceImpl extends ProxiedRemoteServiceServlet implements S } @Override - public Collection getCompetitorRegistrationsFromLogHierarchy(String leaderboardName) { - List> logHierarchy = getLogHierarchy(leaderboardName); - - Collection competitorRegistrations = new ArrayList(); - - for (AbstractLog abstractLog : logHierarchy) { - competitorRegistrations.addAll(convertToCompetitorDTOs( - new RegisteredCompetitorsAnalyzer<>( - abstractLog).analyze())); - } - - return competitorRegistrations; + public Collection getCompetitorRegistrationsForRace(String leaderboardName, String raceColumnName, + String fleetName) throws NotFoundException { + RaceColumn raceColumn = getRaceColumn(leaderboardName, raceColumnName); + Fleet fleet = getFleetByName(raceColumn, fleetName); + return convertToCompetitorDTOs(raceColumn.getAllCompetitors(fleet)); + } + + @Override + public Collection getCompetitorRegistrationsForLeaderboard(String leaderboardName) throws NotFoundException { + Leaderboard leaderboard = getLeaderboardByName(leaderboardName); + return convertToCompetitorDTOs(leaderboard.getAllCompetitors()); } @Override - public Collection getCompetitorRegistrationsOnRaceLog(String leaderboardName, String raceColumnName, - String fleetName) { - RaceLog raceLog = getRaceLog(leaderboardName, raceColumnName, fleetName); - return convertToCompetitorDTOs(new RegisteredCompetitorsAnalyzer<>(raceLog).analyze()); + public Collection getCompetitorRegistrationsInRegattaLog(String leaderboardName) throws DoesNotHaveRegattaLogException, NotFoundException { + Leaderboard leaderboard = getLeaderboardByName(leaderboardName); + if (! (leaderboard instanceof HasRegattaLike)) { + throw new DoesNotHaveRegattaLogException(); + } + HasRegattaLike regattaLikeLeaderboard = ((HasRegattaLike) leaderboard); + return convertToCompetitorDTOs(regattaLikeLeaderboard.getCompetitorsRegisteredInRegattaLog()); + } + + @Override + public Collection getCompetitorRegistrationsInRaceLog(String leaderboardName, String raceColumnName, + String fleetName) throws NotFoundException { + RaceColumn raceColumn = getRaceColumn(leaderboardName, raceColumnName); + Fleet fleet = getFleetByName(raceColumn, fleetName); + return convertToCompetitorDTOs(raceColumn.getCompetitorsRegisteredInRacelog(fleet)); + } + + @Override + public Boolean areCompetitorRegistrationsEnabledForRace(String leaderboardName, String raceColumnName, + String fleetName) throws NotFoundException { + RaceColumn raceColumn = getRaceColumn(leaderboardName, raceColumnName); + Fleet fleet = getFleetByName(raceColumn, fleetName); + return raceColumn.isCompetitorRegistrationInRacelogEnabled(fleet); + } + + private Fleet getFleetByName(RaceColumn raceColumn, String fleetName) throws NotFoundException{ + Fleet fleet = raceColumn.getFleetByName(fleetName); + if (fleet == null){ + throw new NotFoundException("fleet with name "+fleetName+" not found"); + } + return fleet; + } + + private Leaderboard getLeaderboardByName(String leaderboardName) throws NotFoundException{ + Leaderboard leaderboard = getService().getLeaderboardByName(leaderboardName); + if (leaderboard == null){ + throw new NotFoundException("Leaderboard with name "+leaderboardName+" not found"); + } + return leaderboard; + } + + private RaceColumn getRaceColumn(String leaderboardName, String raceColumnName) throws NotFoundException{ + Leaderboard leaderboard = getService().getLeaderboardByName(leaderboardName); + if (leaderboard == null){ + throw new NotFoundException("leaderboard with name "+leaderboardName+" not found"); + } + RaceColumn raceColumn = leaderboard.getRaceColumnByName(raceColumnName); + if (raceColumn == null){ + throw new NotFoundException("raceColumn with name "+raceColumnName+" not found"); + } + return raceColumn; + } + + @Override + public void disableCompetitorRegistrationsForRace(String leaderboardName, String raceColumnName, String fleetName) throws NotRevokableException, NotFoundException { + if (areCompetitorRegistrationsEnabledForRace(leaderboardName, raceColumnName, fleetName)){ + RaceColumn raceColumn = getRaceColumn(leaderboardName, raceColumnName); + raceColumn.disableCompetitorRegistrationOnRaceLog(getFleetByName(raceColumn, fleetName)); + } + } + + @Override + public void enableCompetitorRegistrationsForRace(String leaderboardName, String raceColumnName, String fleetName) throws IllegalArgumentException, NotFoundException { + if (!areCompetitorRegistrationsEnabledForRace(leaderboardName, raceColumnName, fleetName)){ + RaceColumn raceColumn = getRaceColumn(leaderboardName, raceColumnName); + raceColumn.enableCompetitorRegistrationOnRaceLog(getFleetByName(raceColumn, fleetName)); + } + } + + @Override + public Pair checkIfMarksAreUsedInOtherRaceLogs(String leaderboardName, String raceColumnName, + String fleetName, Set marksToRemove) throws NotFoundException { + Set markIds = new HashSet(); + for (MarkDTO markDTO : marksToRemove) { + markIds.add(markDTO.getIdAsString()); + } + RaceLog raceLogToIgnore = getRaceLog(leaderboardName, raceColumnName, fleetName); + HashSet racesContainingMarksToDeleteInCourse = new HashSet(); + boolean marksAreUsedInOtherRaceLogs = false; + Leaderboard leaderboard = getService().getLeaderboardByName(leaderboardName); + for (RaceColumn raceColumn : leaderboard.getRaceColumns()) { + for (Fleet fleet : raceColumn.getFleets()) { + RaceLog raceLog = raceColumn.getRaceLog(fleet); + if (raceLog != raceLogToIgnore) { + LastPublishedCourseDesignFinder finder = new LastPublishedCourseDesignFinder(raceLog); + CourseBase course = finder.analyze(); + for (Waypoint waypoint: course.getWaypoints()) { + for (Mark mark : waypoint.getMarks()) { + if (markIds.contains(mark.getId().toString())) { + racesContainingMarksToDeleteInCourse.add(raceColumn.getName()+"/"+fleet.getName()); + marksAreUsedInOtherRaceLogs = true; + } + } + } + } + } + } + StringBuilder racesInCollision = new StringBuilder(); + for (String raceName : racesContainingMarksToDeleteInCourse) { + racesInCollision.append(raceName+", "); + } + return new Pair(marksAreUsedInOtherRaceLogs, + racesInCollision.substring(0, Math.max(0, racesInCollision.length()-2))); + } + + @Override + public List getDeviceMappings(String leaderboardName) + throws DoesNotHaveRegattaLogException, TransformationException { + RegattaLog regattaLog = getRegattaLogInternal(leaderboardName); + return getDeviceMappings(regattaLog); } } diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/DeviceIdentifierDTO.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/DeviceIdentifierDTO.java index db78ebe5c78..c48a5bcf3e6 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/DeviceIdentifierDTO.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/DeviceIdentifierDTO.java @@ -13,6 +13,37 @@ public class DeviceIdentifierDTO implements IsSerializable { this.deviceId = deviceId; } + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + ((deviceId == null) ? 0 : deviceId.hashCode()); + result = prime * result + ((deviceType == null) ? 0 : deviceType.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; + DeviceIdentifierDTO other = (DeviceIdentifierDTO) obj; + if (deviceId == null) { + if (other.deviceId != null) + return false; + } else if (!deviceId.equals(other.deviceId)) + return false; + if (deviceType == null) { + if (other.deviceType != null) + return false; + } else if (!deviceType.equals(other.deviceType)) + return false; + return true; + } + public String toString() { return deviceType + " - " + deviceId; } diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/DeviceMappingDTO.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/DeviceMappingDTO.java index 3519a98220f..0bf58858a2e 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/DeviceMappingDTO.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/DeviceMappingDTO.java @@ -24,4 +24,53 @@ public class DeviceMappingDTO implements IsSerializable { this.mappedTo = mappedTo; this.originalRaceLogEventIds = originalRaceLogEventIds; } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + ((deviceIdentifier == null) ? 0 : deviceIdentifier.hashCode()); + result = prime * result + ((from == null) ? 0 : from.hashCode()); + result = prime * result + ((mappedTo == null) ? 0 : mappedTo.hashCode()); + result = prime * result + ((originalRaceLogEventIds == null) ? 0 : originalRaceLogEventIds.hashCode()); + result = prime * result + ((to == null) ? 0 : to.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; + DeviceMappingDTO other = (DeviceMappingDTO) obj; + if (deviceIdentifier == null) { + if (other.deviceIdentifier != null) + return false; + } else if (!deviceIdentifier.equals(other.deviceIdentifier)) + return false; + if (from == null) { + if (other.from != null) + return false; + } else if (!from.equals(other.from)) + return false; + if (mappedTo == null) { + if (other.mappedTo != null) + return false; + } else if (!mappedTo.equals(other.mappedTo)) + return false; + if (originalRaceLogEventIds == null) { + if (other.originalRaceLogEventIds != null) + return false; + } else if (!originalRaceLogEventIds.equals(other.originalRaceLogEventIds)) + return false; + if (to == null) { + if (other.to != null) + return false; + } else if (!to.equals(other.to)) + return false; + return true; + } } diff --git a/java/com.sap.sailing.mongodb.test/src/com/sap/sailing/mongodb/test/RaceLogMongoDBTest.java b/java/com.sap.sailing.mongodb.test/src/com/sap/sailing/mongodb/test/RaceLogMongoDBTest.java index 7c94c108303..6abadaf2984 100644 --- a/java/com.sap.sailing.mongodb.test/src/com/sap/sailing/mongodb/test/RaceLogMongoDBTest.java +++ b/java/com.sap.sailing.mongodb.test/src/com/sap/sailing/mongodb/test/RaceLogMongoDBTest.java @@ -4,6 +4,7 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; import java.net.UnknownHostException; +import java.util.Iterator; import java.util.UUID; import junit.framework.Assert; @@ -11,6 +12,8 @@ import junit.framework.Assert; import org.junit.Before; import com.mongodb.MongoException; +import com.sap.sailing.domain.abstractlog.race.CompetitorResult; +import com.sap.sailing.domain.abstractlog.race.CompetitorResults; import com.sap.sailing.domain.base.ControlPointWithTwoMarks; import com.sap.sailing.domain.base.CourseBase; import com.sap.sailing.domain.base.DomainFactory; @@ -37,6 +40,7 @@ import com.sap.sailing.domain.persistence.PersistenceFactory; import com.sap.sailing.domain.racelog.RaceLogStore; import com.sap.sailing.domain.regattalog.RegattaLogStore; import com.sap.sse.common.TimePoint; +import com.sap.sse.common.Util; public abstract class RaceLogMongoDBTest extends AbstractMongoDBTest { @@ -133,4 +137,13 @@ public abstract class RaceLogMongoDBTest extends AbstractMongoDBTest { return MongoRegattaLogStoreFactory.INSTANCE.getMongoRegattaLogStore(mongoObjectFactory, domainObjectFactory); } + public static void assertCompetitorResultsEqual(final CompetitorResults expectedCompetitorResults, final CompetitorResults loadedCompetitorResults) { + assertEquals(Util.size(expectedCompetitorResults), Util.size(loadedCompetitorResults)); + final Iterator iExpected = expectedCompetitorResults.iterator(); + final Iterator iLoaded = loadedCompetitorResults.iterator(); + while (iExpected.hasNext()) { + assertEquals(iExpected.next(), iLoaded.next()); + } + } + } diff --git a/java/com.sap.sailing.mongodb.test/src/com/sap/sailing/mongodb/test/StoreAndLoadDeviceIdentifierTest.java b/java/com.sap.sailing.mongodb.test/src/com/sap/sailing/mongodb/test/StoreAndLoadDeviceIdentifierTest.java index ccc0a758f12..a95facb58f3 100644 --- a/java/com.sap.sailing.mongodb.test/src/com/sap/sailing/mongodb/test/StoreAndLoadDeviceIdentifierTest.java +++ b/java/com.sap.sailing.mongodb.test/src/com/sap/sailing/mongodb/test/StoreAndLoadDeviceIdentifierTest.java @@ -3,10 +3,8 @@ package com.sap.sailing.mongodb.test; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; import java.net.UnknownHostException; -import java.util.UUID; import org.junit.Before; import org.junit.Test; @@ -14,9 +12,9 @@ import org.junit.Test; import com.mongodb.MongoException; 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.tracking.RaceLogDeviceCompetitorMappingEvent; -import com.sap.sailing.domain.abstractlog.race.tracking.impl.RaceLogDeviceCompetitorMappingEventImpl; +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.impl.RegattaLogDeviceCompetitorMappingEventImpl; import com.sap.sailing.domain.base.Competitor; import com.sap.sailing.domain.base.DomainFactory; import com.sap.sailing.domain.base.impl.CompetitorImpl; @@ -24,13 +22,13 @@ import com.sap.sailing.domain.common.racelog.tracking.TransformationException; import com.sap.sailing.domain.persistence.PersistenceFactory; import com.sap.sailing.domain.persistence.impl.DomainObjectFactoryImpl; import com.sap.sailing.domain.persistence.impl.MongoObjectFactoryImpl; -import com.sap.sailing.domain.persistence.impl.MongoRaceLogStoreImpl; -import com.sap.sailing.domain.racelog.RaceLogIdentifier; +import com.sap.sailing.domain.persistence.impl.MongoRegattaLogStoreImpl; import com.sap.sailing.domain.racelog.tracking.test.mock.MockEmptyServiceFinderFactory; import com.sap.sailing.domain.racelog.tracking.test.mock.MockSmartphoneImeiServiceFinderFactory; import com.sap.sailing.domain.racelog.tracking.test.mock.SmartphoneImeiIdentifier; import com.sap.sailing.domain.racelogtracking.DeviceIdentifier; import com.sap.sailing.domain.racelogtracking.PlaceHolderDeviceIdentifier; +import com.sap.sailing.domain.regattalike.RegattaLikeIdentifier; import com.sap.sailing.domain.trackfiles.TrackFileImportDeviceIdentifierImpl; import com.sap.sse.common.NoCorrespondingServiceRegisteredException; import com.sap.sse.common.TimePoint; @@ -47,11 +45,11 @@ public class StoreAndLoadDeviceIdentifierTest extends AbstractMongoDBTest { protected static final String column = "column"; protected static final String fleet = "fleet"; protected final AbstractLogEventAuthor author = new LogEventAuthorImpl("author", 0); - protected RaceLogIdentifier logIdentifier; + protected RegattaLikeIdentifier logIdentifier; protected MongoObjectFactoryImpl mongoFactory; protected DomainObjectFactoryImpl domainFactory; - protected RaceLog raceLog; + protected RegattaLog RegattaLog; private TimePoint now() { return MillisecondsTimePoint.now(); @@ -61,13 +59,11 @@ public class StoreAndLoadDeviceIdentifierTest extends AbstractMongoDBTest { public void setup() throws UnknownHostException, MongoException, InterruptedException { dropTestDB(); - logIdentifier = mock(RaceLogIdentifier.class); - com.sap.sse.common.Util.Triple triple = new com.sap.sse.common.Util.Triple("a", "b", UUID.randomUUID().toString()); - when(logIdentifier.getIdentifier()).thenReturn(triple); + logIdentifier = mock(RegattaLikeIdentifier.class); } - private RaceLog loadRaceLog() { - return new MongoRaceLogStoreImpl(mongoFactory, domainFactory).getRaceLog(logIdentifier, true); + private RegattaLog loadRegattaLog() { + return new MongoRegattaLogStoreImpl(mongoFactory, domainFactory).getRegattaLog(logIdentifier, true); } private void createFactories(TypeBasedServiceFinderFactory factory) { @@ -76,23 +72,23 @@ public class StoreAndLoadDeviceIdentifierTest extends AbstractMongoDBTest { domainFactory = (DomainObjectFactoryImpl) PersistenceFactory.INSTANCE .getDomainObjectFactory(getMongoService(), DomainFactory.INSTANCE, factory); - raceLog = loadRaceLog(); + RegattaLog = loadRegattaLog(); } private DeviceIdentifier storeAndLoad(DeviceIdentifier device, TypeBasedServiceFinderFactory forStoring, TypeBasedServiceFinderFactory forLoading) { createFactories(forStoring); Competitor c = new CompetitorImpl("a", "a", null, null, null, null, null, /* timeOnTimeFactor */ null, /* timeOnDistanceAllowancePerNauticalMile */ null); - raceLog.add(new RaceLogDeviceCompetitorMappingEventImpl(now(), author, 0, + RegattaLog.add(new RegattaLogDeviceCompetitorMappingEventImpl(now(), now(), author, 0, c, device, now(), now())); createFactories(forLoading); - RaceLog loadedRaceLog = loadRaceLog(); - loadedRaceLog.lockForRead(); - assertEquals(1, Util.size(loadedRaceLog.getRawFixes())); - RaceLogDeviceCompetitorMappingEvent mapping = (RaceLogDeviceCompetitorMappingEvent) loadedRaceLog.getRawFixes().iterator().next(); - loadedRaceLog.unlockAfterRead(); + RegattaLog loadedRegattaLog = loadRegattaLog(); + loadedRegattaLog.lockForRead(); + assertEquals(1, Util.size(loadedRegattaLog.getRawFixes())); + RegattaLogDeviceCompetitorMappingEvent mapping = (RegattaLogDeviceCompetitorMappingEvent) loadedRegattaLog.getRawFixes().iterator().next(); + loadedRegattaLog.unlockAfterRead(); return mapping.getDevice(); } diff --git a/java/com.sap.sailing.mongodb.test/src/com/sap/sailing/mongodb/test/StoreAndLoadRaceLogEventsTest.java b/java/com.sap.sailing.mongodb.test/src/com/sap/sailing/mongodb/test/StoreAndLoadRaceLogEventsTest.java index ab651c9a1b8..488ef888b67 100644 --- a/java/com.sap.sailing.mongodb.test/src/com/sap/sailing/mongodb/test/StoreAndLoadRaceLogEventsTest.java +++ b/java/com.sap.sailing.mongodb.test/src/com/sap/sailing/mongodb/test/StoreAndLoadRaceLogEventsTest.java @@ -33,22 +33,13 @@ import com.sap.sailing.domain.abstractlog.race.impl.RaceLogPassChangeEventImpl; import com.sap.sailing.domain.abstractlog.race.impl.RaceLogRaceStatusEventImpl; import com.sap.sailing.domain.abstractlog.race.impl.RaceLogRevokeEventImpl; import com.sap.sailing.domain.abstractlog.race.impl.RaceLogStartTimeEventImpl; -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.impl.RaceLogCloseOpenEndedDeviceMappingEventImpl; -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.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.base.BoatClass; import com.sap.sailing.domain.base.Competitor; import com.sap.sailing.domain.base.DomainFactory; -import com.sap.sailing.domain.base.Mark; import com.sap.sailing.domain.common.racelog.Flags; import com.sap.sailing.domain.common.racelog.RaceLogRaceStatus; import com.sap.sailing.domain.persistence.PersistenceFactory; @@ -57,8 +48,6 @@ import com.sap.sailing.domain.persistence.impl.FieldNames; import com.sap.sailing.domain.persistence.impl.MongoObjectFactoryImpl; import com.sap.sailing.domain.racelog.RaceLogIdentifier; import com.sap.sailing.domain.racelog.tracking.test.mock.MockSmartphoneImeiServiceFinderFactory; -import com.sap.sailing.domain.racelog.tracking.test.mock.SmartphoneImeiIdentifier; -import com.sap.sailing.domain.racelogtracking.DeviceIdentifier; import com.sap.sse.common.TimePoint; import com.sap.sse.common.Util; import com.sap.sse.common.impl.MillisecondsTimePoint; @@ -182,47 +171,6 @@ public class StoreAndLoadRaceLogEventsTest extends AbstractMongoDBTest { assertEquals(startTime, actualEvent.getStartTime()); } - @Test - public void testStoreAndLoadDeviceCompetitorMappingEvent() { - DeviceIdentifier device = new SmartphoneImeiIdentifier("a"); - Competitor mappedTo = DomainFactory.INSTANCE.getOrCreateCompetitor("abc", "abc", null, null, null, null, null, /* timeOnTimeFactor */ - null, /* timeOnDistanceAllowancePerNauticalMile */null); - TimePoint from = new MillisecondsTimePoint(20); - TimePoint to = new MillisecondsTimePoint(30); - RaceLogDeviceCompetitorMappingEvent expectedEvent = new RaceLogDeviceCompetitorMappingEventImpl( - expectedEventTime, expectedEventTime, author, expectedId, expectedPassId, - mappedTo, device, from, to); - - DBObject dbObject = mongoFactory.storeRaceLogEntry(logIdentifier, expectedEvent); - RaceLogDeviceCompetitorMappingEvent actualEvent = loadEvent(dbObject); - - assertBaseFields(expectedEvent, actualEvent); - assertEquals(device, actualEvent.getDevice()); - assertEquals(from, actualEvent.getFrom()); - assertEquals(to, actualEvent.getTo()); - assertEquals(mappedTo, actualEvent.getMappedTo()); - } - - @Test - public void testStoreAndLoadDeviceMarkMappingEvent() { - DeviceIdentifier device = new SmartphoneImeiIdentifier("a"); - Mark mappedTo = DomainFactory.INSTANCE.getOrCreateMark("abc", "abc"); - TimePoint from = new MillisecondsTimePoint(20); - TimePoint to = new MillisecondsTimePoint(30); - RaceLogDeviceMarkMappingEvent expectedEvent = new RaceLogDeviceMarkMappingEventImpl( - expectedEventTime, expectedEventTime, author, expectedId, expectedPassId, - mappedTo, device, from, to); - - DBObject dbObject = mongoFactory.storeRaceLogEntry(logIdentifier, expectedEvent); - RaceLogDeviceMarkMappingEvent actualEvent = loadEvent(dbObject); - - assertBaseFields(expectedEvent, actualEvent); - assertEquals(device, actualEvent.getDevice()); - assertEquals(from, actualEvent.getFrom()); - assertEquals(to, actualEvent.getTo()); - assertEquals(mappedTo, actualEvent.getMappedTo()); - } - @Test public void testStoreAndLoadDenoteForTrackingEvent() { String raceName = "race"; @@ -274,33 +222,6 @@ public class StoreAndLoadRaceLogEventsTest extends AbstractMongoDBTest { assertEquals(expectedEvent.getCompetitor(), actualEvent.getCompetitor()); } - @Test - public void testStoreAndLoadDefineMarkEvent() { - RaceLogDefineMarkEvent expectedEvent = new RaceLogDefineMarkEventImpl(MillisecondsTimePoint.now(), - expectedEventTime, author, expectedId, expectedPassId, - DomainFactory.INSTANCE.getOrCreateMark("mytestmark")); - - DBObject dbObject = mongoFactory.storeRaceLogEntry(logIdentifier, expectedEvent); - RaceLogDefineMarkEvent actualEvent = loadEvent(dbObject); - - assertBaseFields(expectedEvent, actualEvent); - assertEquals(expectedEvent.getMark(), actualEvent.getMark()); - } - - @Test - public void testStoreAndLoadCloseOpenDeviceMappingEvent() { - RaceLogCloseOpenEndedDeviceMappingEvent expectedEvent = new RaceLogCloseOpenEndedDeviceMappingEventImpl( - expectedEventTime, expectedEventTime, author, expectedId, expectedPassId, UUID.randomUUID(), - new MillisecondsTimePoint(49)); - - DBObject dbObject = mongoFactory.storeRaceLogEntry(logIdentifier, expectedEvent); - RaceLogCloseOpenEndedDeviceMappingEvent actualEvent = loadEvent(dbObject); - - assertBaseFields(expectedEvent, actualEvent); - assertEquals(expectedEvent.getDeviceMappingEventId(), actualEvent.getDeviceMappingEventId()); - assertEquals(expectedEvent.getClosingTimePoint(), actualEvent.getClosingTimePoint()); - } - /** * Will always wait a couple of milliseconds to ensure that {@link RaceLogEvent#getCreatedAt()} has passed. */ diff --git a/java/com.sap.sailing.mongodb.test/src/com/sap/sailing/mongodb/test/StoreGPSFixTrackTest.java b/java/com.sap.sailing.mongodb.test/src/com/sap/sailing/mongodb/test/StoreGPSFixTrackTest.java index c281b7d4f4c..400ab63fffd 100644 --- a/java/com.sap.sailing.mongodb.test/src/com/sap/sailing/mongodb/test/StoreGPSFixTrackTest.java +++ b/java/com.sap.sailing.mongodb.test/src/com/sap/sailing/mongodb/test/StoreGPSFixTrackTest.java @@ -12,10 +12,10 @@ import com.mongodb.DB; import com.mongodb.MongoException; 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; @@ -86,14 +86,14 @@ public class StoreGPSFixTrackTest extends AbstractMongoDBTest { DeviceIdentifier device2 = new SmartphoneImeiIdentifier("b"); store.storeFix(device2, fix4); - RaceLog raceLog = new RaceLogImpl("racelog"); - raceLog.add(new RaceLogDeviceCompetitorMappingEventImpl(time0, author, 0, comp, device1, time0, time1)); - raceLog.add(new RaceLogDeviceMarkMappingEventImpl(time0, author, 0, mark, device2, time0, time1)); + RegattaLog regattaLog = new RegattaLogImpl("racelog"); + regattaLog.add(new RegattaLogDeviceCompetitorMappingEventImpl(time0, author, comp, device1, time0, time1)); + regattaLog.add(new RegattaLogDeviceMarkMappingEventImpl(time0, author, mark, device2, time0, time1)); DynamicGPSFixMovingTrackImpl track1 = new DynamicGPSFixMovingTrackImpl<>(comp, 0); - store.loadCompetitorTrack(track1, raceLog, comp); + store.loadCompetitorTrack(track1, regattaLog, comp); DynamicGPSFixTrackImpl track2 = new DynamicGPSFixTrackImpl<>(mark, 0); - store.loadMarkTrack(track2, raceLog, mark); + store.loadMarkTrack(track2, regattaLog, mark); track1.lockForRead(); assertEquals(2, Util.size(track1.getRawFixes())); assertTrue(track1.getFirstRawFix() instanceof GPSFixMoving); diff --git a/java/com.sap.sailing.mongodb.test/src/com/sap/sailing/mongodb/test/TestStoringAndRetrievingRaceLogInLeaderboards.java b/java/com.sap.sailing.mongodb.test/src/com/sap/sailing/mongodb/test/TestStoringAndRetrievingRaceLogInLeaderboards.java index 483deeae753..69fceafcff4 100644 --- a/java/com.sap.sailing.mongodb.test/src/com/sap/sailing/mongodb/test/TestStoringAndRetrievingRaceLogInLeaderboards.java +++ b/java/com.sap.sailing.mongodb.test/src/com/sap/sailing/mongodb/test/TestStoringAndRetrievingRaceLogInLeaderboards.java @@ -7,7 +7,6 @@ import static org.mockito.Mockito.doCallRealMethod; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; -import java.io.Serializable; import java.net.UnknownHostException; import java.util.UUID; @@ -21,6 +20,7 @@ import com.mongodb.DBObject; import com.mongodb.MongoException; 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.RaceLogCourseAreaChangedEvent; @@ -39,6 +39,7 @@ 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.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; @@ -299,14 +300,11 @@ public class TestStoringAndRetrievingRaceLogInLeaderboards extends RaceLogMongoD Color.RED, "someone@nowhere.de", null, null, null, /* timeOnTimeFactor */ null, /* timeOnDistanceAllowancePerNauticalMile */ null); CompetitorResults storedPositioningList = new CompetitorResultsImpl(); - storedPositioningList.add(new com.sap.sse.common.Util.Triple(storedCompetitor.getId(), storedCompetitor.getName(), MaxPointsReason.NONE)); - + storedPositioningList.add(new CompetitorResultImpl(storedCompetitor.getId(), storedCompetitor.getName(), /* rank */ + 1, MaxPointsReason.NONE, /* score */ null, /* finishingTimePoint */null, /* comment */null)); RaceLogFinishPositioningConfirmedEvent event = new RaceLogFinishPositioningConfirmedEventImpl(now, author, 0, storedPositioningList); - addAndStoreRaceLogEvent(leaderboard, raceColumnName, event); - RaceLog loadedRaceLog = retrieveRaceLog(); - loadedRaceLog.lockForRead(); try { RaceLogEvent loadedEvent = loadedRaceLog.getFirstRawFix(); @@ -320,14 +318,41 @@ public class TestStoringAndRetrievingRaceLogInLeaderboards extends RaceLogMongoD } } + @Test + public void testStoreAndRetrieveSimpleLeaderboardWithRaceLogFinishPositioningConfirmedEventWithContents() { + Competitor storedCompetitor = DomainFactory.INSTANCE.getOrCreateCompetitor(UUID.randomUUID(), "SAP Extreme Sailing Team", + Color.RED, "someone@nowhere.de", null, null, null, + /* timeOnTimeFactor */ null, /* timeOnDistanceAllowancePerNauticalMile */ null); + CompetitorResults storedPositioningList = new CompetitorResultsImpl(); + final TimePoint finishingTimePoint = MillisecondsTimePoint.now(); + final String comment = "This is a comment"; + storedPositioningList.add(new CompetitorResultImpl(storedCompetitor.getId(), storedCompetitor.getName(), /* rank */ + 1, MaxPointsReason.NONE, /* score */ 12.3, finishingTimePoint, comment)); + RaceLogFinishPositioningConfirmedEvent event = new RaceLogFinishPositioningConfirmedEventImpl(now, author, 0, storedPositioningList); + addAndStoreRaceLogEvent(leaderboard, raceColumnName, event); + RaceLog loadedRaceLog = retrieveRaceLog(); + loadedRaceLog.lockForRead(); + try { + RaceLogEvent loadedEvent = loadedRaceLog.getFirstRawFix(); + RaceLogFinishPositioningConfirmedEvent loadedConfirmedEvent = (RaceLogFinishPositioningConfirmedEvent) loadedEvent; + CompetitorResults results = loadedConfirmedEvent.getPositionedCompetitorsIDsNamesMaxPointsReasons(); + assertEquals(1, Util.size(results)); + final CompetitorResult result = results.iterator().next(); + assertEquals(comment, result.getComment()); + assertEquals(12.3, result.getScore(), 0.000001); + assertEquals(MaxPointsReason.NONE, result.getMaxPointsReason()); + assertEquals(1, result.getOneBasedRank()); + assertEquals(finishingTimePoint, result.getFinishingTime()); + } finally { + loadedRaceLog.unlockAfterRead(); + } + } + @Test public void testStoreAndRetrieveSimpleLeaderboardWithBackwardsCompatibleRaceLogFinishPositioningConfirmedEvent() { RaceLogFinishPositioningConfirmedEvent event = new RaceLogFinishPositioningConfirmedEventImpl(now, author, 0, null); - createAndStoreOldRaceLogFinishPositioningConfirmedEventDBEntry(); - RaceLog loadedRaceLog = retrieveRaceLog(); - loadedRaceLog.lockForRead(); try { RaceLogEvent loadedEvent = loadedRaceLog.getFirstRawFix(); @@ -369,8 +394,8 @@ public class TestStoringAndRetrievingRaceLogInLeaderboards extends RaceLogMongoD Competitor storedCompetitor = DomainFactory.INSTANCE.getOrCreateCompetitor(UUID.randomUUID(), "SAP Extreme Sailing Team", Color.RED, "someone@nowhere.de", null, null, null, /* timeOnTimeFactor */ null, /* timeOnDistanceAllowancePerNauticalMile */ null); CompetitorResults storedPositioningList = new CompetitorResultsImpl(); - storedPositioningList.add(new com.sap.sse.common.Util.Triple(storedCompetitor.getId(), storedCompetitor.getName(), MaxPointsReason.NONE)); - + storedPositioningList.add(new CompetitorResultImpl(storedCompetitor.getId(), storedCompetitor.getName(), /* rank */ + 1, MaxPointsReason.NONE, /* score */ null, /* finishingTimePoint */null, /* comment */null)); RaceLogFinishPositioningListChangedEvent event = new RaceLogFinishPositioningListChangedEventImpl(now, author, 0, storedPositioningList); addAndStoreRaceLogEvent(leaderboard, raceColumnName, event); @@ -385,10 +410,9 @@ public class TestStoringAndRetrievingRaceLogInLeaderboards extends RaceLogMongoD assertEquals(event.getPassId(), loadedPositioningEvent.getPassId()); assertEquals(event.getId(), loadedPositioningEvent.getId()); assertEquals(event.getInvolvedBoats().size(), loadedPositioningEvent.getInvolvedBoats().size()); - assertEquals(event.getPositionedCompetitorsIDsNamesMaxPointsReasons().size(), loadedPositioningEvent.getPositionedCompetitorsIDsNamesMaxPointsReasons().size()); - assertEquals(event.getPositionedCompetitorsIDsNamesMaxPointsReasons().get(0).getA(), loadedPositioningEvent.getPositionedCompetitorsIDsNamesMaxPointsReasons().get(0).getA()); - assertEquals(event.getPositionedCompetitorsIDsNamesMaxPointsReasons().get(0).getB(), loadedPositioningEvent.getPositionedCompetitorsIDsNamesMaxPointsReasons().get(0).getB()); - assertEquals(event.getPositionedCompetitorsIDsNamesMaxPointsReasons().get(0).getC().name(), loadedPositioningEvent.getPositionedCompetitorsIDsNamesMaxPointsReasons().get(0).getC().name()); + final CompetitorResults expectedCompetiorResults = event.getPositionedCompetitorsIDsNamesMaxPointsReasons(); + final CompetitorResults loadedCompetitorResults = loadedPositioningEvent.getPositionedCompetitorsIDsNamesMaxPointsReasons(); + assertCompetitorResultsEqual(expectedCompetiorResults, loadedCompetitorResults); assertEquals(1, Util.size(loadedRaceLog.getFixes())); } finally { loadedRaceLog.unlockAfterRead(); @@ -399,11 +423,8 @@ public class TestStoringAndRetrievingRaceLogInLeaderboards extends RaceLogMongoD public void testStoreAndRetrieveSimpleLeaderboardWithRaceLogCourseAreaChangeEvent() { final UUID uuid = UUID.randomUUID(); RaceLogCourseAreaChangedEvent event = new RaceLogCourseAreaChangeEventImpl(now, author, 0, uuid); - addAndStoreRaceLogEvent(leaderboard, raceColumnName, event); - RaceLog loadedRaceLog = retrieveRaceLog(); - loadedRaceLog.lockForRead(); try { RaceLogEvent loadedEvent = loadedRaceLog.getFirstRawFix(); diff --git a/java/com.sap.sailing.mongodb.test/src/com/sap/sailing/mongodb/test/TestStoringAndRetrievingRaceLogInRegatta.java b/java/com.sap.sailing.mongodb.test/src/com/sap/sailing/mongodb/test/TestStoringAndRetrievingRaceLogInRegatta.java index dea3c3d63e4..046d7bf82bf 100644 --- a/java/com.sap.sailing.mongodb.test/src/com/sap/sailing/mongodb/test/TestStoringAndRetrievingRaceLogInRegatta.java +++ b/java/com.sap.sailing.mongodb.test/src/com/sap/sailing/mongodb/test/TestStoringAndRetrievingRaceLogInRegatta.java @@ -3,7 +3,6 @@ package com.sap.sailing.mongodb.test; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNull; -import java.io.Serializable; import java.net.UnknownHostException; import java.util.ArrayList; import java.util.List; @@ -31,6 +30,7 @@ import com.sap.sailing.domain.abstractlog.race.RaceLogRaceStatusEvent; 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.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; @@ -202,14 +202,10 @@ public class TestStoringAndRetrievingRaceLogInRegatta extends AbstractTestStorin Competitor storedCompetitor = DomainFactory.INSTANCE.getOrCreateCompetitor(UUID.randomUUID(), "SAP Extreme Sailing Team", Color.RED, "someone@nowhere.de", null, null, null, /* timeOnTimeFactor */ null, /* timeOnDistanceAllowancePerNauticalMile */ null); CompetitorResults storedPositioningList = new CompetitorResultsImpl(); - storedPositioningList.add(new com.sap.sse.common.Util.Triple(storedCompetitor.getId(), storedCompetitor.getName(), MaxPointsReason.NONE)); - + storedPositioningList.add(new CompetitorResultImpl(storedCompetitor.getId(), storedCompetitor.getName(), /* rank */ 1, MaxPointsReason.NONE, /* score */ null, /* finishingTime */ null, /* comment */ null)); RaceLogFinishPositioningListChangedEvent event = new RaceLogFinishPositioningListChangedEventImpl(now, author, 0, storedPositioningList); - addAndStoreRaceLogEvent(regatta, raceColumnName, event); - RaceLog loadedRaceLog = retrieveRaceLog(); - loadedRaceLog.lockForRead(); try { RaceLogEvent loadedEvent = loadedRaceLog.getFirstRawFix(); @@ -218,10 +214,7 @@ public class TestStoringAndRetrievingRaceLogInRegatta extends AbstractTestStorin assertEquals(event.getPassId(), loadedPositioningEvent.getPassId()); assertEquals(event.getId(), loadedPositioningEvent.getId()); assertEquals(event.getInvolvedBoats().size(), loadedPositioningEvent.getInvolvedBoats().size()); - assertEquals(event.getPositionedCompetitorsIDsNamesMaxPointsReasons().size(), loadedPositioningEvent.getPositionedCompetitorsIDsNamesMaxPointsReasons().size()); - assertEquals(event.getPositionedCompetitorsIDsNamesMaxPointsReasons().get(0).getA(), loadedPositioningEvent.getPositionedCompetitorsIDsNamesMaxPointsReasons().get(0).getA()); - assertEquals(event.getPositionedCompetitorsIDsNamesMaxPointsReasons().get(0).getB(), loadedPositioningEvent.getPositionedCompetitorsIDsNamesMaxPointsReasons().get(0).getB()); - assertEquals(event.getPositionedCompetitorsIDsNamesMaxPointsReasons().get(0).getC().name(), loadedPositioningEvent.getPositionedCompetitorsIDsNamesMaxPointsReasons().get(0).getC().name()); + assertCompetitorResultsEqual(event.getPositionedCompetitorsIDsNamesMaxPointsReasons(), loadedPositioningEvent.getPositionedCompetitorsIDsNamesMaxPointsReasons()); assertEquals(1, Util.size(loadedRaceLog.getFixes())); } finally { loadedRaceLog.unlockAfterRead(); @@ -233,14 +226,10 @@ public class TestStoringAndRetrievingRaceLogInRegatta extends AbstractTestStorin Competitor storedCompetitor = DomainFactory.INSTANCE.getOrCreateCompetitor(UUID.randomUUID(), "SAP Extreme Sailing Team", Color.RED, "someone@nowhere.de", null, null, null, /* timeOnTimeFactor */ null, /* timeOnDistanceAllowancePerNauticalMile */ null); CompetitorResults storedPositioningList = new CompetitorResultsImpl(); - storedPositioningList.add(new com.sap.sse.common.Util.Triple(storedCompetitor.getId(), storedCompetitor.getName(), MaxPointsReason.NONE)); - + storedPositioningList.add(new CompetitorResultImpl(storedCompetitor.getId(), storedCompetitor.getName(), /* rank */ 1, MaxPointsReason.NONE, /* score */ null, /* finishingTime */ null, /* comment */ null)); RaceLogFinishPositioningConfirmedEvent event = new RaceLogFinishPositioningConfirmedEventImpl(now, author, 0, storedPositioningList); - addAndStoreRaceLogEvent(regatta, raceColumnName, event); - RaceLog loadedRaceLog = retrieveRaceLog(); - loadedRaceLog.lockForRead(); try { RaceLogEvent loadedEvent = loadedRaceLog.getFirstRawFix(); @@ -249,10 +238,7 @@ public class TestStoringAndRetrievingRaceLogInRegatta extends AbstractTestStorin assertEquals(event.getPassId(), loadedConfirmedEvent.getPassId()); assertEquals(event.getId(), loadedConfirmedEvent.getId()); assertEquals(event.getInvolvedBoats().size(), loadedConfirmedEvent.getInvolvedBoats().size()); - assertEquals(event.getPositionedCompetitorsIDsNamesMaxPointsReasons().size(), loadedConfirmedEvent.getPositionedCompetitorsIDsNamesMaxPointsReasons().size()); - assertEquals(event.getPositionedCompetitorsIDsNamesMaxPointsReasons().get(0).getA(), loadedConfirmedEvent.getPositionedCompetitorsIDsNamesMaxPointsReasons().get(0).getA()); - assertEquals(event.getPositionedCompetitorsIDsNamesMaxPointsReasons().get(0).getB(), loadedConfirmedEvent.getPositionedCompetitorsIDsNamesMaxPointsReasons().get(0).getB()); - assertEquals(event.getPositionedCompetitorsIDsNamesMaxPointsReasons().get(0).getC().name(), loadedConfirmedEvent.getPositionedCompetitorsIDsNamesMaxPointsReasons().get(0).getC().name()); + assertCompetitorResultsEqual(event.getPositionedCompetitorsIDsNamesMaxPointsReasons(), loadedConfirmedEvent.getPositionedCompetitorsIDsNamesMaxPointsReasons()); assertEquals(1, Util.size(loadedRaceLog.getFixes())); } finally { loadedRaceLog.unlockAfterRead(); diff --git a/java/com.sap.sailing.server.gateway.serialization.shared.android/src/com/sap/sailing/server/gateway/deserialization/racelog/impl/RaceLogCloseOpenEndedDeviceMappingEventDeserializer.java b/java/com.sap.sailing.server.gateway.serialization.shared.android/src/com/sap/sailing/server/gateway/deserialization/racelog/impl/RaceLogCloseOpenEndedDeviceMappingEventDeserializer.java deleted file mode 100644 index 6b5e267c27a..00000000000 --- a/java/com.sap.sailing.server.gateway.serialization.shared.android/src/com/sap/sailing/server/gateway/deserialization/racelog/impl/RaceLogCloseOpenEndedDeviceMappingEventDeserializer.java +++ /dev/null @@ -1,35 +0,0 @@ -package com.sap.sailing.server.gateway.deserialization.racelog.impl; - -import java.io.Serializable; -import java.util.List; - -import org.json.simple.JSONObject; - -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.base.Competitor; -import com.sap.sailing.server.gateway.deserialization.JsonDeserializationException; -import com.sap.sailing.server.gateway.deserialization.JsonDeserializer; -import com.sap.sailing.server.gateway.deserialization.impl.Helpers; -import com.sap.sse.common.TimePoint; -import com.sap.sse.common.impl.MillisecondsTimePoint; - -public class RaceLogCloseOpenEndedDeviceMappingEventDeserializer extends BaseRaceLogEventDeserializer { - public static final String FIELD_DEVICE_MAPPING_EVENT_ID = "deviceMappingEventId"; - public static final String FIELD_CLOSING_TIMEPOINT_MILLIS = "closingTimePointMillis"; - - public RaceLogCloseOpenEndedDeviceMappingEventDeserializer(JsonDeserializer competitorDeserializer) { - super(competitorDeserializer); - } - - @Override - protected RaceLogEvent deserialize(JSONObject object, Serializable id, TimePoint createdAt, AbstractLogEventAuthor author, TimePoint timePoint, int passId, List competitors) - throws JsonDeserializationException { - Serializable deviceMappingEventId = Helpers.tryUuidConversion((Serializable) object.get(FIELD_DEVICE_MAPPING_EVENT_ID)); - TimePoint closingTimePoint = new MillisecondsTimePoint((Long) object.get(FIELD_CLOSING_TIMEPOINT_MILLIS)); - - return new RaceLogCloseOpenEndedDeviceMappingEventImpl(createdAt, timePoint, author, id, passId, - deviceMappingEventId, closingTimePoint); - } -} diff --git a/java/com.sap.sailing.server.gateway.serialization.shared.android/src/com/sap/sailing/server/gateway/deserialization/racelog/impl/RaceLogDefineMarkEventDeserializer.java b/java/com.sap.sailing.server.gateway.serialization.shared.android/src/com/sap/sailing/server/gateway/deserialization/racelog/impl/RaceLogDefineMarkEventDeserializer.java deleted file mode 100644 index 257b743f295..00000000000 --- a/java/com.sap.sailing.server.gateway.serialization.shared.android/src/com/sap/sailing/server/gateway/deserialization/racelog/impl/RaceLogDefineMarkEventDeserializer.java +++ /dev/null @@ -1,34 +0,0 @@ -package com.sap.sailing.server.gateway.deserialization.racelog.impl; - -import java.io.Serializable; -import java.util.List; - -import org.json.simple.JSONObject; - -import com.sap.sailing.domain.abstractlog.AbstractLogEventAuthor; -import com.sap.sailing.domain.abstractlog.race.RaceLogEvent; -import com.sap.sailing.domain.abstractlog.race.tracking.impl.RaceLogDefineMarkEventImpl; -import com.sap.sailing.domain.base.Competitor; -import com.sap.sailing.domain.base.Mark; -import com.sap.sailing.server.gateway.deserialization.JsonDeserializationException; -import com.sap.sailing.server.gateway.deserialization.JsonDeserializer; -import com.sap.sailing.server.gateway.deserialization.impl.Helpers; -import com.sap.sailing.server.gateway.serialization.racelog.impl.RaceLogDefineMarkEventSerializer; -import com.sap.sse.common.TimePoint; - -public class RaceLogDefineMarkEventDeserializer extends BaseRaceLogEventDeserializer { - private final JsonDeserializer markDeserializer; - public RaceLogDefineMarkEventDeserializer(JsonDeserializer competitorDeserializer, - JsonDeserializer markDeserializer) { - super(competitorDeserializer); - this.markDeserializer = markDeserializer; - } - - @Override - protected RaceLogEvent deserialize(JSONObject object, Serializable id, TimePoint createdAt, AbstractLogEventAuthor author, TimePoint timePoint, int passId, List competitors) - throws JsonDeserializationException { - Mark mark = markDeserializer.deserialize(Helpers.getNestedObjectSafe(object, RaceLogDefineMarkEventSerializer.FIELD_MARK)); - - return new RaceLogDefineMarkEventImpl(createdAt, timePoint, author, id, passId, mark); - } -} diff --git a/java/com.sap.sailing.server.gateway.serialization.shared.android/src/com/sap/sailing/server/gateway/deserialization/racelog/impl/RaceLogDeviceCompetitorMappingEventDeserializer.java b/java/com.sap.sailing.server.gateway.serialization.shared.android/src/com/sap/sailing/server/gateway/deserialization/racelog/impl/RaceLogDeviceCompetitorMappingEventDeserializer.java deleted file mode 100644 index d89ed2065ba..00000000000 --- a/java/com.sap.sailing.server.gateway.serialization.shared.android/src/com/sap/sailing/server/gateway/deserialization/racelog/impl/RaceLogDeviceCompetitorMappingEventDeserializer.java +++ /dev/null @@ -1,33 +0,0 @@ -package com.sap.sailing.server.gateway.deserialization.racelog.impl; - -import java.io.Serializable; - -import org.json.simple.JSONObject; - -import com.sap.sailing.domain.abstractlog.AbstractLogEventAuthor; -import com.sap.sailing.domain.abstractlog.race.RaceLogEvent; -import com.sap.sailing.domain.abstractlog.race.tracking.impl.RaceLogDeviceCompetitorMappingEventImpl; -import com.sap.sailing.domain.base.Competitor; -import com.sap.sailing.domain.racelogtracking.DeviceIdentifier; -import com.sap.sailing.server.gateway.deserialization.JsonDeserializationException; -import com.sap.sailing.server.gateway.deserialization.JsonDeserializer; -import com.sap.sse.common.TimePoint; - -public class RaceLogDeviceCompetitorMappingEventDeserializer extends - RaceLogDeviceMappingEventDeserializer { - public RaceLogDeviceCompetitorMappingEventDeserializer( - JsonDeserializer competitorDeserializer, - JsonDeserializer deviceDeserializer) { - super(competitorDeserializer, deviceDeserializer); - } - - @Override - protected RaceLogEvent furtherDeserialize(JSONObject itemObject, TimePoint from, TimePoint to, - DeviceIdentifier device, Serializable id, TimePoint createdAt, - AbstractLogEventAuthor author, TimePoint timePoint, int passId) throws JsonDeserializationException { - Competitor mappedTo = competitorDeserializer.deserialize(itemObject); - return new RaceLogDeviceCompetitorMappingEventImpl(createdAt, timePoint, author, id, passId, - mappedTo, device, from, to); - } - -} diff --git a/java/com.sap.sailing.server.gateway.serialization.shared.android/src/com/sap/sailing/server/gateway/deserialization/racelog/impl/RaceLogDeviceMappingEventDeserializer.java b/java/com.sap.sailing.server.gateway.serialization.shared.android/src/com/sap/sailing/server/gateway/deserialization/racelog/impl/RaceLogDeviceMappingEventDeserializer.java deleted file mode 100644 index d107823a514..00000000000 --- a/java/com.sap.sailing.server.gateway.serialization.shared.android/src/com/sap/sailing/server/gateway/deserialization/racelog/impl/RaceLogDeviceMappingEventDeserializer.java +++ /dev/null @@ -1,49 +0,0 @@ -package com.sap.sailing.server.gateway.deserialization.racelog.impl; - -import java.io.Serializable; -import java.util.List; - -import org.json.simple.JSONObject; - -import com.sap.sailing.domain.abstractlog.AbstractLogEventAuthor; -import com.sap.sailing.domain.abstractlog.race.RaceLogEvent; -import com.sap.sailing.domain.base.Competitor; -import com.sap.sailing.domain.racelogtracking.DeviceIdentifier; -import com.sap.sailing.server.gateway.deserialization.JsonDeserializationException; -import com.sap.sailing.server.gateway.deserialization.JsonDeserializer; -import com.sap.sailing.server.gateway.deserialization.impl.Helpers; -import com.sap.sailing.server.gateway.serialization.racelog.impl.RaceLogDeviceMappingEventSerializer; -import com.sap.sse.common.TimePoint; -import com.sap.sse.common.WithID; -import com.sap.sse.common.impl.MillisecondsTimePoint; - -public abstract class RaceLogDeviceMappingEventDeserializer -extends BaseRaceLogEventDeserializer { - protected final JsonDeserializer deviceDeserializer; - - public RaceLogDeviceMappingEventDeserializer( - JsonDeserializer competitorDeserializer, - JsonDeserializer deviceDeserializer) { - super(competitorDeserializer); - this.deviceDeserializer = deviceDeserializer; - } - - protected abstract RaceLogEvent furtherDeserialize(JSONObject itemObject, TimePoint from, TimePoint to, - DeviceIdentifier device, Serializable id, TimePoint createdAt, AbstractLogEventAuthor author, - TimePoint timePoint, int passId) throws JsonDeserializationException; - - @Override - protected RaceLogEvent deserialize(JSONObject object, Serializable id, - TimePoint createdAt, AbstractLogEventAuthor author, - TimePoint timePoint, int passId, List competitors) - throws JsonDeserializationException { - JSONObject deviceJson = Helpers.toJSONObjectSafe(object.get(RaceLogDeviceMappingEventSerializer.FIELD_DEVICE)); - DeviceIdentifier device = deviceDeserializer.deserialize(deviceJson); - JSONObject itemObject = Helpers.getNestedObjectSafe(object, RaceLogDeviceMappingEventSerializer.FIELD_ITEM); - long fromMillis = (Long) object.get(RaceLogDeviceMappingEventSerializer.FIELD_FROM_MILLIS); - long toMillis = (Long) object.get(RaceLogDeviceMappingEventSerializer.FIELD_TO_MILLIS); - TimePoint from = new MillisecondsTimePoint(fromMillis); - TimePoint to = new MillisecondsTimePoint(toMillis); - return furtherDeserialize(itemObject, from, to, device, id, createdAt, author, timePoint, passId); - } -} diff --git a/java/com.sap.sailing.server.gateway.serialization.shared.android/src/com/sap/sailing/server/gateway/deserialization/racelog/impl/RaceLogDeviceMarkMappingEventDeserializer.java b/java/com.sap.sailing.server.gateway.serialization.shared.android/src/com/sap/sailing/server/gateway/deserialization/racelog/impl/RaceLogDeviceMarkMappingEventDeserializer.java deleted file mode 100644 index 1823dcbe870..00000000000 --- a/java/com.sap.sailing.server.gateway.serialization.shared.android/src/com/sap/sailing/server/gateway/deserialization/racelog/impl/RaceLogDeviceMarkMappingEventDeserializer.java +++ /dev/null @@ -1,37 +0,0 @@ -package com.sap.sailing.server.gateway.deserialization.racelog.impl; - -import java.io.Serializable; - -import org.json.simple.JSONObject; - -import com.sap.sailing.domain.abstractlog.AbstractLogEventAuthor; -import com.sap.sailing.domain.abstractlog.race.RaceLogEvent; -import com.sap.sailing.domain.abstractlog.race.tracking.impl.RaceLogDeviceMarkMappingEventImpl; -import com.sap.sailing.domain.base.Competitor; -import com.sap.sailing.domain.base.Mark; -import com.sap.sailing.domain.racelogtracking.DeviceIdentifier; -import com.sap.sailing.server.gateway.deserialization.JsonDeserializationException; -import com.sap.sailing.server.gateway.deserialization.JsonDeserializer; -import com.sap.sse.common.TimePoint; - -public class RaceLogDeviceMarkMappingEventDeserializer extends - RaceLogDeviceMappingEventDeserializer { - private final JsonDeserializer markDeserializer; - - public RaceLogDeviceMarkMappingEventDeserializer( - JsonDeserializer competitorDeserializer, JsonDeserializer markDeserializer, - JsonDeserializer deviceDeserializer) { - super(competitorDeserializer, deviceDeserializer); - this.markDeserializer = markDeserializer; - } - - @Override - protected RaceLogEvent furtherDeserialize(JSONObject itemObject, TimePoint from, TimePoint to, - DeviceIdentifier device, Serializable id, TimePoint createdAt, - AbstractLogEventAuthor author, TimePoint timePoint, int passId) throws JsonDeserializationException { - Mark mappedTo = (Mark) markDeserializer.deserialize(itemObject); - return new RaceLogDeviceMarkMappingEventImpl(createdAt, timePoint, author, id, passId, - mappedTo, device, from, to); - } - -} diff --git a/java/com.sap.sailing.server.gateway.serialization.shared.android/src/com/sap/sailing/server/gateway/deserialization/racelog/impl/RaceLogEventDeserializer.java b/java/com.sap.sailing.server.gateway.serialization.shared.android/src/com/sap/sailing/server/gateway/deserialization/racelog/impl/RaceLogEventDeserializer.java index 91b4aea0199..8201335ef90 100755 --- a/java/com.sap.sailing.server.gateway.serialization.shared.android/src/com/sap/sailing/server/gateway/deserialization/racelog/impl/RaceLogEventDeserializer.java +++ b/java/com.sap.sailing.server.gateway.serialization.shared.android/src/com/sap/sailing/server/gateway/deserialization/racelog/impl/RaceLogEventDeserializer.java @@ -20,14 +20,10 @@ import com.sap.sailing.server.gateway.deserialization.impl.PositionJsonDeseriali import com.sap.sailing.server.gateway.deserialization.impl.WindJsonDeserializer; import com.sap.sailing.server.gateway.serialization.racelog.impl.BaseRaceLogEventSerializer; import com.sap.sailing.server.gateway.serialization.racelog.impl.RaceLogAdditionalScoringInformationSerializer; -import com.sap.sailing.server.gateway.serialization.racelog.impl.RaceLogCloseOpenEndedDeviceMappingEventSerializer; import com.sap.sailing.server.gateway.serialization.racelog.impl.RaceLogCourseAreaChangedEventSerializer; import com.sap.sailing.server.gateway.serialization.racelog.impl.RaceLogCourseDesignChangedEventSerializer; -import com.sap.sailing.server.gateway.serialization.racelog.impl.RaceLogDefineMarkEventSerializer; import com.sap.sailing.server.gateway.serialization.racelog.impl.RaceLogDenoteForTrackingEventSerializer; import com.sap.sailing.server.gateway.serialization.racelog.impl.RaceLogDependentStartTimeEventSerializer; -import com.sap.sailing.server.gateway.serialization.racelog.impl.RaceLogDeviceCompetitorMappingEventSerializer; -import com.sap.sailing.server.gateway.serialization.racelog.impl.RaceLogDeviceMarkMappingEventSerializer; import com.sap.sailing.server.gateway.serialization.racelog.impl.RaceLogEndOfTrackingEventSerializer; import com.sap.sailing.server.gateway.serialization.racelog.impl.RaceLogFinishPositioningConfirmedEventSerializer; import com.sap.sailing.server.gateway.serialization.racelog.impl.RaceLogFinishPositioningListChangedEventSerializer; @@ -45,6 +41,7 @@ import com.sap.sailing.server.gateway.serialization.racelog.impl.RaceLogStartPro import com.sap.sailing.server.gateway.serialization.racelog.impl.RaceLogStartTimeEventSerializer; import com.sap.sailing.server.gateway.serialization.racelog.impl.RaceLogStartTrackingEventSerializer; import com.sap.sailing.server.gateway.serialization.racelog.impl.RaceLogSuppressedMarkPassingsEventSerializer; +import com.sap.sailing.server.gateway.serialization.racelog.impl.RaceLogUseCompetitorsFromRaceLogEventSerializer; import com.sap.sailing.server.gateway.serialization.racelog.impl.RaceLogWindFixEventSerializer; import com.sap.sailing.server.gateway.serialization.racelog.tracking.impl.SmartphoneUUIDJsonHandler; @@ -80,18 +77,16 @@ public class RaceLogEventDeserializer implements JsonDeserializer new RaceLogWindFixEventDeserializer(competitorDeserializer, new WindJsonDeserializer( new PositionJsonDeserializer())), - new RaceLogDeviceCompetitorMappingEventDeserializer(competitorDeserializer, deviceDeserializer), - new RaceLogDeviceMarkMappingEventDeserializer(competitorDeserializer, new MarkDeserializer(domainFactory), deviceDeserializer), new RaceLogDenoteForTrackingEventDeserializer(competitorDeserializer, domainFactory), new RaceLogStartTrackingEventDeserializer(competitorDeserializer), new RaceLogRevokeEventDeserializer(competitorDeserializer), new RaceLogRegisterCompetitorEventDeserializer(competitorDeserializer), - new RaceLogDefineMarkEventDeserializer(competitorDeserializer, new MarkDeserializer(domainFactory)), - new RaceLogCloseOpenEndedDeviceMappingEventDeserializer(competitorDeserializer), new RaceLogAdditionalScoringInformationEventDeserializer(competitorDeserializer), new RaceLogFixedMarkPassingEventDeserializer(competitorDeserializer), new RaceLogSuppressedMarkPassingsEventDeserializer(competitorDeserializer), - new RaceLogStartOfTrackingEventDeserializer(competitorDeserializer), new RaceLogEndOfTrackingEventDeserializer(competitorDeserializer)); + new RaceLogStartOfTrackingEventDeserializer(competitorDeserializer), + new RaceLogUseCompetitorsFromRaceLogEventDeserializer(competitorDeserializer), + new RaceLogEndOfTrackingEventDeserializer(competitorDeserializer)); } protected final JsonDeserializer flagEventDeserializer; @@ -108,19 +103,16 @@ public class RaceLogEventDeserializer implements JsonDeserializer protected final JsonDeserializer startProcedureChangedEventDeserializer; protected final JsonDeserializer protestStartTimeEventDeserializer; protected final JsonDeserializer windFixEventDeserializer; - protected final JsonDeserializer deviceCompetitorMappingEventDeserializer; - protected final JsonDeserializer deviceMarkMappingEventDeserializer; protected final JsonDeserializer denoteForTrackingEventDeserializer; protected final JsonDeserializer startTrackingEventDeserializer; protected final JsonDeserializer revokeEventDeserializer; protected final JsonDeserializer registerCompetitorEventDeserializer; - protected final JsonDeserializer defineMarkEventDeserializer; - protected final JsonDeserializer closeOpenEndedDeviceMappingEventDeserializer; protected final JsonDeserializer additionalScoringInformationEventDeserializer; protected final JsonDeserializer fixedMarkPassingEventDeserializer; protected final JsonDeserializer suppressedMarkPassingsDeserializer; protected final JsonDeserializer startOfTrackingDeserializer; protected final JsonDeserializer endOfTrackingDeserializer; + protected final JsonDeserializer useCompetitorsFromRaceLogDeserializer; public RaceLogEventDeserializer(JsonDeserializer flagEventDeserializer, JsonDeserializer startTimeEventDeserializer, @@ -136,18 +128,16 @@ public class RaceLogEventDeserializer implements JsonDeserializer JsonDeserializer startProcedureChangedEventDeserializer, JsonDeserializer protestStartTimeEventDeserializer, JsonDeserializer windFixEventDeserializer, - JsonDeserializer deviceCompetitorMappingEventDeserializer, - JsonDeserializer deviceMarkMappingEventDeserializer, JsonDeserializer denoteForTrackingEventDeserializer, JsonDeserializer startTrackingEventDeserializer, JsonDeserializer revokeEventDeserializer, JsonDeserializer registerCompetitorEventDeserializer, - JsonDeserializer defineMarkEventDeserializer, - JsonDeserializer closeOpenEndedDeviceMappingEventDeserializer, JsonDeserializer additionalScoringInformationEventDeserializer, JsonDeserializer fixedMarkPassingEventDeserializer, JsonDeserializer suppressedMarkPassingsEventDeserializer, - JsonDeserializer startOfTrackingEventDeserializer, JsonDeserializer endOfTrackingEventDeserializer) { + JsonDeserializer startOfTrackingEventDeserializer, + JsonDeserializer useCompetitorsFromRaceLogDeserializer, + JsonDeserializer endOfTrackingEventDeserializer) { this.flagEventDeserializer = flagEventDeserializer; this.startTimeEventDeserializer = startTimeEventDeserializer; this.dependentStartTimeEventDeserializer = dependentStartTimeEventDeserializer; @@ -162,19 +152,16 @@ public class RaceLogEventDeserializer implements JsonDeserializer this.startProcedureChangedEventDeserializer = startProcedureChangedEventDeserializer; this.protestStartTimeEventDeserializer = protestStartTimeEventDeserializer; this.windFixEventDeserializer = windFixEventDeserializer; - this.deviceCompetitorMappingEventDeserializer = deviceCompetitorMappingEventDeserializer; - this.deviceMarkMappingEventDeserializer = deviceMarkMappingEventDeserializer; this.denoteForTrackingEventDeserializer = denoteForTrackingEventDeserializer; this.startTrackingEventDeserializer = startTrackingEventDeserializer; this.revokeEventDeserializer = revokeEventDeserializer; this.registerCompetitorEventDeserializer = registerCompetitorEventDeserializer; - this.defineMarkEventDeserializer = defineMarkEventDeserializer; - this.closeOpenEndedDeviceMappingEventDeserializer = closeOpenEndedDeviceMappingEventDeserializer; this.additionalScoringInformationEventDeserializer = additionalScoringInformationEventDeserializer; this.fixedMarkPassingEventDeserializer = fixedMarkPassingEventDeserializer; this.suppressedMarkPassingsDeserializer = suppressedMarkPassingsEventDeserializer; this.startOfTrackingDeserializer = startOfTrackingEventDeserializer; this.endOfTrackingDeserializer = endOfTrackingEventDeserializer; + this.useCompetitorsFromRaceLogDeserializer = useCompetitorsFromRaceLogDeserializer; } protected JsonDeserializer getDeserializer(JSONObject object) throws JsonDeserializationException { @@ -208,10 +195,6 @@ public class RaceLogEventDeserializer implements JsonDeserializer return protestStartTimeEventDeserializer; } else if (type.equals(RaceLogWindFixEventSerializer.VALUE_CLASS)) { return windFixEventDeserializer; - } else if (type.equals(RaceLogDeviceCompetitorMappingEventSerializer.VALUE_CLASS)) { - return deviceCompetitorMappingEventDeserializer; - } else if (type.equals(RaceLogDeviceMarkMappingEventSerializer.VALUE_CLASS)) { - return deviceMarkMappingEventDeserializer; } else if (type.equals(RaceLogDenoteForTrackingEventSerializer.VALUE_CLASS)) { return denoteForTrackingEventDeserializer; } else if (type.equals(RaceLogStartTrackingEventSerializer.VALUE_CLASS)) { @@ -220,10 +203,6 @@ public class RaceLogEventDeserializer implements JsonDeserializer return revokeEventDeserializer; } else if (type.equals(RaceLogRegisterCompetitorEventSerializer.VALUE_CLASS)) { return registerCompetitorEventDeserializer; - } else if (type.equals(RaceLogDefineMarkEventSerializer.VALUE_CLASS)) { - return defineMarkEventDeserializer; - } else if (type.equals(RaceLogCloseOpenEndedDeviceMappingEventSerializer.VALUE_CLASS)) { - return closeOpenEndedDeviceMappingEventDeserializer; } else if (type.equals(RaceLogAdditionalScoringInformationSerializer.VALUE_CLASS)) { return additionalScoringInformationEventDeserializer; } else if (type.equals(RaceLogFixedMarkPassingEventSerializer.VALUE_CLASS)) { @@ -234,6 +213,8 @@ public class RaceLogEventDeserializer implements JsonDeserializer return startOfTrackingDeserializer; } else if (type.equals(RaceLogEndOfTrackingEventSerializer.VALUE_CLASS)){ return endOfTrackingDeserializer; + } else if (type.equals(RaceLogUseCompetitorsFromRaceLogEventSerializer.VALUE_CLASS)){ + return endOfTrackingDeserializer; } throw new JsonDeserializationException(String.format("There is no deserializer defined for event type %s.", diff --git a/java/com.sap.sailing.server.gateway.serialization.shared.android/src/com/sap/sailing/server/gateway/deserialization/racelog/impl/RaceLogFinishPositioningConfirmedEventDeserializer.java b/java/com.sap.sailing.server.gateway.serialization.shared.android/src/com/sap/sailing/server/gateway/deserialization/racelog/impl/RaceLogFinishPositioningConfirmedEventDeserializer.java index 684435f0f33..27bbff64e24 100644 --- a/java/com.sap.sailing.server.gateway.serialization.shared.android/src/com/sap/sailing/server/gateway/deserialization/racelog/impl/RaceLogFinishPositioningConfirmedEventDeserializer.java +++ b/java/com.sap.sailing.server.gateway.serialization.shared.android/src/com/sap/sailing/server/gateway/deserialization/racelog/impl/RaceLogFinishPositioningConfirmedEventDeserializer.java @@ -1,59 +1,23 @@ package com.sap.sailing.server.gateway.deserialization.racelog.impl; import java.io.Serializable; -import java.util.List; - -import org.json.simple.JSONArray; -import org.json.simple.JSONObject; import com.sap.sailing.domain.abstractlog.AbstractLogEventAuthor; import com.sap.sailing.domain.abstractlog.race.CompetitorResults; -import com.sap.sailing.domain.abstractlog.race.RaceLogEvent; -import com.sap.sailing.domain.abstractlog.race.impl.CompetitorResultsImpl; import com.sap.sailing.domain.abstractlog.race.impl.RaceLogFinishPositioningConfirmedEventImpl; import com.sap.sailing.domain.base.Competitor; -import com.sap.sailing.domain.common.MaxPointsReason; -import com.sap.sailing.server.gateway.deserialization.JsonDeserializationException; import com.sap.sailing.server.gateway.deserialization.JsonDeserializer; -import com.sap.sailing.server.gateway.deserialization.impl.Helpers; -import com.sap.sailing.server.gateway.serialization.racelog.impl.RaceLogFinishPositioningConfirmedEventSerializer; import com.sap.sse.common.TimePoint; -import com.sap.sse.common.Util; -public class RaceLogFinishPositioningConfirmedEventDeserializer extends BaseRaceLogEventDeserializer { +public class RaceLogFinishPositioningConfirmedEventDeserializer extends RaceLogFinishPositioningEventDeserializer { public RaceLogFinishPositioningConfirmedEventDeserializer(JsonDeserializer competitorDeserializer) { super(competitorDeserializer); } - @Override - protected RaceLogEvent deserialize(JSONObject object, Serializable id, TimePoint createdAt, AbstractLogEventAuthor author, TimePoint timePoint, int passId, List competitors) - throws JsonDeserializationException { - - JSONArray jsonPositionedCompetitors = Helpers.getNestedArraySafe(object, RaceLogFinishPositioningConfirmedEventSerializer.FIELD_POSITIONED_COMPETITORS); - CompetitorResults positionedCompetitors = deserializePositionedCompetitors(jsonPositionedCompetitors); - + protected RaceLogFinishPositioningConfirmedEventImpl createRaceLogFinishPositioningEvent(Serializable id, + TimePoint createdAt, AbstractLogEventAuthor author, TimePoint timePoint, int passId, + CompetitorResults positionedCompetitors) { return new RaceLogFinishPositioningConfirmedEventImpl(createdAt, timePoint, author, id, passId, positionedCompetitors); } - - private CompetitorResults deserializePositionedCompetitors(JSONArray jsonPositionedCompetitors) throws JsonDeserializationException { - CompetitorResults positionedCompetitors = new CompetitorResultsImpl(); - - for (Object object : jsonPositionedCompetitors) { - JSONObject jsonPositionedCompetitor = Helpers.toJSONObjectSafe(object); - - Serializable competitorId = (Serializable) jsonPositionedCompetitor.get(RaceLogFinishPositioningConfirmedEventSerializer.FIELD_COMPETITOR_ID); - competitorId = Helpers.tryUuidConversion(competitorId); - String competitorName = (String) jsonPositionedCompetitor.get(RaceLogFinishPositioningConfirmedEventSerializer.FIELD_COMPETITOR_NAME); - - String maxPointsReasonName = (String) jsonPositionedCompetitor.get(RaceLogFinishPositioningConfirmedEventSerializer.FIELD_SCORE_CORRECTIONS_MAX_POINTS_REASON); - MaxPointsReason maxPointsReason = MaxPointsReason.valueOf(maxPointsReasonName); - - Util.Triple positionedCompetitor = new Util.Triple(competitorId, competitorName, maxPointsReason); - positionedCompetitors.add(positionedCompetitor); - } - - return positionedCompetitors; - } - } diff --git a/java/com.sap.sailing.server.gateway.serialization.shared.android/src/com/sap/sailing/server/gateway/deserialization/racelog/impl/RaceLogFinishPositioningEventDeserializer.java b/java/com.sap.sailing.server.gateway.serialization.shared.android/src/com/sap/sailing/server/gateway/deserialization/racelog/impl/RaceLogFinishPositioningEventDeserializer.java new file mode 100644 index 00000000000..ddc073e7cba --- /dev/null +++ b/java/com.sap.sailing.server.gateway.serialization.shared.android/src/com/sap/sailing/server/gateway/deserialization/racelog/impl/RaceLogFinishPositioningEventDeserializer.java @@ -0,0 +1,65 @@ +package com.sap.sailing.server.gateway.deserialization.racelog.impl; + +import java.io.Serializable; +import java.util.List; + +import org.json.simple.JSONArray; +import org.json.simple.JSONObject; + +import com.sap.sailing.domain.abstractlog.AbstractLogEventAuthor; +import com.sap.sailing.domain.abstractlog.race.CompetitorResults; +import com.sap.sailing.domain.abstractlog.race.RaceLogEvent; +import com.sap.sailing.domain.abstractlog.race.RaceLogFinishPositioningEvent; +import com.sap.sailing.domain.abstractlog.race.impl.CompetitorResultImpl; +import com.sap.sailing.domain.abstractlog.race.impl.CompetitorResultsImpl; +import com.sap.sailing.domain.base.Competitor; +import com.sap.sailing.domain.common.MaxPointsReason; +import com.sap.sailing.server.gateway.deserialization.JsonDeserializationException; +import com.sap.sailing.server.gateway.deserialization.JsonDeserializer; +import com.sap.sailing.server.gateway.deserialization.impl.Helpers; +import com.sap.sailing.server.gateway.serialization.racelog.impl.RaceLogFinishPositioningConfirmedEventSerializer; +import com.sap.sse.common.TimePoint; +import com.sap.sse.common.impl.MillisecondsTimePoint; + +public abstract class RaceLogFinishPositioningEventDeserializer extends BaseRaceLogEventDeserializer { + + public RaceLogFinishPositioningEventDeserializer(JsonDeserializer competitorDeserializer) { + super(competitorDeserializer); + } + + @Override + protected RaceLogEvent deserialize(JSONObject object, Serializable id, TimePoint createdAt, AbstractLogEventAuthor author, TimePoint timePoint, int passId, List competitors) + throws JsonDeserializationException { + JSONArray jsonPositionedCompetitors = Helpers.getNestedArraySafe(object, RaceLogFinishPositioningConfirmedEventSerializer.FIELD_POSITIONED_COMPETITORS); + CompetitorResults positionedCompetitors = deserializePositionedCompetitors(jsonPositionedCompetitors); + return createRaceLogFinishPositioningEvent(id, createdAt, author, timePoint, passId, positionedCompetitors); + } + + protected abstract RaceLogFinishPositioningEvent createRaceLogFinishPositioningEvent(Serializable id, + TimePoint createdAt, AbstractLogEventAuthor author, TimePoint timePoint, int passId, + CompetitorResults positionedCompetitors); + + private CompetitorResults deserializePositionedCompetitors(JSONArray jsonPositionedCompetitors) throws JsonDeserializationException { + CompetitorResults positionedCompetitors = new CompetitorResultsImpl(); + int rankCounter = 1; + for (Object object : jsonPositionedCompetitors) { + JSONObject jsonPositionedCompetitor = Helpers.toJSONObjectSafe(object); + Serializable competitorId = (Serializable) jsonPositionedCompetitor.get(RaceLogFinishPositioningConfirmedEventSerializer.FIELD_COMPETITOR_ID); + competitorId = Helpers.tryUuidConversion(competitorId); + final String competitorDisplayName = (String) jsonPositionedCompetitor.get(RaceLogFinishPositioningConfirmedEventSerializer.FIELD_COMPETITOR_NAME); + final String maxPointsReasonName = (String) jsonPositionedCompetitor.get(RaceLogFinishPositioningConfirmedEventSerializer.FIELD_SCORE_CORRECTIONS_MAX_POINTS_REASON); + final MaxPointsReason maxPointsReason = MaxPointsReason.valueOf(maxPointsReasonName); + final Integer rank = (Integer) jsonPositionedCompetitor.get(RaceLogFinishPositioningConfirmedEventSerializer.FIELD_RANK); + final Double score = (Double) jsonPositionedCompetitor.get(RaceLogFinishPositioningConfirmedEventSerializer.FIELD_SCORE); + final Long finishingTimePointAsMillis = (Long) jsonPositionedCompetitor.get(RaceLogFinishPositioningConfirmedEventSerializer.FIELD_FINISHING_TIME_POINT_AS_MILLIS); + final TimePoint finishingTime = finishingTimePointAsMillis == null ? null : new MillisecondsTimePoint(finishingTimePointAsMillis); + final String comment = (String) jsonPositionedCompetitor.get(RaceLogFinishPositioningConfirmedEventSerializer.FIELD_COMMENT); + CompetitorResultImpl positionedCompetitor = new CompetitorResultImpl( + competitorId, competitorDisplayName, rank == null ? rankCounter : rank, maxPointsReason, score, finishingTime, comment); + rankCounter++; + positionedCompetitors.add(positionedCompetitor); + } + return positionedCompetitors; + } + +} diff --git a/java/com.sap.sailing.server.gateway.serialization.shared.android/src/com/sap/sailing/server/gateway/deserialization/racelog/impl/RaceLogFinishPositioningListChangedEventDeserializer.java b/java/com.sap.sailing.server.gateway.serialization.shared.android/src/com/sap/sailing/server/gateway/deserialization/racelog/impl/RaceLogFinishPositioningListChangedEventDeserializer.java index e0561b41c54..76f74ffea6a 100644 --- a/java/com.sap.sailing.server.gateway.serialization.shared.android/src/com/sap/sailing/server/gateway/deserialization/racelog/impl/RaceLogFinishPositioningListChangedEventDeserializer.java +++ b/java/com.sap.sailing.server.gateway.serialization.shared.android/src/com/sap/sailing/server/gateway/deserialization/racelog/impl/RaceLogFinishPositioningListChangedEventDeserializer.java @@ -1,59 +1,25 @@ package com.sap.sailing.server.gateway.deserialization.racelog.impl; import java.io.Serializable; -import java.util.List; - -import org.json.simple.JSONArray; -import org.json.simple.JSONObject; import com.sap.sailing.domain.abstractlog.AbstractLogEventAuthor; import com.sap.sailing.domain.abstractlog.race.CompetitorResults; -import com.sap.sailing.domain.abstractlog.race.RaceLogEvent; -import com.sap.sailing.domain.abstractlog.race.impl.CompetitorResultsImpl; +import com.sap.sailing.domain.abstractlog.race.RaceLogFinishPositioningEvent; import com.sap.sailing.domain.abstractlog.race.impl.RaceLogFinishPositioningListChangedEventImpl; import com.sap.sailing.domain.base.Competitor; -import com.sap.sailing.domain.common.MaxPointsReason; -import com.sap.sailing.server.gateway.deserialization.JsonDeserializationException; import com.sap.sailing.server.gateway.deserialization.JsonDeserializer; -import com.sap.sailing.server.gateway.deserialization.impl.Helpers; -import com.sap.sailing.server.gateway.serialization.racelog.impl.RaceLogFinishPositioningListChangedEventSerializer; import com.sap.sse.common.TimePoint; -import com.sap.sse.common.Util; -public class RaceLogFinishPositioningListChangedEventDeserializer extends BaseRaceLogEventDeserializer { +public class RaceLogFinishPositioningListChangedEventDeserializer extends RaceLogFinishPositioningEventDeserializer { public RaceLogFinishPositioningListChangedEventDeserializer(JsonDeserializer competitorDeserializer) { super(competitorDeserializer); } @Override - protected RaceLogEvent deserialize(JSONObject object, Serializable id, TimePoint createdAt, AbstractLogEventAuthor author, TimePoint timePoint, int passId, List competitors) - throws JsonDeserializationException { - - JSONArray jsonPositionedCompetitors = Helpers.getNestedArraySafe(object, RaceLogFinishPositioningListChangedEventSerializer.FIELD_POSITIONED_COMPETITORS); - CompetitorResults positionedCompetitors = deserializePositionedCompetitors(jsonPositionedCompetitors); - + protected RaceLogFinishPositioningEvent createRaceLogFinishPositioningEvent(Serializable id, + TimePoint createdAt, AbstractLogEventAuthor author, TimePoint timePoint, int passId, + CompetitorResults positionedCompetitors) { return new RaceLogFinishPositioningListChangedEventImpl(createdAt, timePoint, author, id, passId, positionedCompetitors); } - - private CompetitorResults deserializePositionedCompetitors(JSONArray jsonPositionedCompetitors) throws JsonDeserializationException { - CompetitorResults positionedCompetitors = new CompetitorResultsImpl(); - - for (Object object : jsonPositionedCompetitors) { - JSONObject jsonPositionedCompetitor = Helpers.toJSONObjectSafe(object); - - Serializable competitorId = (Serializable) jsonPositionedCompetitor.get(RaceLogFinishPositioningListChangedEventSerializer.FIELD_COMPETITOR_ID); - competitorId = Helpers.tryUuidConversion(competitorId); - String competitorName = (String) jsonPositionedCompetitor.get(RaceLogFinishPositioningListChangedEventSerializer.FIELD_COMPETITOR_NAME); - - String maxPointsReasonName = (String) jsonPositionedCompetitor.get(RaceLogFinishPositioningListChangedEventSerializer.FIELD_SCORE_CORRECTIONS_MAX_POINTS_REASON); - MaxPointsReason maxPointsReason = MaxPointsReason.valueOf(maxPointsReasonName); - - Util.Triple positionedCompetitor = new Util.Triple(competitorId, competitorName, maxPointsReason); - positionedCompetitors.add(positionedCompetitor); - } - - return positionedCompetitors; - } - } diff --git a/java/com.sap.sailing.server.gateway.serialization.shared.android/src/com/sap/sailing/server/gateway/deserialization/racelog/impl/RaceLogUseCompetitorsFromRaceLogEventDeserializer.java b/java/com.sap.sailing.server.gateway.serialization.shared.android/src/com/sap/sailing/server/gateway/deserialization/racelog/impl/RaceLogUseCompetitorsFromRaceLogEventDeserializer.java new file mode 100644 index 00000000000..b04801428cd --- /dev/null +++ b/java/com.sap.sailing.server.gateway.serialization.shared.android/src/com/sap/sailing/server/gateway/deserialization/racelog/impl/RaceLogUseCompetitorsFromRaceLogEventDeserializer.java @@ -0,0 +1,30 @@ +package com.sap.sailing.server.gateway.deserialization.racelog.impl; + +import java.io.Serializable; +import java.util.List; + +import org.json.simple.JSONObject; + +import com.sap.sailing.domain.abstractlog.AbstractLogEventAuthor; +import com.sap.sailing.domain.abstractlog.race.RaceLogEvent; +import com.sap.sailing.domain.abstractlog.race.tracking.impl.RaceLogUseCompetitorsFromRaceLogEventImpl; +import com.sap.sailing.domain.base.Competitor; +import com.sap.sailing.server.gateway.deserialization.JsonDeserializationException; +import com.sap.sailing.server.gateway.deserialization.JsonDeserializer; +import com.sap.sse.common.TimePoint; + +public class RaceLogUseCompetitorsFromRaceLogEventDeserializer extends BaseRaceLogEventDeserializer implements + JsonDeserializer { + + public RaceLogUseCompetitorsFromRaceLogEventDeserializer(JsonDeserializer competitorDeserializer) { + super(competitorDeserializer); + } + + @Override + protected RaceLogEvent deserialize(JSONObject object, Serializable id, TimePoint createdAt, + AbstractLogEventAuthor author, TimePoint timePoint, int passId, List competitors) + throws JsonDeserializationException { + return new RaceLogUseCompetitorsFromRaceLogEventImpl(createdAt, author, timePoint, id, passId); + } + +} diff --git a/java/com.sap.sailing.server.gateway.serialization.shared.android/src/com/sap/sailing/server/gateway/serialization/racelog/impl/RaceLogCloseOpenEndedDeviceMappingEventSerializer.java b/java/com.sap.sailing.server.gateway.serialization.shared.android/src/com/sap/sailing/server/gateway/serialization/racelog/impl/RaceLogCloseOpenEndedDeviceMappingEventSerializer.java deleted file mode 100644 index dc7648ade71..00000000000 --- a/java/com.sap.sailing.server.gateway.serialization.shared.android/src/com/sap/sailing/server/gateway/serialization/racelog/impl/RaceLogCloseOpenEndedDeviceMappingEventSerializer.java +++ /dev/null @@ -1,35 +0,0 @@ -package com.sap.sailing.server.gateway.serialization.racelog.impl; - -import org.json.simple.JSONObject; - -import com.sap.sailing.domain.abstractlog.race.RaceLogEvent; -import com.sap.sailing.domain.abstractlog.race.tracking.RaceLogCloseOpenEndedDeviceMappingEvent; -import com.sap.sailing.domain.abstractlog.shared.events.CloseOpenEndedDeviceMappingEvent; -import com.sap.sailing.domain.base.Competitor; -import com.sap.sailing.server.gateway.deserialization.racelog.impl.RaceLogCloseOpenEndedDeviceMappingEventDeserializer; -import com.sap.sailing.server.gateway.serialization.JsonSerializer; - -public class RaceLogCloseOpenEndedDeviceMappingEventSerializer extends BaseRaceLogEventSerializer { - public static final String VALUE_CLASS = CloseOpenEndedDeviceMappingEvent.class.getSimpleName(); - - public RaceLogCloseOpenEndedDeviceMappingEventSerializer(JsonSerializer competitorSerializer) { - super(competitorSerializer); - } - - @Override - protected String getClassFieldValue() { - return VALUE_CLASS; - } - - @Override - public JSONObject serialize(RaceLogEvent object) { - RaceLogCloseOpenEndedDeviceMappingEvent event = (RaceLogCloseOpenEndedDeviceMappingEvent) object; - - JSONObject result = super.serialize(event); - result.put(RaceLogCloseOpenEndedDeviceMappingEventDeserializer.FIELD_DEVICE_MAPPING_EVENT_ID, event.getDeviceMappingEventId()); - result.put(RaceLogCloseOpenEndedDeviceMappingEventDeserializer.FIELD_CLOSING_TIMEPOINT_MILLIS, event.getClosingTimePoint().asMillis()); - - return result; - } - -} diff --git a/java/com.sap.sailing.server.gateway.serialization.shared.android/src/com/sap/sailing/server/gateway/serialization/racelog/impl/RaceLogDefineMarkEventSerializer.java b/java/com.sap.sailing.server.gateway.serialization.shared.android/src/com/sap/sailing/server/gateway/serialization/racelog/impl/RaceLogDefineMarkEventSerializer.java deleted file mode 100644 index 6085a0674b6..00000000000 --- a/java/com.sap.sailing.server.gateway.serialization.shared.android/src/com/sap/sailing/server/gateway/serialization/racelog/impl/RaceLogDefineMarkEventSerializer.java +++ /dev/null @@ -1,38 +0,0 @@ -package com.sap.sailing.server.gateway.serialization.racelog.impl; - -import org.json.simple.JSONObject; - -import com.sap.sailing.domain.abstractlog.race.RaceLogEvent; -import com.sap.sailing.domain.abstractlog.race.tracking.RaceLogDefineMarkEvent; -import com.sap.sailing.domain.base.Competitor; -import com.sap.sailing.domain.base.ControlPoint; -import com.sap.sailing.server.gateway.serialization.JsonSerializer; - -public class RaceLogDefineMarkEventSerializer extends BaseRaceLogEventSerializer { - public static final String VALUE_CLASS = RaceLogDefineMarkEvent.class.getSimpleName(); - public static final String FIELD_MARK = "mark"; - - private final JsonSerializer markSerializer; - - public RaceLogDefineMarkEventSerializer( - JsonSerializer competitorSerializer, JsonSerializer markSerializer) { - super(competitorSerializer); - this.markSerializer = markSerializer; - } - - @Override - protected String getClassFieldValue() { - return VALUE_CLASS; - } - - @Override - public JSONObject serialize(RaceLogEvent object) { - RaceLogDefineMarkEvent event = (RaceLogDefineMarkEvent) object; - - JSONObject result = super.serialize(event); - result.put(FIELD_MARK, markSerializer.serialize(event.getMark())); - - return result; - } - -} diff --git a/java/com.sap.sailing.server.gateway.serialization.shared.android/src/com/sap/sailing/server/gateway/serialization/racelog/impl/RaceLogDeviceCompetitorMappingEventSerializer.java b/java/com.sap.sailing.server.gateway.serialization.shared.android/src/com/sap/sailing/server/gateway/serialization/racelog/impl/RaceLogDeviceCompetitorMappingEventSerializer.java deleted file mode 100644 index 424a12d1ff7..00000000000 --- a/java/com.sap.sailing.server.gateway.serialization.shared.android/src/com/sap/sailing/server/gateway/serialization/racelog/impl/RaceLogDeviceCompetitorMappingEventSerializer.java +++ /dev/null @@ -1,28 +0,0 @@ -package com.sap.sailing.server.gateway.serialization.racelog.impl; - -import org.json.simple.JSONObject; - -import com.sap.sailing.domain.abstractlog.shared.events.DeviceCompetitorMappingEvent; -import com.sap.sailing.domain.base.Competitor; -import com.sap.sailing.domain.racelogtracking.DeviceIdentifier; -import com.sap.sailing.server.gateway.serialization.JsonSerializer; - -public class RaceLogDeviceCompetitorMappingEventSerializer extends RaceLogDeviceMappingEventSerializer { - public static final String VALUE_CLASS = DeviceCompetitorMappingEvent.class.getSimpleName(); - - public RaceLogDeviceCompetitorMappingEventSerializer( - JsonSerializer competitorSerializer, - JsonSerializer deviceSerializer) { - super(competitorSerializer, deviceSerializer); - } - - @Override - protected String getClassFieldValue() { - return VALUE_CLASS; - } - - @Override - protected JSONObject serializeItem(Competitor item) { - return competitorSerializer.serialize(item); - } -} diff --git a/java/com.sap.sailing.server.gateway.serialization.shared.android/src/com/sap/sailing/server/gateway/serialization/racelog/impl/RaceLogDeviceMappingEventSerializer.java b/java/com.sap.sailing.server.gateway.serialization.shared.android/src/com/sap/sailing/server/gateway/serialization/racelog/impl/RaceLogDeviceMappingEventSerializer.java deleted file mode 100644 index 5629f84da5d..00000000000 --- a/java/com.sap.sailing.server.gateway.serialization.shared.android/src/com/sap/sailing/server/gateway/serialization/racelog/impl/RaceLogDeviceMappingEventSerializer.java +++ /dev/null @@ -1,39 +0,0 @@ -package com.sap.sailing.server.gateway.serialization.racelog.impl; - -import org.json.simple.JSONObject; - -import com.sap.sailing.domain.abstractlog.race.RaceLogEvent; -import com.sap.sailing.domain.abstractlog.shared.events.DeviceMappingEvent; -import com.sap.sailing.domain.base.Competitor; -import com.sap.sailing.domain.racelogtracking.DeviceIdentifier; -import com.sap.sailing.server.gateway.serialization.JsonSerializer; -import com.sap.sse.common.WithID; - -public abstract class RaceLogDeviceMappingEventSerializer extends BaseRaceLogEventSerializer { - private final JsonSerializer deviceSerializer; - public static final String FIELD_ITEM = "item"; - public static final String FIELD_DEVICE = "device"; - public static final String FIELD_FROM_MILLIS = "fromMillis"; - public static final String FIELD_TO_MILLIS = "toMillis"; - - public RaceLogDeviceMappingEventSerializer(JsonSerializer competitorSerializer, - JsonSerializer deviceSerializer) { - super(competitorSerializer); - this.deviceSerializer = deviceSerializer; - } - - protected abstract JSONObject serializeItem(ItemT item); - - @Override - public JSONObject serialize(RaceLogEvent object) { - @SuppressWarnings("unchecked") - DeviceMappingEvent event = (DeviceMappingEvent) object; - JSONObject result = super.serialize(object); - result.put(FIELD_FROM_MILLIS, event.getFrom().asMillis()); - result.put(FIELD_TO_MILLIS, event.getTo().asMillis()); - result.put(FIELD_ITEM, serializeItem(event.getMappedTo())); - result.put(FIELD_DEVICE, deviceSerializer.serialize(event.getDevice())); - return result; - } - -} diff --git a/java/com.sap.sailing.server.gateway.serialization.shared.android/src/com/sap/sailing/server/gateway/serialization/racelog/impl/RaceLogDeviceMarkMappingEventSerializer.java b/java/com.sap.sailing.server.gateway.serialization.shared.android/src/com/sap/sailing/server/gateway/serialization/racelog/impl/RaceLogDeviceMarkMappingEventSerializer.java deleted file mode 100644 index aa5bbf0a571..00000000000 --- a/java/com.sap.sailing.server.gateway.serialization.shared.android/src/com/sap/sailing/server/gateway/serialization/racelog/impl/RaceLogDeviceMarkMappingEventSerializer.java +++ /dev/null @@ -1,32 +0,0 @@ -package com.sap.sailing.server.gateway.serialization.racelog.impl; - -import org.json.simple.JSONObject; - -import com.sap.sailing.domain.abstractlog.shared.events.DeviceMarkMappingEvent; -import com.sap.sailing.domain.base.Competitor; -import com.sap.sailing.domain.base.ControlPoint; -import com.sap.sailing.domain.base.Mark; -import com.sap.sailing.domain.racelogtracking.DeviceIdentifier; -import com.sap.sailing.server.gateway.serialization.JsonSerializer; - -public class RaceLogDeviceMarkMappingEventSerializer extends RaceLogDeviceMappingEventSerializer { - public static final String VALUE_CLASS = DeviceMarkMappingEvent.class.getSimpleName(); - private final JsonSerializer markSerializer; - - public RaceLogDeviceMarkMappingEventSerializer( - JsonSerializer competitorSerializer, JsonSerializer markSerializer, - JsonSerializer deviceSerializer) { - super(competitorSerializer, deviceSerializer); - this.markSerializer = markSerializer; - } - - @Override - protected String getClassFieldValue() { - return VALUE_CLASS; - } - - @Override - protected JSONObject serializeItem(Mark item) { - return markSerializer.serialize(item); - } -} diff --git a/java/com.sap.sailing.server.gateway.serialization.shared.android/src/com/sap/sailing/server/gateway/serialization/racelog/impl/RaceLogEventSerializer.java b/java/com.sap.sailing.server.gateway.serialization.shared.android/src/com/sap/sailing/server/gateway/serialization/racelog/impl/RaceLogEventSerializer.java index 13b39ac2c7c..9f466062a45 100644 --- a/java/com.sap.sailing.server.gateway.serialization.shared.android/src/com/sap/sailing/server/gateway/serialization/racelog/impl/RaceLogEventSerializer.java +++ b/java/com.sap.sailing.server.gateway.serialization.shared.android/src/com/sap/sailing/server/gateway/serialization/racelog/impl/RaceLogEventSerializer.java @@ -24,13 +24,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; import com.sap.sailing.domain.base.Competitor; import com.sap.sailing.domain.racelogtracking.DeviceIdentifier; import com.sap.sailing.domain.racelogtracking.SmartphoneUUIDIdentifier; @@ -74,21 +71,17 @@ public class RaceLogEventSerializer implements JsonSerializer, Rac new RaceLogWindFixEventSerializer(competitorSerializer, new WindJsonSerializer( new PositionJsonSerializer())), - new RaceLogDeviceCompetitorMappingEventSerializer(competitorSerializer, deviceSerializer), - new RaceLogDeviceMarkMappingEventSerializer(competitorSerializer, new MarkJsonSerializer(), deviceSerializer), new RaceLogDenoteForTrackingEventSerializer(competitorSerializer), new RaceLogStartTrackingEventSerializer(competitorSerializer), new RaceLogRevokeEventSerializer(competitorSerializer), new RaceLogRegisterCompetitorEventSerializer(competitorSerializer), - new RaceLogDefineMarkEventSerializer(competitorSerializer, new MarkJsonSerializer()), - new RaceLogCloseOpenEndedDeviceMappingEventSerializer(competitorSerializer), new RaceLogAdditionalScoringInformationSerializer(competitorSerializer), new RaceLogFixedMarkPassingEventSerializer(competitorSerializer), new RaceLogSuppressedMarkPassingsEventSerializer(competitorSerializer), new RaceLogDependentStartTimeEventSerializer(competitorSerializer), new RaceLogStartOfTrackingEventSerializer(competitorSerializer), + new RaceLogUseCompetitorsFromRaceLogEventSerializer(competitorSerializer), new RaceLogEndOfTrackingEventSerializer(competitorSerializer)); - } private final JsonSerializer flagEventSerializer; @@ -104,20 +97,17 @@ public class RaceLogEventSerializer implements JsonSerializer, Rac private final JsonSerializer startProcedureChangedEventSerializer; private final JsonSerializer protestStartTimeEventSerializer; private final JsonSerializer windFixEventSerializer; - private final JsonSerializer deviceCompetitorMappingSerializer; - private final JsonSerializer deviceMarkMappingSerializer; private final JsonSerializer denoteForTrackingSerializer; private final JsonSerializer startTrackingSerializer; private final JsonSerializer revokeSerializer; private final JsonSerializer registerCompetitorSerializer; - private final JsonSerializer defineMarkSerializer; - private final JsonSerializer closeOpenEndedDeviceMappingEventSerializer; private final JsonSerializer additionalScoringInformationSerializer; private final JsonSerializer fixedMarkPassingEventSerializer; private final JsonSerializer suppressedMarkPassingsEventSerializer; private final JsonSerializer dependentStartTimeEventSerializer; private final JsonSerializer startOfTrackingEventSerializer; private final JsonSerializer endOfTrackingEventSerializer; + private final JsonSerializer useCompetitorsFromRaceLogEventSerializer; private JsonSerializer chosenSerializer; @@ -136,20 +126,17 @@ public class RaceLogEventSerializer implements JsonSerializer, Rac JsonSerializer startProcedureChangedEventSerializer, JsonSerializer protestStartTimeEventSerializer, JsonSerializer windFixEventSerializer, - JsonSerializer deviceCompetitorMappingSerializer, - JsonSerializer deviceMarkMappingSerializer, JsonSerializer denoteForTrackingSerializer, JsonSerializer createRaceSerializer, JsonSerializer revokeSerializer, JsonSerializer registerCompetitorSerializer, - JsonSerializer defineMarkSerializer, - JsonSerializer closeOpenEndedDeviceMappingEventSerializer, JsonSerializer additionalScoringInformationSerializer, JsonSerializer fixedMarkPassingEventSerializer, JsonSerializer suppressedMarkPassingsSerializer, JsonSerializer dependentStartTimeEventSerializer, JsonSerializer startOfTrackingEventSerializer, - JsonSerializer endOfTrackingEventSerializer) { + JsonSerializer endOfTrackingEventSerializer, + JsonSerializer useCompetitorsFromRaceLogEventSerializer) { this.flagEventSerializer = flagEventSerializer; this.startTimeSerializer = startTimeSerializer; this.raceStatusSerializer = raceStatusSerializer; @@ -163,20 +150,17 @@ public class RaceLogEventSerializer implements JsonSerializer, Rac this.startProcedureChangedEventSerializer = startProcedureChangedEventSerializer; this.protestStartTimeEventSerializer = protestStartTimeEventSerializer; this.windFixEventSerializer = windFixEventSerializer; - this.deviceCompetitorMappingSerializer = deviceCompetitorMappingSerializer; - this.deviceMarkMappingSerializer = deviceMarkMappingSerializer; this.denoteForTrackingSerializer = denoteForTrackingSerializer; this.startTrackingSerializer = createRaceSerializer; this.revokeSerializer = revokeSerializer; this.registerCompetitorSerializer = registerCompetitorSerializer; - this.defineMarkSerializer = defineMarkSerializer; - this.closeOpenEndedDeviceMappingEventSerializer = closeOpenEndedDeviceMappingEventSerializer; this.additionalScoringInformationSerializer = additionalScoringInformationSerializer; this.fixedMarkPassingEventSerializer = fixedMarkPassingEventSerializer; this.suppressedMarkPassingsEventSerializer = suppressedMarkPassingsSerializer; this.dependentStartTimeEventSerializer = dependentStartTimeEventSerializer; this.startOfTrackingEventSerializer = startOfTrackingEventSerializer; this.endOfTrackingEventSerializer = endOfTrackingEventSerializer; + this.useCompetitorsFromRaceLogEventSerializer = useCompetitorsFromRaceLogEventSerializer; this.chosenSerializer = null; } @@ -262,16 +246,6 @@ public class RaceLogEventSerializer implements JsonSerializer, Rac chosenSerializer = windFixEventSerializer; } - @Override - public void visit(RaceLogDeviceCompetitorMappingEvent event) { - chosenSerializer = deviceCompetitorMappingSerializer; - } - - @Override - public void visit(RaceLogDeviceMarkMappingEvent event) { - chosenSerializer = deviceMarkMappingSerializer; - } - @Override public void visit(RaceLogDenoteForTrackingEvent event) { chosenSerializer = denoteForTrackingSerializer; @@ -288,27 +262,15 @@ public class RaceLogEventSerializer implements JsonSerializer, Rac public void visit(RaceLogRegisterCompetitorEvent event) { chosenSerializer = registerCompetitorSerializer; } - - @Override - public void visit(RaceLogDefineMarkEvent event) { - chosenSerializer = defineMarkSerializer; - } - @Override - public void visit(RaceLogCloseOpenEndedDeviceMappingEvent event) { - chosenSerializer = closeOpenEndedDeviceMappingEventSerializer; - } - @Override public void visit(RaceLogAdditionalScoringInformationEvent additionalScoringInformation) { chosenSerializer = additionalScoringInformationSerializer; - } - @Override + @Override public void visit(RaceLogFixedMarkPassingEvent event) { chosenSerializer = fixedMarkPassingEventSerializer; - } @Override @@ -330,4 +292,9 @@ public class RaceLogEventSerializer implements JsonSerializer, Rac public void visit(RaceLogEndOfTrackingEvent event) { chosenSerializer = endOfTrackingEventSerializer; } + + @Override + public void visit(RaceLogUseCompetitorsFromRaceLogEvent event) { + chosenSerializer = useCompetitorsFromRaceLogEventSerializer; + } } diff --git a/java/com.sap.sailing.server.gateway.serialization.shared.android/src/com/sap/sailing/server/gateway/serialization/racelog/impl/RaceLogFinishPositioningConfirmedEventSerializer.java b/java/com.sap.sailing.server.gateway.serialization.shared.android/src/com/sap/sailing/server/gateway/serialization/racelog/impl/RaceLogFinishPositioningConfirmedEventSerializer.java index d755014ad47..31af1458cf2 100644 --- a/java/com.sap.sailing.server.gateway.serialization.shared.android/src/com/sap/sailing/server/gateway/serialization/racelog/impl/RaceLogFinishPositioningConfirmedEventSerializer.java +++ b/java/com.sap.sailing.server.gateway.serialization.shared.android/src/com/sap/sailing/server/gateway/serialization/racelog/impl/RaceLogFinishPositioningConfirmedEventSerializer.java @@ -1,27 +1,13 @@ package com.sap.sailing.server.gateway.serialization.racelog.impl; -import java.io.Serializable; -import java.util.List; - -import org.json.simple.JSONArray; -import org.json.simple.JSONObject; - -import com.sap.sailing.domain.abstractlog.race.RaceLogEvent; import com.sap.sailing.domain.abstractlog.race.RaceLogFinishPositioningConfirmedEvent; import com.sap.sailing.domain.base.Competitor; -import com.sap.sailing.domain.common.MaxPointsReason; import com.sap.sailing.server.gateway.serialization.JsonSerializer; -import com.sap.sse.common.Util; -public class RaceLogFinishPositioningConfirmedEventSerializer extends BaseRaceLogEventSerializer { +public class RaceLogFinishPositioningConfirmedEventSerializer extends RaceLogFinishPositioningEventSerializer { public static final String VALUE_CLASS = RaceLogFinishPositioningConfirmedEvent.class.getSimpleName(); - public static final String FIELD_POSITIONED_COMPETITORS = "positionedCompetitors"; - public static final String FIELD_COMPETITOR_ID = "competitorId"; - public static final String FIELD_COMPETITOR_NAME = "competitorName"; - public static final String FIELD_SCORE_CORRECTIONS_MAX_POINTS_REASON = "maxPointsReason"; - public RaceLogFinishPositioningConfirmedEventSerializer(JsonSerializer competitorSerializer) { super(competitorSerializer); } @@ -30,33 +16,4 @@ public class RaceLogFinishPositioningConfirmedEventSerializer extends BaseRaceLo protected String getClassFieldValue() { return VALUE_CLASS; } - - @Override - public JSONObject serialize(RaceLogEvent object) { - RaceLogFinishPositioningConfirmedEvent finishPositioningConfirmedEvent = (RaceLogFinishPositioningConfirmedEvent) object; - - JSONObject result = super.serialize(finishPositioningConfirmedEvent); - - result.put(FIELD_POSITIONED_COMPETITORS, serializePositionedCompetitors(finishPositioningConfirmedEvent.getPositionedCompetitorsIDsNamesMaxPointsReasons())); - - return result; - } - - private JSONArray serializePositionedCompetitors(List> positionedCompetitors) { - JSONArray jsonPositionedCompetitors = new JSONArray(); - - if (positionedCompetitors != null) { // for backwards compatibility reasons - for (Util.Triple positionedCompetitor : positionedCompetitors) { - JSONObject jsonPositionedCompetitor = new JSONObject(); - - jsonPositionedCompetitor.put(FIELD_COMPETITOR_ID, positionedCompetitor.getA().toString()); - jsonPositionedCompetitor.put(FIELD_COMPETITOR_NAME, positionedCompetitor.getB()); - jsonPositionedCompetitor.put(FIELD_SCORE_CORRECTIONS_MAX_POINTS_REASON, positionedCompetitor.getC().name()); - jsonPositionedCompetitors.add(jsonPositionedCompetitor); - } - } - - return jsonPositionedCompetitors; - } - } diff --git a/java/com.sap.sailing.server.gateway.serialization.shared.android/src/com/sap/sailing/server/gateway/serialization/racelog/impl/RaceLogFinishPositioningEventSerializer.java b/java/com.sap.sailing.server.gateway.serialization.shared.android/src/com/sap/sailing/server/gateway/serialization/racelog/impl/RaceLogFinishPositioningEventSerializer.java new file mode 100644 index 00000000000..875fc490c6f --- /dev/null +++ b/java/com.sap.sailing.server.gateway.serialization.shared.android/src/com/sap/sailing/server/gateway/serialization/racelog/impl/RaceLogFinishPositioningEventSerializer.java @@ -0,0 +1,56 @@ +package com.sap.sailing.server.gateway.serialization.racelog.impl; + +import org.json.simple.JSONArray; +import org.json.simple.JSONObject; + +import com.sap.sailing.domain.abstractlog.race.CompetitorResult; +import com.sap.sailing.domain.abstractlog.race.CompetitorResults; +import com.sap.sailing.domain.abstractlog.race.RaceLogEvent; +import com.sap.sailing.domain.abstractlog.race.RaceLogFinishPositioningEvent; +import com.sap.sailing.domain.base.Competitor; +import com.sap.sailing.server.gateway.serialization.JsonSerializer; + +public abstract class RaceLogFinishPositioningEventSerializer extends BaseRaceLogEventSerializer { + public static final String FIELD_POSITIONED_COMPETITORS = "positionedCompetitors"; + public static final String FIELD_COMPETITOR_ID = "competitorId"; + public static final String FIELD_COMPETITOR_NAME = "competitorName"; + public static final String FIELD_SCORE_CORRECTIONS_MAX_POINTS_REASON = "maxPointsReason"; + public static final String FIELD_SCORE = "score"; + public static final String FIELD_COMMENT = "comment"; + public static final String FIELD_RANK = "rank"; + public static final String FIELD_FINISHING_TIME_POINT_AS_MILLIS = "finishingTimePointAsMillis"; + + public RaceLogFinishPositioningEventSerializer(JsonSerializer competitorSerializer) { + super(competitorSerializer); + } + + @Override + protected abstract String getClassFieldValue(); + + @Override + public JSONObject serialize(RaceLogEvent object) { + RaceLogFinishPositioningEvent finishPositioningConfirmedEvent = (RaceLogFinishPositioningEvent) object; + JSONObject result = super.serialize(finishPositioningConfirmedEvent); + result.put(FIELD_POSITIONED_COMPETITORS, serializePositionedCompetitors(finishPositioningConfirmedEvent.getPositionedCompetitorsIDsNamesMaxPointsReasons())); + return result; + } + + private JSONArray serializePositionedCompetitors(CompetitorResults positionedCompetitors) { + JSONArray jsonPositionedCompetitors = new JSONArray(); + if (positionedCompetitors != null) { // for backwards compatibility reasons + for (CompetitorResult positionedCompetitor : positionedCompetitors) { + JSONObject jsonPositionedCompetitor = new JSONObject(); + jsonPositionedCompetitor.put(FIELD_COMPETITOR_ID, positionedCompetitor.getCompetitorId().toString()); + jsonPositionedCompetitor.put(FIELD_COMPETITOR_NAME, positionedCompetitor.getCompetitorDisplayName()); + jsonPositionedCompetitor.put(FIELD_SCORE_CORRECTIONS_MAX_POINTS_REASON, positionedCompetitor.getMaxPointsReason().name()); + jsonPositionedCompetitor.put(FIELD_SCORE, positionedCompetitor.getScore()); + jsonPositionedCompetitor.put(FIELD_COMMENT, positionedCompetitor.getComment()); + jsonPositionedCompetitor.put(FIELD_RANK, positionedCompetitor.getOneBasedRank()); + jsonPositionedCompetitor.put(FIELD_FINISHING_TIME_POINT_AS_MILLIS, positionedCompetitor.getFinishingTime() == null ? null : positionedCompetitor.getFinishingTime().asMillis()); + jsonPositionedCompetitors.add(jsonPositionedCompetitor); + } + } + return jsonPositionedCompetitors; + } + +} diff --git a/java/com.sap.sailing.server.gateway.serialization.shared.android/src/com/sap/sailing/server/gateway/serialization/racelog/impl/RaceLogFinishPositioningListChangedEventSerializer.java b/java/com.sap.sailing.server.gateway.serialization.shared.android/src/com/sap/sailing/server/gateway/serialization/racelog/impl/RaceLogFinishPositioningListChangedEventSerializer.java index 209fd01064f..bc6c4a3fda2 100644 --- a/java/com.sap.sailing.server.gateway.serialization.shared.android/src/com/sap/sailing/server/gateway/serialization/racelog/impl/RaceLogFinishPositioningListChangedEventSerializer.java +++ b/java/com.sap.sailing.server.gateway.serialization.shared.android/src/com/sap/sailing/server/gateway/serialization/racelog/impl/RaceLogFinishPositioningListChangedEventSerializer.java @@ -1,25 +1,12 @@ package com.sap.sailing.server.gateway.serialization.racelog.impl; -import java.io.Serializable; -import java.util.List; - -import org.json.simple.JSONArray; -import org.json.simple.JSONObject; - -import com.sap.sailing.domain.abstractlog.race.RaceLogEvent; import com.sap.sailing.domain.abstractlog.race.RaceLogFinishPositioningListChangedEvent; import com.sap.sailing.domain.base.Competitor; -import com.sap.sailing.domain.common.MaxPointsReason; import com.sap.sailing.server.gateway.serialization.JsonSerializer; -import com.sap.sse.common.Util; -public class RaceLogFinishPositioningListChangedEventSerializer extends BaseRaceLogEventSerializer { +public class RaceLogFinishPositioningListChangedEventSerializer extends RaceLogFinishPositioningEventSerializer { public static final String VALUE_CLASS = RaceLogFinishPositioningListChangedEvent.class.getSimpleName(); - public static final String FIELD_POSITIONED_COMPETITORS = "positionedCompetitors"; - public static final String FIELD_COMPETITOR_ID = "competitorId"; - public static final String FIELD_COMPETITOR_NAME = "competitorName"; - public static final String FIELD_SCORE_CORRECTIONS_MAX_POINTS_REASON = "maxPointsReason"; public RaceLogFinishPositioningListChangedEventSerializer(JsonSerializer competitorSerializer) { super(competitorSerializer); @@ -29,31 +16,4 @@ public class RaceLogFinishPositioningListChangedEventSerializer extends BaseRace protected String getClassFieldValue() { return VALUE_CLASS; } - - @Override - public JSONObject serialize(RaceLogEvent object) { - RaceLogFinishPositioningListChangedEvent finishPositioningListEvent = (RaceLogFinishPositioningListChangedEvent) object; - - JSONObject result = super.serialize(finishPositioningListEvent); - - result.put(FIELD_POSITIONED_COMPETITORS, serializePositionedCompetitors(finishPositioningListEvent.getPositionedCompetitorsIDsNamesMaxPointsReasons())); - - return result; - } - - private JSONArray serializePositionedCompetitors(List> positionedCompetitors) { - JSONArray jsonPositionedCompetitors = new JSONArray(); - - for (Util.Triple positionedCompetitor : positionedCompetitors) { - JSONObject jsonPositionedCompetitor = new JSONObject(); - - jsonPositionedCompetitor.put(FIELD_COMPETITOR_ID, positionedCompetitor.getA().toString()); - jsonPositionedCompetitor.put(FIELD_COMPETITOR_NAME, positionedCompetitor.getB()); - jsonPositionedCompetitor.put(FIELD_SCORE_CORRECTIONS_MAX_POINTS_REASON, positionedCompetitor.getC().name()); - jsonPositionedCompetitors.add(jsonPositionedCompetitor); - } - - return jsonPositionedCompetitors; - } - } diff --git a/java/com.sap.sailing.server.gateway.serialization.shared.android/src/com/sap/sailing/server/gateway/serialization/racelog/impl/RaceLogUseCompetitorsFromRaceLogEventSerializer.java b/java/com.sap.sailing.server.gateway.serialization.shared.android/src/com/sap/sailing/server/gateway/serialization/racelog/impl/RaceLogUseCompetitorsFromRaceLogEventSerializer.java new file mode 100644 index 00000000000..3f31e7b2405 --- /dev/null +++ b/java/com.sap.sailing.server.gateway.serialization.shared.android/src/com/sap/sailing/server/gateway/serialization/racelog/impl/RaceLogUseCompetitorsFromRaceLogEventSerializer.java @@ -0,0 +1,21 @@ +package com.sap.sailing.server.gateway.serialization.racelog.impl; + +import com.sap.sailing.domain.abstractlog.race.RaceLogEvent; +import com.sap.sailing.domain.abstractlog.race.tracking.RaceLogUseCompetitorsFromRaceLogEvent; +import com.sap.sailing.domain.base.Competitor; +import com.sap.sailing.server.gateway.serialization.JsonSerializer; + +public class RaceLogUseCompetitorsFromRaceLogEventSerializer extends BaseRaceLogEventSerializer implements + JsonSerializer { + public static final String VALUE_CLASS = RaceLogUseCompetitorsFromRaceLogEvent.class.getSimpleName(); + + public RaceLogUseCompetitorsFromRaceLogEventSerializer(JsonSerializer competitorSerializer) { + super(competitorSerializer); + } + + @Override + protected String getClassFieldValue() { + return VALUE_CLASS; + } + +} diff --git a/java/com.sap.sailing.server.gateway.serialization.test/src/com/sap/sailing/server/gateway/serialization/test/racelog/RaceLogEventSerializerTest.java b/java/com.sap.sailing.server.gateway.serialization.test/src/com/sap/sailing/server/gateway/serialization/test/racelog/RaceLogEventSerializerTest.java index ac829c9c22d..f47dd00c129 100644 --- a/java/com.sap.sailing.server.gateway.serialization.test/src/com/sap/sailing/server/gateway/serialization/test/racelog/RaceLogEventSerializerTest.java +++ b/java/com.sap.sailing.server.gateway.serialization.test/src/com/sap/sailing/server/gateway/serialization/test/racelog/RaceLogEventSerializerTest.java @@ -25,11 +25,7 @@ import com.sap.sailing.domain.abstractlog.race.impl.RaceLogRevokeEventImpl; import com.sap.sailing.domain.abstractlog.race.impl.RaceLogStartProcedureChangedEventImpl; import com.sap.sailing.domain.abstractlog.race.impl.RaceLogStartTimeEventImpl; import com.sap.sailing.domain.abstractlog.race.impl.RaceLogWindFixEventImpl; -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.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.base.DomainFactory; @@ -56,19 +52,16 @@ public class RaceLogEventSerializerTest { private JsonSerializer startProcedureTypeChangedEventSerializer; private JsonSerializer protestStartTimeEventSerializer; private JsonSerializer windFixEventSerializer; - private JsonSerializer deviceCompetitorMappingEventSerializer; - private JsonSerializer deviceMarkMappingEventSerializer; private JsonSerializer denoteForTrackingEventSerializer; private JsonSerializer startTrackingEventSerializer; private JsonSerializer revokeEventSerializer; private JsonSerializer registerCompetitorEventSerializer; - private JsonSerializer defineMarkEventSerializer; - private JsonSerializer closeOpenEndedDeviceMappingEventSerializer; private JsonSerializer additionalScoringInformationSerializer; private JsonSerializer fixedMarkPassingEventSerializer; private JsonSerializer suppressedMarkPassingsSerializer; private JsonSerializer dependentStartTimeEventSerializer; private JsonSerializer startOfTrackingEventSerializer; + private JsonSerializer useCompetitorsFromRaceLogEventSerializer; private JsonSerializer endOfTrackingEventSerializer; private AbstractLogEventAuthor author = new LogEventAuthorImpl("Test Author", 1); @@ -89,19 +82,16 @@ public class RaceLogEventSerializerTest { startProcedureTypeChangedEventSerializer = mock(JsonSerializer.class); protestStartTimeEventSerializer = mock(JsonSerializer.class); windFixEventSerializer = mock(JsonSerializer.class); - deviceCompetitorMappingEventSerializer = mock(JsonSerializer.class); - deviceMarkMappingEventSerializer = mock(JsonSerializer.class); denoteForTrackingEventSerializer = mock(JsonSerializer.class); startTrackingEventSerializer = mock(JsonSerializer.class); revokeEventSerializer = mock(JsonSerializer.class); registerCompetitorEventSerializer = mock(JsonSerializer.class); - defineMarkEventSerializer = mock(JsonSerializer.class); - closeOpenEndedDeviceMappingEventSerializer = mock(JsonSerializer.class); additionalScoringInformationSerializer = mock(JsonSerializer.class); fixedMarkPassingEventSerializer = mock(JsonSerializer.class); suppressedMarkPassingsSerializer = mock(JsonSerializer.class); dependentStartTimeEventSerializer = mock(JsonSerializer.class); startOfTrackingEventSerializer = mock(JsonSerializer.class); + useCompetitorsFromRaceLogEventSerializer = mock(JsonSerializer.class); endOfTrackingEventSerializer = mock(JsonSerializer.class); serializer = new RaceLogEventSerializer(flagEventSerializer, startTimeSerializer, raceStatusSerializer, @@ -109,12 +99,11 @@ public class RaceLogEventSerializerTest { finishPositioningListChangedEventSerializer, finishPositioningConfirmedEventSerializer, pathfinderEventSerializer, gateLineOpeningTimeEventSerializer, startProcedureTypeChangedEventSerializer, protestStartTimeEventSerializer, windFixEventSerializer, - deviceCompetitorMappingEventSerializer, deviceMarkMappingEventSerializer, denoteForTrackingEventSerializer, startTrackingEventSerializer, revokeEventSerializer, - registerCompetitorEventSerializer, defineMarkEventSerializer, - closeOpenEndedDeviceMappingEventSerializer, fixedMarkPassingEventSerializer, - suppressedMarkPassingsSerializer, additionalScoringInformationSerializer, - dependentStartTimeEventSerializer, startOfTrackingEventSerializer, endOfTrackingEventSerializer); + registerCompetitorEventSerializer, fixedMarkPassingEventSerializer, suppressedMarkPassingsSerializer, + additionalScoringInformationSerializer, dependentStartTimeEventSerializer, + startOfTrackingEventSerializer, useCompetitorsFromRaceLogEventSerializer, + endOfTrackingEventSerializer); } @Test @@ -220,23 +209,7 @@ public class RaceLogEventSerializerTest { serializer.serialize(event); verify(windFixEventSerializer).serialize(event); } - - @Test - public void testDeviceCompetitorMappingSerializer() { - // we use the real event type here because we do not want to re-implement the dispatching. - RaceLogEvent event = new RaceLogDeviceCompetitorMappingEventImpl(null, author, 0, null, null, null, null); - serializer.serialize(event); - verify(deviceCompetitorMappingEventSerializer).serialize(event); - } - - @Test - public void testDeviceMarkMappingSerializer() { - // we use the real event type here because we do not want to re-implement the dispatching. - RaceLogEvent event = new RaceLogDeviceMarkMappingEventImpl(null, author, 0, null, null, null, null); - serializer.serialize(event); - verify(deviceMarkMappingEventSerializer).serialize(event); - } - + @Test public void testDenoteForTrackingSerializer() { // we use the real event type here because we do not want to re-implement the dispatching. @@ -272,20 +245,4 @@ public class RaceLogEventSerializerTest { serializer.serialize(event); verify(registerCompetitorEventSerializer).serialize(event); } - - @Test - public void testDefineMarkEventSerializer() { - // we use the real event type here because we do not want to re-implement the dispatching. - RaceLogEvent event = new RaceLogDefineMarkEventImpl(null, author, 0, null); - serializer.serialize(event); - verify(defineMarkEventSerializer).serialize(event); - } - - @Test - public void testCloseOpenEndedDeviceMappingEventSerializer() { - // we use the real event type here because we do not want to re-implement the dispatching. - RaceLogEvent event = new RaceLogCloseOpenEndedDeviceMappingEventImpl(null, author, 0, null, null); - serializer.serialize(event); - verify(closeOpenEndedDeviceMappingEventSerializer).serialize(event); - } } diff --git a/java/com.sap.sailing.server.gateway.serialization.test/src/com/sap/sailing/server/gateway/serialization/test/racelog/RaceLogFinishPositioningConfirmedEventSerializerTest.java b/java/com.sap.sailing.server.gateway.serialization.test/src/com/sap/sailing/server/gateway/serialization/test/racelog/RaceLogFinishPositioningConfirmedEventSerializerTest.java index 74e560a6bfd..9735e2dbb04 100644 --- a/java/com.sap.sailing.server.gateway.serialization.test/src/com/sap/sailing/server/gateway/serialization/test/racelog/RaceLogFinishPositioningConfirmedEventSerializerTest.java +++ b/java/com.sap.sailing.server.gateway.serialization.test/src/com/sap/sailing/server/gateway/serialization/test/racelog/RaceLogFinishPositioningConfirmedEventSerializerTest.java @@ -3,8 +3,9 @@ package com.sap.sailing.server.gateway.serialization.test.racelog; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; -import java.io.Serializable; +import java.util.Iterator; import java.util.UUID; import org.json.simple.JSONObject; @@ -13,8 +14,10 @@ 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.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.base.DomainFactory; @@ -52,10 +55,19 @@ public class RaceLogFinishPositioningConfirmedEventSerializerTest { positioningList = new CompetitorResultsImpl(); } + public static void assertCompetitorResultsEqual(final CompetitorResults expectedCompetitorResults, final CompetitorResults loadedCompetitorResults) { + assertEquals(Util.size(expectedCompetitorResults), Util.size(loadedCompetitorResults)); + final Iterator iExpected = expectedCompetitorResults.iterator(); + final Iterator iLoaded = loadedCompetitorResults.iterator(); + while (iExpected.hasNext()) { + assertEquals(iExpected.next(), iLoaded.next()); + } + } + @Test public void testSerializeAndDeserializeRaceLogFinishPositioningConfirmedEvent() throws JsonDeserializationException { - positioningList.add(new com.sap.sse.common.Util.Triple(UUID.randomUUID(), "SAP Extreme", - MaxPointsReason.NONE)); + positioningList.add(new CompetitorResultImpl(UUID.randomUUID(), "SAP Extreme", /* rank */ 1, + MaxPointsReason.NONE, /* score */ null, /* finishingTime */ null, /* comment */ null)); event = new RaceLogFinishPositioningConfirmedEventImpl(now, author, 0, positioningList); JSONObject jsonConfirmationEvent = serializer.serialize(event); RaceLogFinishPositioningConfirmedEvent deserializedEvent = (RaceLogFinishPositioningConfirmedEvent) deserializer @@ -68,14 +80,8 @@ public class RaceLogFinishPositioningConfirmedEventSerializerTest { assertEquals(0, Util.size(deserializedEvent.getInvolvedBoats())); assertNotNull(event.getPositionedCompetitorsIDsNamesMaxPointsReasons()); assertNotNull(deserializedEvent.getPositionedCompetitorsIDsNamesMaxPointsReasons()); - assertEquals(1, event.getPositionedCompetitorsIDsNamesMaxPointsReasons().size()); - assertEquals(1, deserializedEvent.getPositionedCompetitorsIDsNamesMaxPointsReasons().size()); - assertEquals(event.getPositionedCompetitorsIDsNamesMaxPointsReasons().get(0).getA(), deserializedEvent.getPositionedCompetitorsIDsNamesMaxPointsReasons() - .get(0).getA()); - assertEquals(event.getPositionedCompetitorsIDsNamesMaxPointsReasons().get(0).getB(), deserializedEvent.getPositionedCompetitorsIDsNamesMaxPointsReasons() - .get(0).getB()); - assertEquals(event.getPositionedCompetitorsIDsNamesMaxPointsReasons().get(0).getC(), deserializedEvent.getPositionedCompetitorsIDsNamesMaxPointsReasons() - .get(0).getC()); + assertEquals(1, Util.size(event.getPositionedCompetitorsIDsNamesMaxPointsReasons())); + assertCompetitorResultsEqual(event.getPositionedCompetitorsIDsNamesMaxPointsReasons(), deserializedEvent.getPositionedCompetitorsIDsNamesMaxPointsReasons()); } @Test @@ -93,7 +99,7 @@ public class RaceLogFinishPositioningConfirmedEventSerializerTest { assertEquals(0, Util.size(deserializedEvent.getInvolvedBoats())); assertNull(event.getPositionedCompetitorsIDsNamesMaxPointsReasons()); assertNotNull(deserializedEvent.getPositionedCompetitorsIDsNamesMaxPointsReasons()); - assertEquals(0, deserializedEvent.getPositionedCompetitorsIDsNamesMaxPointsReasons().size()); + assertTrue(Util.isEmpty(deserializedEvent.getPositionedCompetitorsIDsNamesMaxPointsReasons())); } @Test @@ -111,8 +117,8 @@ public class RaceLogFinishPositioningConfirmedEventSerializerTest { assertEquals(0, Util.size(deserializedEvent.getInvolvedBoats())); assertNotNull(event.getPositionedCompetitorsIDsNamesMaxPointsReasons()); assertNotNull(deserializedEvent.getPositionedCompetitorsIDsNamesMaxPointsReasons()); - assertEquals(0, event.getPositionedCompetitorsIDsNamesMaxPointsReasons().size()); - assertEquals(0, deserializedEvent.getPositionedCompetitorsIDsNamesMaxPointsReasons().size()); + assertTrue(Util.isEmpty(event.getPositionedCompetitorsIDsNamesMaxPointsReasons())); + assertTrue(Util.isEmpty(deserializedEvent.getPositionedCompetitorsIDsNamesMaxPointsReasons())); } } diff --git a/java/com.sap.sailing.server.gateway.test/src/com/sap/sailing/server/gateway/test/DeviceIdentifierSerializationTest.java b/java/com.sap.sailing.server.gateway.test/src/com/sap/sailing/server/gateway/test/DeviceIdentifierSerializationTest.java new file mode 100644 index 00000000000..76bcf92d04d --- /dev/null +++ b/java/com.sap.sailing.server.gateway.test/src/com/sap/sailing/server/gateway/test/DeviceIdentifierSerializationTest.java @@ -0,0 +1,66 @@ +package com.sap.sailing.server.gateway.test; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +import org.json.simple.JSONObject; +import org.junit.Before; +import org.junit.Test; + +import com.sap.sailing.domain.racelog.tracking.test.mock.MockEmptyServiceFinder; +import com.sap.sailing.domain.racelog.tracking.test.mock.SmartphoneImeiIdentifier; +import com.sap.sailing.domain.racelog.tracking.test.mock.SmartphoneImeiJsonHandler; +import com.sap.sailing.domain.racelogtracking.DeviceIdentifier; +import com.sap.sailing.domain.racelogtracking.PlaceHolderDeviceIdentifier; +import com.sap.sailing.domain.trackfiles.TrackFileImportDeviceIdentifierImpl; +import com.sap.sailing.server.gateway.deserialization.JsonDeserializationException; +import com.sap.sailing.server.gateway.deserialization.impl.DeviceIdentifierJsonDeserializer; +import com.sap.sailing.server.gateway.serialization.impl.DeviceIdentifierJsonSerializer; +import com.sap.sailing.server.gateway.serialization.racelog.tracking.DeviceIdentifierJsonHandler; +import com.sap.sailing.server.gateway.serialization.racelog.tracking.impl.PlaceHolderDeviceIdentifierJsonHandler; +import com.sap.sse.common.TypeBasedServiceFinder; + +public class DeviceIdentifierSerializationTest { + @Before + public void setup() { + } + + @Test + public void testSerializationOfDeviceIdentifier() throws JsonDeserializationException { + final DeviceIdentifierJsonDeserializer myDeserializer = DeviceIdentifierJsonDeserializer.create(new SmartphoneImeiJsonHandler(), SmartphoneImeiIdentifier.TYPE); + final DeviceIdentifierJsonSerializer mySerializer = DeviceIdentifierJsonSerializer.create(new SmartphoneImeiJsonHandler(), SmartphoneImeiIdentifier.TYPE); + DeviceIdentifier device = new SmartphoneImeiIdentifier("abc"); + JSONObject json = mySerializer.serialize(device); + DeviceIdentifier deserialized = myDeserializer.deserialize(json); + assertEquals(device, deserialized); + } + + @Test + public void testSerializationOfDeviceIdentifierWithNoSerializer() throws JsonDeserializationException { + TypeBasedServiceFinder onlyFallback = new MockEmptyServiceFinder<>(); + onlyFallback.setFallbackService(new PlaceHolderDeviceIdentifierJsonHandler()); + final DeviceIdentifierJsonDeserializer myDeserializer = new DeviceIdentifierJsonDeserializer(onlyFallback); + final DeviceIdentifierJsonSerializer mySerializer = DeviceIdentifierJsonSerializer.create(new SmartphoneImeiJsonHandler(), SmartphoneImeiIdentifier.TYPE); + DeviceIdentifier device = new SmartphoneImeiIdentifier("abc"); + JSONObject json = mySerializer.serialize(device); + DeviceIdentifier deserialized = myDeserializer.deserialize(json); + assertTrue(deserialized instanceof PlaceHolderDeviceIdentifier); + assertEquals(device.getStringRepresentation(), deserialized.getStringRepresentation()); + assertEquals(device.getIdentifierType(), deserialized.getIdentifierType()); + } + + @Test + public void testSerializationOfDeviceIdentifierWithNoDeserializer() throws JsonDeserializationException { + TypeBasedServiceFinder onlyFallback = new MockEmptyServiceFinder<>(); + onlyFallback.setFallbackService(new PlaceHolderDeviceIdentifierJsonHandler()); + final DeviceIdentifierJsonDeserializer myDeserializer = DeviceIdentifierJsonDeserializer.create(new SmartphoneImeiJsonHandler(), SmartphoneImeiIdentifier.TYPE); + final DeviceIdentifierJsonSerializer mySerializer = new DeviceIdentifierJsonSerializer(onlyFallback); + //track file device id can't be restored from string rep + DeviceIdentifier device = new TrackFileImportDeviceIdentifierImpl("file", "track"); + JSONObject json = mySerializer.serialize(device); + DeviceIdentifier deserialized = myDeserializer.deserialize(json); + assertTrue(deserialized instanceof PlaceHolderDeviceIdentifier); + assertEquals(device.getStringRepresentation(), deserialized.getStringRepresentation()); + assertEquals(device.getIdentifierType(), deserialized.getIdentifierType()); + } +} diff --git a/java/com.sap.sailing.server.gateway.test/src/com/sap/sailing/server/gateway/test/RaceLogSerializationTest.java b/java/com.sap.sailing.server.gateway.test/src/com/sap/sailing/server/gateway/test/RaceLogSerializationTest.java deleted file mode 100644 index 6a6054d6d2a..00000000000 --- a/java/com.sap.sailing.server.gateway.test/src/com/sap/sailing/server/gateway/test/RaceLogSerializationTest.java +++ /dev/null @@ -1,130 +0,0 @@ -package com.sap.sailing.server.gateway.test; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; - -import java.util.Collections; -import java.util.Date; - -import org.json.simple.JSONObject; -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.RaceLogEvent; -import com.sap.sailing.domain.abstractlog.race.tracking.RaceLogDeviceCompetitorMappingEvent; -import com.sap.sailing.domain.abstractlog.race.tracking.impl.RaceLogDeviceCompetitorMappingEventImpl; -import com.sap.sailing.domain.abstractlog.shared.events.DeviceCompetitorMappingEvent; -import com.sap.sailing.domain.base.Competitor; -import com.sap.sailing.domain.base.DomainFactory; -import com.sap.sailing.domain.base.impl.BoatClassImpl; -import com.sap.sailing.domain.base.impl.BoatImpl; -import com.sap.sailing.domain.base.impl.CompetitorImpl; -import com.sap.sailing.domain.base.impl.NationalityImpl; -import com.sap.sailing.domain.base.impl.PersonImpl; -import com.sap.sailing.domain.base.impl.TeamImpl; -import com.sap.sailing.domain.racelog.tracking.test.mock.MockEmptyServiceFinder; -import com.sap.sailing.domain.racelog.tracking.test.mock.SmartphoneImeiIdentifier; -import com.sap.sailing.domain.racelog.tracking.test.mock.SmartphoneImeiJsonHandler; -import com.sap.sailing.domain.racelogtracking.DeviceIdentifier; -import com.sap.sailing.domain.racelogtracking.PlaceHolderDeviceIdentifier; -import com.sap.sailing.domain.trackfiles.TrackFileImportDeviceIdentifierImpl; -import com.sap.sailing.server.gateway.deserialization.JsonDeserializationException; -import com.sap.sailing.server.gateway.deserialization.JsonDeserializer; -import com.sap.sailing.server.gateway.deserialization.impl.DeviceIdentifierJsonDeserializer; -import com.sap.sailing.server.gateway.deserialization.racelog.impl.RaceLogEventDeserializer; -import com.sap.sailing.server.gateway.serialization.JsonSerializer; -import com.sap.sailing.server.gateway.serialization.impl.CompetitorJsonSerializer; -import com.sap.sailing.server.gateway.serialization.impl.DeviceIdentifierJsonSerializer; -import com.sap.sailing.server.gateway.serialization.racelog.impl.RaceLogEventSerializer; -import com.sap.sailing.server.gateway.serialization.racelog.tracking.DeviceIdentifierJsonHandler; -import com.sap.sailing.server.gateway.serialization.racelog.tracking.impl.PlaceHolderDeviceIdentifierJsonHandler; -import com.sap.sse.common.TimePoint; -import com.sap.sse.common.TypeBasedServiceFinder; -import com.sap.sse.common.impl.MillisecondsTimePoint; - -public class RaceLogSerializationTest { - private JsonSerializer serializer; - private JsonDeserializer deserializer; - private final AbstractLogEventAuthor author = new LogEventAuthorImpl("test", 0); - private static final Competitor competitor = new CompetitorImpl("a", "b", null, - null, null, - new TeamImpl("a", Collections.singletonList(new PersonImpl("a", new NationalityImpl("GER"), new Date(), "abc")), null), new BoatImpl("a", new BoatClassImpl("a", true), "abc"), /* timeOnTimeFactor */ null, /* timeOnDistanceAllowancePerNauticalMile */ null); - - @Before - public void setup() { - } - - private void setup(JsonDeserializer deviceDeserializer, JsonSerializer deviceSerializer) { - JsonSerializer cSer = CompetitorJsonSerializer.create(); - serializer = RaceLogEventSerializer.create(cSer, deviceSerializer); - deserializer = RaceLogEventDeserializer.create(DomainFactory.INSTANCE, deviceDeserializer); - } - - private TimePoint t() { - return MillisecondsTimePoint.now(); - } - - @Test - public void testSerializationOfDeviceIdentifier() throws JsonDeserializationException { - setup(DeviceIdentifierJsonDeserializer.create(new SmartphoneImeiJsonHandler(), SmartphoneImeiIdentifier.TYPE), - DeviceIdentifierJsonSerializer.create(new SmartphoneImeiJsonHandler(), SmartphoneImeiIdentifier.TYPE)); - DeviceIdentifier device = new SmartphoneImeiIdentifier("abc"); - RaceLogDeviceCompetitorMappingEvent event = new RaceLogDeviceCompetitorMappingEventImpl( - t(), author, 0, competitor, device, t(), t()); - - JSONObject json = serializer.serialize(event); - - RaceLogEvent deserialized = deserializer.deserialize(json); - - assertTrue(deserialized instanceof DeviceCompetitorMappingEvent); - RaceLogDeviceCompetitorMappingEvent deserializedMapping = (RaceLogDeviceCompetitorMappingEvent) deserialized; - assertEquals(event.getDevice(), deserializedMapping.getDevice()); - } - - @Test - public void testSerializationOfDeviceIdentifierWithNoSerializer() throws JsonDeserializationException { - TypeBasedServiceFinder onlyFallback = new MockEmptyServiceFinder<>(); - onlyFallback.setFallbackService(new PlaceHolderDeviceIdentifierJsonHandler()); - - setup(new DeviceIdentifierJsonDeserializer(onlyFallback), - DeviceIdentifierJsonSerializer.create(new SmartphoneImeiJsonHandler(), SmartphoneImeiIdentifier.TYPE)); - DeviceIdentifier device = new SmartphoneImeiIdentifier("abc"); - RaceLogDeviceCompetitorMappingEvent event = new RaceLogDeviceCompetitorMappingEventImpl( - t(), author, 0, competitor, device, t(), t()); - - JSONObject json = serializer.serialize(event); - - RaceLogEvent deserialized = deserializer.deserialize(json); - - assertTrue(deserialized instanceof DeviceCompetitorMappingEvent); - RaceLogDeviceCompetitorMappingEvent deserializedMapping = (RaceLogDeviceCompetitorMappingEvent) deserialized; - assertTrue(deserializedMapping.getDevice() instanceof PlaceHolderDeviceIdentifier); - assertEquals(event.getDevice().getStringRepresentation(), deserializedMapping.getDevice().getStringRepresentation()); - assertEquals(event.getDevice().getIdentifierType(), deserializedMapping.getDevice().getIdentifierType()); - } - - @Test - public void testSerializationOfDeviceIdentifierWithNoDeserializer() throws JsonDeserializationException { - TypeBasedServiceFinder onlyFallback = new MockEmptyServiceFinder<>(); - onlyFallback.setFallbackService(new PlaceHolderDeviceIdentifierJsonHandler()); - - setup(DeviceIdentifierJsonDeserializer.create(new SmartphoneImeiJsonHandler(), SmartphoneImeiIdentifier.TYPE), - new DeviceIdentifierJsonSerializer(onlyFallback)); - //track file device id can't be restored from string rep - DeviceIdentifier device = new TrackFileImportDeviceIdentifierImpl("file", "track"); - RaceLogDeviceCompetitorMappingEvent event = new RaceLogDeviceCompetitorMappingEventImpl( - t(), author, 0, competitor, device, t(), t()); - - JSONObject json = serializer.serialize(event); - - RaceLogEvent deserialized = deserializer.deserialize(json); - - assertTrue(deserialized instanceof RaceLogDeviceCompetitorMappingEvent); - RaceLogDeviceCompetitorMappingEvent deserializedMapping = (RaceLogDeviceCompetitorMappingEvent) deserialized; - assertTrue(deserializedMapping.getDevice() instanceof PlaceHolderDeviceIdentifier); - assertEquals(event.getDevice().getStringRepresentation(), deserializedMapping.getDevice().getStringRepresentation()); - assertEquals(event.getDevice().getIdentifierType(), deserializedMapping.getDevice().getIdentifierType()); - } -} diff --git a/java/com.sap.sailing.server.gateway.test/src/com/sap/sailing/server/gateway/test/jaxrs/LeaderboardsResourceCheckinAndOutTest.java b/java/com.sap.sailing.server.gateway.test/src/com/sap/sailing/server/gateway/test/jaxrs/LeaderboardsResourceCheckinAndOutTest.java index f396795f3ec..ce41334c142 100644 --- a/java/com.sap.sailing.server.gateway.test/src/com/sap/sailing/server/gateway/test/jaxrs/LeaderboardsResourceCheckinAndOutTest.java +++ b/java/com.sap.sailing.server.gateway.test/src/com/sap/sailing/server/gateway/test/jaxrs/LeaderboardsResourceCheckinAndOutTest.java @@ -17,8 +17,8 @@ import org.junit.Before; import org.junit.Test; import com.sap.sailing.domain.abstractlog.regatta.RegattaLog; -import com.sap.sailing.domain.abstractlog.shared.analyzing.DeviceCompetitorMappingFinder; -import com.sap.sailing.domain.abstractlog.shared.analyzing.RegisteredCompetitorsAnalyzer; +import com.sap.sailing.domain.abstractlog.regatta.tracking.analyzing.impl.RegattaLogDeviceCompetitorMappingFinder; +import com.sap.sailing.domain.abstractlog.shared.analyzing.CompetitorsInLogAnalyzer; import com.sap.sailing.domain.base.Competitor; import com.sap.sailing.domain.base.Regatta; import com.sap.sailing.domain.base.impl.BoatClassImpl; @@ -54,7 +54,7 @@ public class LeaderboardsResourceCheckinAndOutTest extends AbstractJaxRsApiTest new HighPoint(), 0, null, OneDesignRankingMetric::new); racingEventService.addRegattaWithoutReplication(regatta); leaderboard = racingEventService.addRegattaLeaderboard(regatta.getRegattaIdentifier(), "regatta", new int[] {}); - + regatta.registerCompetitor(competitor); log = leaderboard.getRegattaLike().getRegattaLog(); } @@ -73,8 +73,8 @@ public class LeaderboardsResourceCheckinAndOutTest extends AbstractJaxRsApiTest Response response = resource.postCheckin(json.toString(), leaderboard.getName()); assertThat("checkin returns OK", response.getStatus(), equalTo(Response.Status.OK.getStatusCode())); - Set registeredCompetitors = new RegisteredCompetitorsAnalyzer<>(log).analyze(); - Map>> mappings = new DeviceCompetitorMappingFinder<>(log).analyze(); + Set registeredCompetitors = new CompetitorsInLogAnalyzer<>(log).analyze(); + Map>> mappings = new RegattaLogDeviceCompetitorMappingFinder(log).analyze(); assertThat("competitor was registered", registeredCompetitors.size(), equalTo(1)); assertThat("device mappings for competitor exist", mappings.size(), equalTo(1)); @@ -97,7 +97,7 @@ public class LeaderboardsResourceCheckinAndOutTest extends AbstractJaxRsApiTest response = resource.postCheckout(json.toString(), leaderboard.getName()); assertThat("checkout returns OK", response.getStatus(), equalTo(Response.Status.OK.getStatusCode())); - mappings = new DeviceCompetitorMappingFinder<>(log).analyze(); + mappings = new RegattaLogDeviceCompetitorMappingFinder(log).analyze(); mappingForC = mappings.get(competitor).get(0); assertThat("mapping now ends at checkout timepoint", mappingForC.getTimeRange().to().asMillis(), equalTo(toMillis)); diff --git a/java/com.sap.sailing.server.gateway.test/src/com/sap/sailing/server/gateway/test/jaxrs/LeaderboardsResourcePingMarkTest.java b/java/com.sap.sailing.server.gateway.test/src/com/sap/sailing/server/gateway/test/jaxrs/LeaderboardsResourcePingMarkTest.java index e82ef8d2300..6268ea97ab3 100644 --- a/java/com.sap.sailing.server.gateway.test/src/com/sap/sailing/server/gateway/test/jaxrs/LeaderboardsResourcePingMarkTest.java +++ b/java/com.sap.sailing.server.gateway.test/src/com/sap/sailing/server/gateway/test/jaxrs/LeaderboardsResourcePingMarkTest.java @@ -15,7 +15,7 @@ import org.junit.Before; import org.junit.Test; import com.sap.sailing.domain.abstractlog.regatta.RegattaLog; -import com.sap.sailing.domain.abstractlog.shared.analyzing.DeviceMarkMappingFinder; +import com.sap.sailing.domain.abstractlog.regatta.tracking.analyzing.impl.RegattaLogDeviceMarkMappingFinder; import com.sap.sailing.domain.base.Mark; import com.sap.sailing.domain.base.Regatta; import com.sap.sailing.domain.base.impl.BoatClassImpl; @@ -67,7 +67,6 @@ public class LeaderboardsResourcePingMarkTest extends AbstractJaxRsApiTest { new HighPoint(), 0, null, OneDesignRankingMetric::new); racingEventService.addRegattaWithoutReplication(regatta); leaderboard = racingEventService.addRegattaLeaderboard(regatta.getRegattaIdentifier(), "regatta", new int[] {}); - log = leaderboard.getRegattaLike().getRegattaLog(); } @@ -78,19 +77,19 @@ public class LeaderboardsResourcePingMarkTest extends AbstractJaxRsApiTest { { Response response = resource.pingMark(PING_MARK_JSON, leaderboard.getName(), mark.getId().toString()); assertThat("response is ok", response.getStatus(), equalTo(Response.Status.OK.getStatusCode())); - Map>> mappings = new DeviceMarkMappingFinder<>(log).analyze(); + Map>> mappings = new RegattaLogDeviceMarkMappingFinder(log).analyze(); List> mappingsForMark = mappings.get(mark); assertThat("one mapping was created for the one ping", mappingsForMark.size(), equalTo(1)); assertOneFixPerMapping(mappingsForMark); } { - // now produce a second ping; this should produce two fixes for the mark: one repeating the last known - // position, and another one with the new position. + // now produce a second ping; this should produce also only one fix; no additional artificial fixes are + // created (anymore; they used to be before bug2851) Response response = resource.pingMark(PING2_MARK_JSON, leaderboard.getName(), mark.getId().toString()); assertThat("response is ok", response.getStatus(), equalTo(Response.Status.OK.getStatusCode())); - Map>> mappings = new DeviceMarkMappingFinder<>(log).analyze(); + Map>> mappings = new RegattaLogDeviceMarkMappingFinder(log).analyze(); List> mappingsForMark = mappings.get(mark); - assertThat("two additional mappings were created for the second ping", mappingsForMark.size(), equalTo(3)); + assertThat("Assert no additional mapping was created for the second ping", mappingsForMark.size(), equalTo(2)); assertOneFixPerMapping(mappingsForMark); } } @@ -103,5 +102,4 @@ public class LeaderboardsResourcePingMarkTest extends AbstractJaxRsApiTest { assertThat("all fixes stored", racingEventService.getGPSFixStore().getNumberOfFixes(device), equalTo(1L)); } } - } diff --git a/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/impl/rc/MarksJsonExportServlet.java b/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/impl/rc/MarksJsonExportServlet.java index d38dc9d95ae..efcb71cc9f5 100644 --- a/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/impl/rc/MarksJsonExportServlet.java +++ b/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/impl/rc/MarksJsonExportServlet.java @@ -1,8 +1,6 @@ package com.sap.sailing.server.gateway.impl.rc; import java.io.IOException; -import java.util.ArrayList; -import java.util.List; import java.util.UUID; import javax.servlet.ServletException; @@ -11,13 +9,11 @@ import javax.servlet.http.HttpServletResponse; import org.json.simple.JSONArray; -import com.sap.sailing.domain.abstractlog.race.tracking.analyzing.impl.RaceLogDefinedMarkFinder; 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.common.racelog.RaceLogServletConstants; import com.sap.sailing.domain.leaderboard.Leaderboard; -import com.sap.sailing.domain.tracking.TrackedRace; import com.sap.sailing.server.RacingEventService; import com.sap.sailing.server.gateway.AbstractJsonHttpServlet; import com.sap.sailing.server.gateway.serialization.coursedata.impl.MarkJsonSerializer; @@ -61,19 +57,8 @@ public class MarksJsonExportServlet extends AbstractJsonHttpServlet { response.sendError(HttpServletResponse.SC_NOT_FOUND, "No such fleet found."); return; } - TrackedRace trackedRace = raceColumn.getTrackedRace(fleet); JSONArray result = new JSONArray(); - final Iterable marks; - if (trackedRace != null) { - marks = trackedRace.getMarks(); - } else { - final List marksList = new ArrayList<>(); - // no tracked race associated yet; grab the mark definitions from the race log: - for (Mark markDefinitionFromRaceLog : new RaceLogDefinedMarkFinder(raceColumn.getRaceLog(fleet)).analyze()) { - marksList.add(markDefinitionFromRaceLog); - } - marks = marksList; - } + final Iterable marks = raceColumn.getMarks(fleet); MarkJsonSerializer serializer = new MarkJsonSerializer(); for (Mark mark : marks) { if (toUUID(mark.getId().toString()) != null) { diff --git a/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/jaxrs/api/LeaderboardsResource.java b/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/jaxrs/api/LeaderboardsResource.java index 6879796f33e..ff04315885c 100644 --- a/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/jaxrs/api/LeaderboardsResource.java +++ b/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/jaxrs/api/LeaderboardsResource.java @@ -36,14 +36,10 @@ import org.json.simple.parser.ParseException; 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.tracking.analyzing.impl.RaceLogDefinedMarkFinder; import com.sap.sailing.domain.abstractlog.regatta.RegattaLog; 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.events.impl.RegattaLogRegisterCompetitorEventImpl; import com.sap.sailing.domain.abstractlog.regatta.impl.OpenEndedDeviceMappingFinder; -import com.sap.sailing.domain.abstractlog.shared.analyzing.RegisteredCompetitorsAnalyzer; import com.sap.sailing.domain.base.Competitor; import com.sap.sailing.domain.base.DomainFactory; import com.sap.sailing.domain.base.Fleet; @@ -51,7 +47,6 @@ import com.sap.sailing.domain.base.Mark; import com.sap.sailing.domain.base.Nationality; import com.sap.sailing.domain.base.RaceColumn; import com.sap.sailing.domain.base.Waypoint; -import com.sap.sailing.domain.common.Distance; import com.sap.sailing.domain.common.MaxPointsReason; import com.sap.sailing.domain.common.NoWindException; import com.sap.sailing.domain.common.Position; @@ -64,7 +59,6 @@ import com.sap.sailing.domain.common.dto.RaceColumnDTO; import com.sap.sailing.domain.common.racelog.RaceLogServletConstants; import com.sap.sailing.domain.common.racelog.tracking.DeviceMappingConstants; import com.sap.sailing.domain.common.tracking.GPSFix; -import com.sap.sailing.domain.common.tracking.impl.GPSFixImpl; import com.sap.sailing.domain.leaderboard.Leaderboard; import com.sap.sailing.domain.leaderboard.SettableScoreCorrection; import com.sap.sailing.domain.racelogtracking.DeviceIdentifier; @@ -76,7 +70,6 @@ import com.sap.sailing.domain.regattalike.IsRegattaLike; import com.sap.sailing.domain.regattalike.LeaderboardThatHasRegattaLike; import com.sap.sailing.domain.tracking.MarkPassing; import com.sap.sailing.domain.tracking.TrackedRace; -import com.sap.sailing.domain.tracking.impl.GPSFixTrackImpl; import com.sap.sailing.server.RacingEventService; import com.sap.sailing.server.gateway.deserialization.JsonDeserializationException; import com.sap.sailing.server.gateway.deserialization.impl.FlatGPSFixJsonDeserializer; @@ -85,8 +78,6 @@ import com.sap.sailing.server.gateway.jaxrs.AbstractSailingServerResource; import com.sap.sailing.server.gateway.serialization.coursedata.impl.MarkJsonSerializer; import com.sap.sailing.server.gateway.serialization.impl.FlatGPSFixJsonSerializer; import com.sap.sailing.server.gateway.serialization.impl.MarkJsonSerializerWithPosition; -import com.sap.sse.common.Duration; -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; @@ -367,7 +358,7 @@ public class LeaderboardsResource extends AbstractSailingServerResource { .entity("Leaderboard does not exist or does not hold a RegattaLog").type(MediaType.TEXT_PLAIN) .build(); } - IsRegattaLike isRegattaLike = ((HasRegattaLike) leaderboard).getRegattaLike(); + HasRegattaLike hasRegattaLike = (HasRegattaLike) leaderboard; DomainFactory domainFactory = getService().getDomainObjectFactory().getBaseDomainFactory(); AbstractLogEventAuthor author = new LogEventAuthorImpl(AbstractLogEventAuthor.NAME_COMPATIBILITY, AbstractLogEventAuthor.PRIORITY_COMPATIBILITY); @@ -383,7 +374,7 @@ public class LeaderboardsResource extends AbstractSailingServerResource { return Response.status(Status.BAD_REQUEST).entity("Invalid JSON body in request") .type(MediaType.TEXT_PLAIN).build(); } - TimePoint now = MillisecondsTimePoint.now(); + final TimePoint now = MillisecondsTimePoint.now(); String competitorId = (String) requestObject.get(DeviceMappingConstants.JSON_COMPETITOR_ID_AS_STRING); String deviceUuid = (String) requestObject.get(DeviceMappingConstants.JSON_DEVICE_UUID); Long fromMillis = (Long) requestObject.get(DeviceMappingConstants.JSON_FROM_MILLIS); @@ -402,20 +393,22 @@ public class LeaderboardsResource extends AbstractSailingServerResource { Competitor mappedTo = domainFactory.getCompetitorStore().getExistingCompetitorByIdAsString(competitorId); if (mappedTo == null) { logger.warning("No competitor found for id " + competitorId); - return Response.status(Status.BAD_REQUEST).entity("No competitor found for id " + competitorId) + return Response.status(Status.BAD_REQUEST).entity("No competitor found for id " + StringEscapeUtils.escapeHtml(competitorId)) .type(MediaType.TEXT_PLAIN).build(); } - // add registration if necessary - Set registered = new RegisteredCompetitorsAnalyzer<>(isRegattaLike.getRegattaLog()).analyze(); + + Set registered = (Set) hasRegattaLike.getAllCompetitors(); if (!registered.contains(mappedTo)) { - isRegattaLike.getRegattaLog().add( - new RegattaLogRegisterCompetitorEventImpl(now, now, author, UUID.randomUUID(), mappedTo)); + logger.warning("Competitor found but not registered on a race of " + leaderboardName); + return Response.status(Status.BAD_REQUEST) + .entity("Competitor found but not registered on a race of " + StringEscapeUtils.escapeHtml(leaderboardName)) + .type(MediaType.TEXT_PLAIN).build(); } DeviceIdentifier device = new SmartphoneUUIDIdentifierImpl(UUID.fromString(deviceUuid)); TimePoint from = new MillisecondsTimePoint(fromMillis); event = new RegattaLogDeviceCompetitorMappingEventImpl(now, now, author, UUID.randomUUID(), mappedTo, device, - from, null); - isRegattaLike.getRegattaLog().add(event); + from, /* to */ null); + hasRegattaLike.getRegattaLike().getRegattaLog().add(event); logger.fine("Successfully checked in competitor " + mappedTo.getName()); return Response.status(Status.OK).build(); } @@ -439,21 +432,16 @@ public class LeaderboardsResource extends AbstractSailingServerResource { @Path("{name}/device_mappings/end") public Response postCheckout(String json, @PathParam("name") String leaderboardName) { Leaderboard leaderboard = getService().getLeaderboardByName(leaderboardName); - if (!leaderboardIsValid(leaderboard)) { logger.warning("Leaderboard does not exist or does not hold a RegattaLog"); return Response.status(Status.INTERNAL_SERVER_ERROR) .entity("Leaderboard does not exist or does not hold a RegattaLog").type(MediaType.TEXT_PLAIN) .build(); } - IsRegattaLike isRegattaLike = ((HasRegattaLike) leaderboard).getRegattaLike(); - AbstractLogEventAuthor author = new LogEventAuthorImpl(AbstractLogEventAuthor.NAME_COMPATIBILITY, AbstractLogEventAuthor.PRIORITY_COMPATIBILITY); - - TimePoint now = MillisecondsTimePoint.now(); - + final TimePoint now = MillisecondsTimePoint.now(); logger.fine("Post issued to " + this.getClass().getName()); Object requestBody; JSONObject requestObject; @@ -465,40 +453,32 @@ public class LeaderboardsResource extends AbstractSailingServerResource { return Response.status(Status.BAD_REQUEST).entity("Invalid JSON body in request") .type(MediaType.TEXT_PLAIN).build(); } - logger.fine("JSON requestObject is: " + requestObject.toString()); - Long toMillis = (Long) requestObject.get("toMillis"); - String competitorId = (String) requestObject.get("competitorId"); - String deviceUuid = (String) requestObject.get("deviceUuid"); + Long toMillis = (Long) requestObject.get(DeviceMappingConstants.JSON_TO_MILLIS); + String competitorId = (String) requestObject.get(DeviceMappingConstants.JSON_COMPETITOR_ID_AS_STRING); + String deviceUuid = (String) requestObject.get(DeviceMappingConstants.JSON_DEVICE_UUID); TimePoint closingTimePoint = new MillisecondsTimePoint(toMillis); - if (toMillis == null || deviceUuid == null || closingTimePoint == null) { logger.warning("Invalid JSON body in request"); return Response.status(Status.BAD_REQUEST).entity("Invalid JSON body in request") .type(MediaType.TEXT_PLAIN).build(); } - Competitor mappedTo = getService().getCompetitorStore().getExistingCompetitorByIdAsString(competitorId); if (mappedTo == null) { logger.warning("No competitor found for id " + competitorId); return Response.status(Status.BAD_REQUEST).entity("No competitor found for id " + competitorId) .type(MediaType.TEXT_PLAIN).build(); } - - OpenEndedDeviceMappingFinder finder = new OpenEndedDeviceMappingFinder(isRegattaLike.getRegattaLog(), mappedTo, - deviceUuid); + OpenEndedDeviceMappingFinder finder = new OpenEndedDeviceMappingFinder(isRegattaLike.getRegattaLog(), mappedTo, deviceUuid); Serializable deviceMappingEventId = finder.analyze(); - if (deviceMappingEventId == null) { logger.warning("No corresponding open competitor to device mapping has been found"); return Response.status(Status.BAD_REQUEST) .entity("No corresponding open competitor to device mapping has been found") .type(MediaType.TEXT_PLAIN).build(); } - - RegattaLogCloseOpenEndedDeviceMappingEventImpl event = new RegattaLogCloseOpenEndedDeviceMappingEventImpl( - author, now, deviceMappingEventId, closingTimePoint); - + RegattaLogCloseOpenEndedDeviceMappingEventImpl event = new RegattaLogCloseOpenEndedDeviceMappingEventImpl(now, + author, deviceMappingEventId, closingTimePoint); isRegattaLike.getRegattaLog().add(event); logger.fine("Successfully checked out competitor " + mappedTo.getName()); return Response.status(Status.OK).build(); @@ -543,24 +523,23 @@ public class LeaderboardsResource extends AbstractSailingServerResource { .entity("Could not find a leaderboard with name '" + StringEscapeUtils.escapeHtml(leaderboardName) + "'.") .type(MediaType.TEXT_PLAIN).build(); } - final Set marks; + + if (!(leaderboard instanceof HasRegattaLike)) { + return Response.status(Status.NOT_FOUND) + .entity("Leaderboard with name '" + leaderboardName + "'does not contain a RegattaLog'.") + .type(MediaType.TEXT_PLAIN).build(); + } + + final Set marks = new HashSet(); if (raceColumnName == null) { if (fleetName != null) { return Response - .status(Status.BAD_REQUEST) - .entity("Either specify neither raceColumnName nor fleetName, only raceColumnName, or raceColumnName and fleetName but not only fleetName") - .type(MediaType.TEXT_PLAIN).build(); + .status(Status.BAD_REQUEST) + .entity("Either specify neither raceColumnName nor fleetName, only raceColumnName, or raceColumnName and fleetName but not only fleetName") + .type(MediaType.TEXT_PLAIN).build(); } else { - marks = new HashSet(); for (RaceColumn raceColumn : leaderboard.getRaceColumns()) { - for (Fleet fleet : raceColumn.getFleets()) { - RaceLog raceLog = raceColumn.getRaceLog(fleet); - TrackedRace trackedRace = raceColumn.getTrackedRace(fleet); // might not yet be attached - Util.addAll(new RaceLogDefinedMarkFinder(raceLog).analyze(), marks); - if (trackedRace != null) { - Util.addAll(trackedRace.getMarks(), marks); - } - } + Util.addAll(raceColumn.getAllMarks(), marks); } } } else { @@ -579,22 +558,20 @@ public class LeaderboardsResource extends AbstractSailingServerResource { StringEscapeUtils.escapeHtml(leaderboardName) + "'.").type(MediaType.TEXT_PLAIN).build(); } else { - marks = getMarksForFleet(raceColumn, fleet); + Util.addAll(raceColumn.getMarks(fleet), marks); } } else { // Return all marks for a certain race column - marks = new HashSet(); - for (Fleet fleet : raceColumn.getFleets()) { - Util.addAll(getMarksForFleet(raceColumn, fleet), marks); - } + // if all races have a tracked race return all marks part of at least one tracked race + // if at least one race doesn't have a tracked race, return also the marks defined in the RegattaLog + Util.addAll(raceColumn.getAllMarks(), marks); } } JSONArray array = new JSONArray(); for (Mark mark : marks) { final TimePoint now = MillisecondsTimePoint.now(); Position lastKnownPosition = getService().getMarkPosition(mark, - (LeaderboardThatHasRegattaLike) leaderboard, now, - /* raceLog==null means use all race logs */ null); + (LeaderboardThatHasRegattaLike) leaderboard, now); array.add(markWithPositionSerializer.serialize(new Pair<>(mark, lastKnownPosition))); } JSONObject result = new JSONObject(); @@ -602,21 +579,10 @@ public class LeaderboardsResource extends AbstractSailingServerResource { return Response.ok(result.toJSONString(), MediaType.APPLICATION_JSON).build(); } - private Set getMarksForFleet(RaceColumn raceColumn, Fleet fleet) { - RaceLog raceLog = raceColumn.getRaceLog(fleet); - TrackedRace trackedRace = raceColumn.getTrackedRace(fleet); // might not yet be attached - Set marks = new HashSet<>(); - Util.addAll(new RaceLogDefinedMarkFinder(raceLog).analyze(), marks); - if (trackedRace != null) { - Util.addAll(trackedRace.getMarks(), marks); - } - return marks; - } - private final MarkJsonSerializer markSerializer = new MarkJsonSerializer(); - private final MarkJsonSerializerWithPosition markWithPositionSerializer = new MarkJsonSerializerWithPosition(markSerializer, new FlatGPSFixJsonSerializer()); + private final MarkJsonSerializerWithPosition markWithPositionSerializer = new MarkJsonSerializerWithPosition( + markSerializer, new FlatGPSFixJsonSerializer()); private final FlatGPSFixJsonDeserializer fixDeserializer = new FlatGPSFixJsonDeserializer(); - private final FlatGPSFixJsonSerializer fixSerializer = new FlatGPSFixJsonSerializer(); /** * Mockito requires this to be public in order to be able to mock it :-( @@ -625,28 +591,23 @@ public class LeaderboardsResource extends AbstractSailingServerResource { return getService(RaceLogTrackingAdapterFactory.class).getAdapter(getService().getBaseDomainFactory()); } + /** + * Expects one GPS Fix in the format understood by {@link #fixDeserializer} in the POST message body, parses that fix, + * adds the fix to the {@link RacingEventService#getGPSFixStore() GPSFixStore} and creates mappings for each fix in the RegattaLog. + */ @POST @Path("{leaderboardName}/marks/{markId}/gps_fixes") @Consumes(MediaType.APPLICATION_JSON) - /** - * Add the fixes to the GPSFixStore and create mappings for each fix in the RegattaLog. - * @param json - * @param leaderboardName - * @param markId - * @return - * @throws HTTPException - */ public Response pingMark(String json, @PathParam("leaderboardName") String leaderboardName, @PathParam("markId") String markId) throws HTTPException { logger.fine("Post issued to " + this.getClass().getName()); - + final RacingEventService service = getService(); Leaderboard leaderboard = getService().getLeaderboardByName(leaderboardName); if (leaderboard == null) { return Response.status(Status.NOT_FOUND) .entity("Could not find a leaderboard with name '" + StringEscapeUtils.escapeHtml(leaderboardName) + "'.") .type(MediaType.TEXT_PLAIN).build(); } - RegattaLog regattaLog = null; if (leaderboard instanceof HasRegattaLike) { regattaLog = ((HasRegattaLike) leaderboard).getRegattaLike().getRegattaLog(); @@ -655,17 +616,13 @@ public class LeaderboardsResource extends AbstractSailingServerResource { .entity("Leaderboard '" + StringEscapeUtils.escapeHtml(leaderboardName) + "' does not have an attached RegattaLog.") .type(MediaType.TEXT_PLAIN).build(); } - - Mark mark = getService().getBaseDomainFactory().getExistingMarkByIdAsString(markId); + final Mark mark = service.getBaseDomainFactory().getExistingMarkByIdAsString(markId); if (mark == null) { return Response.status(Status.NOT_FOUND).entity("Could not find a mark with ID '" + StringEscapeUtils.escapeHtml(markId) + "'.") .type(MediaType.TEXT_PLAIN).build(); } - TimePoint now = MillisecondsTimePoint.now(); - Position lastKnownPosition = getService().getMarkPosition(mark, - (LeaderboardThatHasRegattaLike) leaderboard, now, - /* raceLog==null means use all race logs */ null); - GPSFix fix = null; + // grab the position as found in TrackedRaces attached to the leaderboard + final GPSFix fix; try { Object requestBody = JSONValue.parseWithException(json); JSONObject requestObject = Helpers.toJSONObjectSafe(requestBody); @@ -676,28 +633,8 @@ public class LeaderboardsResource extends AbstractSailingServerResource { return Response.status(Status.BAD_REQUEST).entity("Invalid JSON body in request") .type(MediaType.TEXT_PLAIN).build(); } - RaceLogTrackingAdapter adapter = getRaceLogTrackingAdapter(); - RacingEventService service = getService(); - try { - if (lastKnownPosition != null) { - // ping again to avoid interpolation, avoid filtering by paying attention to maxSpeedForSmoothing - final Distance distance = lastKnownPosition.getDistance(fix.getPosition()); - final Duration minDuration = GPSFixTrackImpl.getDefaultMaxSpeedForSmoothing().getDuration(distance); - final GPSFix repeatedFixAvoidingCreepingMark = new GPSFixImpl(lastKnownPosition, fix.getTimePoint().minus(minDuration)); - adapter.pingMark(regattaLog, mark, repeatedFixAvoidingCreepingMark, service); - } - adapter.pingMark(regattaLog, mark, fix, service); - logger.log(Level.INFO, "Pinged mark " + mark.getName()); - } catch (NoCorrespondingServiceRegisteredException e) { - logger.log(Level.WARNING, "Could not ping mark " + mark.getName()); - } - - if (lastKnownPosition != null) { - JSONObject lastKnownFixJson = fixSerializer.serialize(new GPSFixImpl(lastKnownPosition, now)); - String fixJson = lastKnownFixJson.toJSONString(); - return Response.ok(fixJson, MediaType.APPLICATION_JSON).build(); - } else { - return Response.ok().build(); - } + final RaceLogTrackingAdapter adapter = getRaceLogTrackingAdapter(); + adapter.pingMark(regattaLog, mark, fix, service); + return Response.ok().build(); } } diff --git a/java/com.sap.sailing.server.test/src/com/sap/sailing/server/impl/MediaMasterDataExportTest.java b/java/com.sap.sailing.server.test/src/com/sap/sailing/server/impl/MediaMasterDataExportTest.java index 3cf24c8da1f..455cd856500 100644 --- a/java/com.sap.sailing.server.test/src/com/sap/sailing/server/impl/MediaMasterDataExportTest.java +++ b/java/com.sap.sailing.server.test/src/com/sap/sailing/server/impl/MediaMasterDataExportTest.java @@ -47,6 +47,7 @@ import com.sap.sailing.domain.leaderboard.impl.RegattaLeaderboardImpl; import com.sap.sailing.domain.leaderboard.impl.ThresholdBasedResultDiscardingRuleImpl; import com.sap.sailing.domain.masterdataimport.TopLevelMasterData; import com.sap.sailing.domain.racelog.tracking.GPSFixStore; +import com.sap.sailing.domain.ranking.OneDesignRankingMetric; import com.sap.sailing.domain.tracking.TrackedRegattaRegistry; import com.sap.sse.common.Duration; import com.sap.sse.common.TimePoint; @@ -181,7 +182,7 @@ public class MediaMasterDataExportTest { TrackedRegattaRegistry trackedRegattaRegistry = mock(TrackedRegattaRegistry.class); Series series = new SeriesImpl("series name", isMedal, regattaFleets, raceColumnNames, trackedRegattaRegistry); Iterable regattaSeries = Collections.singleton(series); - return new RegattaImpl(regattaName, boatClass, startDate, endDate, regattaSeries, persistent, scoringScheme, regatteId , courseArea); + return new RegattaImpl(regattaName, boatClass, startDate, endDate, regattaSeries, persistent, scoringScheme, regatteId , courseArea, OneDesignRankingMetric::new); } diff --git a/java/com.sap.sailing.server.test/src/com/sap/sailing/server/test/MasterDataImportTest.java b/java/com.sap.sailing.server.test/src/com/sap/sailing/server/test/MasterDataImportTest.java index 4d29a1a5927..03889f1a95b 100644 --- a/java/com.sap.sailing.server.test/src/com/sap/sailing/server/test/MasterDataImportTest.java +++ b/java/com.sap.sailing.server.test/src/com/sap/sailing/server/test/MasterDataImportTest.java @@ -43,6 +43,7 @@ import com.sap.sailing.domain.abstractlog.race.RaceLogEvent; import com.sap.sailing.domain.abstractlog.race.RaceLogFinishPositioningConfirmedEvent; import com.sap.sailing.domain.abstractlog.race.RaceLogStartTimeEvent; import com.sap.sailing.domain.abstractlog.race.RaceLogWindFixEvent; +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.RaceLogStartTimeEventImpl; @@ -126,7 +127,6 @@ import com.sap.sailing.server.masterdata.DummyTrackedRace; import com.sap.sailing.server.masterdata.MasterDataImporter; import com.sap.sse.common.Color; import com.sap.sse.common.TimePoint; -import com.sap.sse.common.Util; import com.sap.sse.common.impl.MillisecondsDurationImpl; import com.sap.sse.common.impl.MillisecondsTimePoint; import com.sap.sse.common.media.MimeType; @@ -847,10 +847,10 @@ public class MasterDataImportTest { // Add a competitor-related race log event to ensure that no competitor resolution is attempted while receiving TimePoint logTimePoint2 = logTimePoint.plus(10); CompetitorResults positionedCompetitors = new CompetitorResultsImpl(); - positionedCompetitors.add(new Util.Triple(competitor.getId(), competitor - .getName(), MaxPointsReason.DNS)); - positionedCompetitors.add(new Util.Triple(competitor2.getId(), - competitor2.getName(), MaxPointsReason.NONE)); + positionedCompetitors.add(new CompetitorResultImpl( + competitor.getId(), competitor.getName(), /* rank */ 1, MaxPointsReason.DNS, /* score */ null, /* finishingTime */ null, /* comment */ null)); + positionedCompetitors.add(new CompetitorResultImpl( + competitor2.getId(), competitor2.getName(), /* rank */ 2, MaxPointsReason.NONE, /* score */ null, /* finishingTime */ null, /* comment */ null)); RaceLogFinishPositioningConfirmedEvent finishPositioningConfirmedEvent = new RaceLogFinishPositioningConfirmedEventImpl( logTimePoint2, author, 1, positionedCompetitors); raceColumn.getRaceLog(testFleet1).add(finishPositioningConfirmedEvent); diff --git a/java/com.sap.sailing.server/src/com/sap/sailing/server/RacingEventService.java b/java/com.sap.sailing.server/src/com/sap/sailing/server/RacingEventService.java index 17a03a3bf9b..1371b31121e 100755 --- a/java/com.sap.sailing.server/src/com/sap/sailing/server/RacingEventService.java +++ b/java/com.sap.sailing.server/src/com/sap/sailing/server/RacingEventService.java @@ -135,20 +135,17 @@ public interface RacingEventService extends TrackedRegattaRegistry, RegattaFetch Leaderboard getLeaderboardByName(String name); /** - * Looks at the mark tracks in the tracked races attached to the leaderboard. If it doesn't find a + * Looks at the mark tracks in the tracked races attached to the leaderboard and tries to find a * track for the mark requested there which has fixes before and after timePoint (to - * ensure that no track cropping has taken place, removing the fixes for the interesting time period), looks in the - * leaderboard's regatta log and the specific raceLog (if provided) or all race logs attached to the - * leaderboard (if not provided) for device mappings for the mark and tries to load fixes from the - * {@link GPSFixStore}. The latter is only necessary if the mark isn't found in any tracked race with fixes - * surrounding timePoint because should there be a tracked race in the leaderboard that has the mark - * then it will also have received the fixes from the {@link GPSFixStore} through the regatta log mapping. + * ensure that no track cropping has taken place, removing the fixes for the interesting time period). Note, that + * no lookup is performed in the {@link RegattaLog} of the {@code leaderboard}, so mark pings that have not yet + * been applied to a {@link TrackedRace} will not be considered by this method. *

* * @return the position obtained by interpolation but never extrapolation from the track identified as described * above */ - Position getMarkPosition(Mark mark, LeaderboardThatHasRegattaLike leaderboard, TimePoint timePoint, RaceLog raceLog); + Position getMarkPosition(Mark mark, LeaderboardThatHasRegattaLike leaderboard, TimePoint timePoint); /** * Stops tracking all races of the regatta specified. This will also stop tracking wind for all races of this regatta. diff --git a/java/com.sap.sailing.server/src/com/sap/sailing/server/impl/RaceLogScoringReplicator.java b/java/com.sap.sailing.server/src/com/sap/sailing/server/impl/RaceLogScoringReplicator.java index 8a9b8b2a725..a2b3ad0ec64 100644 --- a/java/com.sap.sailing.server/src/com/sap/sailing/server/impl/RaceLogScoringReplicator.java +++ b/java/com.sap.sailing.server/src/com/sap/sailing/server/impl/RaceLogScoringReplicator.java @@ -1,12 +1,13 @@ package com.sap.sailing.server.impl; -import java.io.Serializable; -import java.util.List; import java.util.concurrent.Callable; +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.RaceLogEvent; import com.sap.sailing.domain.abstractlog.race.RaceLogFinishPositioningConfirmedEvent; +import com.sap.sailing.domain.abstractlog.race.RaceLogFinishPositioningListChangedEvent; import com.sap.sailing.domain.abstractlog.race.analyzing.impl.ConfirmedFinishPositioningListFinder; import com.sap.sailing.domain.abstractlog.race.analyzing.impl.FinishPositioningListFinder; import com.sap.sailing.domain.base.Competitor; @@ -89,11 +90,11 @@ public class RaceLogScoringReplicator implements RaceColumnListener { @Override public void raceLogEventAdded(RaceColumn raceColumn, RaceLogIdentifier raceLogIdentifier, RaceLogEvent event) { if (event instanceof RaceLogFinishPositioningConfirmedEvent) { - handleFinishPositioningList(raceColumn, raceLogIdentifier, event); + handleFinishPositioningList(raceColumn, raceLogIdentifier, (RaceLogFinishPositioningConfirmedEvent) event); } } - private void handleFinishPositioningList(RaceColumn raceColumn, RaceLogIdentifier raceLogIdentifier, RaceLogEvent event) { + private void handleFinishPositioningList(RaceColumn raceColumn, RaceLogIdentifier raceLogIdentifier, RaceLogFinishPositioningConfirmedEvent event) { Leaderboard leaderboard = service.getLeaderboardByName(raceLogIdentifier.getRegattaLikeParent().getName()); if (leaderboard != null) { Fleet fleet = raceColumn.getFleetByName(raceLogIdentifier.getFleetName()); @@ -108,43 +109,47 @@ public class RaceLogScoringReplicator implements RaceColumnListener { } /** - * Retrieves the last RaceLogFinishPositioningListChangedEvent from the racelog and compares the ranks and - * disqualifications entered by the race committee with the tracked ranks. When a tracked rank for a competitor is - * not the same as the rank of the race committee, a score correction is issued. The positioning list contains a - * list of competitors sorted by the positioning order when finishing. Additionally a MaxPointsReason might be - * entered by the Race Committee. + * Called when a {@link RaceLogFinishPositioningConfirmedEvent} was received by the {@link RaceLog}. Retrieves the + * last {@link RaceLogFinishPositioningConfirmedEvent} from the racelog and compares the ranks and disqualifications + * entered by the race committee with the tracked ranks. When a tracked rank for a competitor is not the same as the + * rank of the race committee, a score correction is issued. The positioning list contains a list of competitors + * sorted by the positioning order when finishing. Additionally a MaxPointsReason might be entered by the Race + * Committee. + *

+ * + * For backward compatibility (old releases didn't store the {@link CompetitorResults} in the event) if no + * {@link CompetitorResults} are found even though there was a {@link RaceLogFinishPositioningConfirmedEvent}, the + * last {@link RaceLogFinishPositioningListChangedEvent} event with {@link CompetitorResults} is looked up and its + * results are used. + * + * TODO bug 3420: also extract the optional score / finishing time / comment and make good use of it * * @param timePoint * the TimePoint at which the race committee confirmed their last rank list entered in the app. */ private void checkNeedForScoreCorrectionByResultsOfRaceCommittee(Leaderboard leaderboard, RaceColumn raceColumn, Fleet fleet, RaceLog raceLog, TimePoint timePoint) { - int numberOfCompetitorsInLeaderboard = Util.size(leaderboard.getCompetitors()); int numberOfCompetitorsInRace; - List> positioningList; - + CompetitorResults positioningList; numberOfCompetitorsInRace = getNumberOfCompetitorsInRace(raceColumn, fleet, numberOfCompetitorsInLeaderboard); - ConfirmedFinishPositioningListFinder confirmedPositioningListFinder = new ConfirmedFinishPositioningListFinder(raceLog); positioningList = confirmedPositioningListFinder.analyze(); - if (positioningList == null) { // we expect this case for old sailing events such as ESS Singapore, Quingdao, where the confirmation event did not contain the finish // positioning list FinishPositioningListFinder positioningListFinder = new FinishPositioningListFinder(raceLog); - positioningList = positioningListFinder.analyze(); + positioningList = positioningListFinder.analyze(); // this is OK because the precondition for calling this method is that a + // RaceLogFinishPositioningConfirmedEvent event was found in the race log } - if (positioningList != null) { - for (com.sap.sse.common.Util.Triple positionedCompetitor : positioningList) { - Competitor competitor = service.getBaseDomainFactory().getExistingCompetitorById(positionedCompetitor.getA()); - - if (positionedCompetitor.getC().equals(MaxPointsReason.NONE)) { + for (CompetitorResult positionedCompetitor : positioningList) { + Competitor competitor = service.getBaseDomainFactory().getExistingCompetitorById(positionedCompetitor.getCompetitorId()); + if (positionedCompetitor.getMaxPointsReason().equals(MaxPointsReason.NONE)) { try { resetMaxPointsReasonIfNecessary(leaderboard, raceColumn, timePoint, competitor); - int rankByRaceCommittee = getRankInPositioningListByRaceCommittee(positioningList, positionedCompetitor); + int rankByRaceCommittee = getRankInPositioningListByRaceCommittee(positionedCompetitor); correctScoreInLeaderboard(leaderboard, raceColumn, timePoint, numberOfCompetitorsInRace, - competitor, rankByRaceCommittee); + competitor, rankByRaceCommittee, positionedCompetitor.getScore()); } catch (NoWindException ex) { ex.printStackTrace(); } @@ -152,7 +157,6 @@ public class RaceLogScoringReplicator implements RaceColumnListener { setMaxPointsReasonInLeaderboardIfNecessary(leaderboard, raceColumn, timePoint, positionedCompetitor, competitor); } } - //Since the metadata update is used by the Sailing suite to determine the final state of a race, it has to be triggered, even though //no score correction was performed applyMetadataUpdate(leaderboard, timePoint, COMMENT_TEXT_ON_SCORE_CORRECTION); @@ -160,11 +164,10 @@ public class RaceLogScoringReplicator implements RaceColumnListener { } private boolean setMaxPointsReasonInLeaderboardIfNecessary(Leaderboard leaderboard, RaceColumn raceColumn, - TimePoint timePoint, com.sap.sse.common.Util.Triple positionedCompetitor, Competitor competitor) { + TimePoint timePoint, CompetitorResult positionedCompetitor, Competitor competitor) { boolean scoreHasBeenCorrected = false; - MaxPointsReason trackedMaxPointsReason = leaderboard.getMaxPointsReason(competitor, raceColumn, timePoint); - MaxPointsReason maxPointsReasonByRaceCommittee = positionedCompetitor.getC(); + MaxPointsReason maxPointsReasonByRaceCommittee = positionedCompetitor.getMaxPointsReason(); if (!maxPointsReasonByRaceCommittee.equals(trackedMaxPointsReason)) { applyMaxPointsReasonOperation(leaderboard, raceColumn, competitor, maxPointsReasonByRaceCommittee, timePoint); scoreHasBeenCorrected = true; @@ -172,22 +175,23 @@ public class RaceLogScoringReplicator implements RaceColumnListener { return scoreHasBeenCorrected; } - private boolean correctScoreInLeaderboard(Leaderboard leaderboard, RaceColumn raceColumn, TimePoint timePoint, + private void correctScoreInLeaderboard(Leaderboard leaderboard, RaceColumn raceColumn, TimePoint timePoint, final int numberOfCompetitorsInRace, - Competitor competitor, int rankByRaceCommittee) throws NoWindException { - boolean scoreHasBeenCorrected = false; - Double scoreByRaceCommittee = leaderboard.getScoringScheme().getScoreForRank(leaderboard, raceColumn, competitor, + Competitor competitor, int rankByRaceCommittee, Double optionalExplicitScore) throws NoWindException { + final Double scoreByRaceCommittee; + if (optionalExplicitScore == null) { + scoreByRaceCommittee = leaderboard.getScoringScheme().getScoreForRank(leaderboard, raceColumn, competitor, rankByRaceCommittee, new Callable() { @Override public Integer call() { return numberOfCompetitorsInRace; } }, leaderboard.getNumberOfCompetitorsInLeaderboardFetcher(), timePoint); - + } else { + scoreByRaceCommittee = optionalExplicitScore; + } // Do ALWAYS apply score corrections from race committee applyScoreCorrectionOperation(leaderboard, raceColumn, competitor, scoreByRaceCommittee, timePoint); - scoreHasBeenCorrected = true; - return scoreHasBeenCorrected; } private boolean resetMaxPointsReasonIfNecessary(Leaderboard leaderboard, RaceColumn raceColumn, TimePoint timePoint, Competitor competitor) { @@ -215,14 +219,17 @@ public class RaceLogScoringReplicator implements RaceColumnListener { } /** - * The positioning list contains a list of competitors sorted by the positioning order when finishing. Additionally a MaxPointsReason might be entered by the - * Race Committee. The rank of a competitor according to the Race Committee is represented by the position in the given positioningList - * @param positioningList The list containing the competitors. The rank is represented by the position of a competitor in the list - * @param positionedCompetitor the competitor whose rank shall be determined - * @return the rank of the given positionedCompetitor + * The positioning list contains a list of competitors sorted by the positioning order when finishing. Additionally + * a MaxPointsReason might be entered by the Race Committee. The rank of a competitor according to the Race + * Committee used to be represented by the position in the list in earlier versions; now it is made explicit in the + * {@link CompetitorResult#getOneBasedRank()} attribute. + * @param positionedCompetitor + * the competitor whose rank shall be determined + * + * @return the (one-based) rank of the given positionedCompetitor */ - private int getRankInPositioningListByRaceCommittee(List> positioningList, com.sap.sse.common.Util.Triple positionedCompetitor) { - return positioningList.indexOf(positionedCompetitor) + 1; // indexOf gives the zero-based position requested competitor in the list, + 1 gives the one-based rank + private int getRankInPositioningListByRaceCommittee(CompetitorResult positionedCompetitor) { + return positionedCompetitor.getOneBasedRank(); } private int getNumberOfCompetitorsInRace(RaceColumn raceColumn, Fleet fleet, int numberOfCompetitorsInLeaderboard) { diff --git a/java/com.sap.sailing.server/src/com/sap/sailing/server/impl/RacingEventServiceImpl.java b/java/com.sap.sailing.server/src/com/sap/sailing/server/impl/RacingEventServiceImpl.java index 3fecb73db30..b6e76088021 100644 --- a/java/com.sap.sailing.server/src/com/sap/sailing/server/impl/RacingEventServiceImpl.java +++ b/java/com.sap.sailing.server/src/com/sap/sailing/server/impl/RacingEventServiceImpl.java @@ -46,7 +46,6 @@ import org.osgi.framework.BundleContext; import org.osgi.framework.ServiceReference; import org.osgi.util.tracker.ServiceTracker; -import com.sap.sailing.domain.abstractlog.AbstractLog; import com.sap.sailing.domain.abstractlog.AbstractLogEventAuthor; import com.sap.sailing.domain.abstractlog.impl.LogEventAuthorImpl; import com.sap.sailing.domain.abstractlog.race.RaceLog; @@ -159,7 +158,6 @@ import com.sap.sailing.domain.tracking.WindStore; import com.sap.sailing.domain.tracking.WindTracker; import com.sap.sailing.domain.tracking.WindTrackerFactory; import com.sap.sailing.domain.tracking.impl.AbstractRaceChangeListener; -import com.sap.sailing.domain.tracking.impl.DynamicGPSFixTrackImpl; import com.sap.sailing.domain.tracking.impl.DynamicTrackedRegattaImpl; import com.sap.sailing.domain.tracking.impl.TrackedRaceImpl; import com.sap.sailing.expeditionconnector.ExpeditionWindTrackerFactory; @@ -1059,12 +1057,12 @@ public class RacingEventServiceImpl implements RacingEventService, ClearStateTes } @Override - public Position getMarkPosition(Mark mark, LeaderboardThatHasRegattaLike leaderboard, TimePoint timePoint, RaceLog raceLog) { + public Position getMarkPosition(Mark mark, LeaderboardThatHasRegattaLike leaderboard, TimePoint timePoint) { GPSFixTrack track = null; // If no spanning track is found, the fix closest to the time point requested is used instead GPSFix nonSpanningFallback = null; for (TrackedRace trackedRace : leaderboard.getTrackedRaces()) { - GPSFixTrack trackCandidate = trackedRace.getTrack(mark); + final GPSFixTrack trackCandidate = trackedRace.getTrack(mark); if (trackCandidate != null) { if (spansTimePoint(trackCandidate, timePoint)) { track = trackCandidate; @@ -1074,31 +1072,10 @@ public class RacingEventServiceImpl implements RacingEventService, ClearStateTes } } } - if (track == null) { // no spanning track found in any tracked race, or no tracked races found - // try to load from store - DynamicGPSFixTrackImpl loadedTrack = new DynamicGPSFixTrackImpl(mark, 0); - track = loadedTrack; - Set> logs = new HashSet<>(); - logs.add(leaderboard.getRegattaLike().getRegattaLog()); - if (raceLog == null) { // no race log explicitly provided --> use all race logs - for (RaceColumn raceColumn : leaderboard.getRaceColumns()) { - for (Fleet fleet : raceColumn.getFleets()) { - logs.add(raceColumn.getRaceLog(fleet)); - } - } - } else { - logs.add(raceLog); - } - for (AbstractLog log : logs) { - try { - getGPSFixStore().loadMarkTrack(loadedTrack, log, mark); - } catch (Exception e) { - logger.log(Level.WARNING, "Couldn't load mark track for mark " + mark + " from log " + log, e); - } - } - } - Position result = track.getEstimatedPosition(timePoint, /* extrapolate */ false); - if (result == null) { + final Position result; + if (track != null) { + result = track.getEstimatedPosition(timePoint, /* extrapolate */ false); + } else { result = nonSpanningFallback == null ? null : nonSpanningFallback.getPosition(); } return result; diff --git a/java/com.sap.sailing.server/src/com/sap/sailing/server/masterdata/DummyTrackedRace.java b/java/com.sap.sailing.server/src/com/sap/sailing/server/masterdata/DummyTrackedRace.java index ae6e89de466..23b95da6c7e 100755 --- a/java/com.sap.sailing.server/src/com/sap/sailing/server/masterdata/DummyTrackedRace.java +++ b/java/com.sap.sailing.server/src/com/sap/sailing/server/masterdata/DummyTrackedRace.java @@ -529,10 +529,6 @@ public class DummyTrackedRace extends TrackedRaceWithWindEssentials { return null; } - @Override - public void waitForLoadingFromGPSFixStoreToFinishRunning(RaceLog forRaceLog) throws InterruptedException { - } - @Override public void addRaceAbortedListener(RaceAbortedListener listener) { } diff --git a/java/com.sap.sse.gwt/src/com/sap/sse/gwt/client/panels/AbstractFilterablePanel.java b/java/com.sap.sse.gwt/src/com/sap/sse/gwt/client/panels/AbstractFilterablePanel.java index 4e1aa1aa200..ed33b868678 100755 --- a/java/com.sap.sse.gwt/src/com/sap/sse/gwt/client/panels/AbstractFilterablePanel.java +++ b/java/com.sap.sse.gwt/src/com/sap/sse/gwt/client/panels/AbstractFilterablePanel.java @@ -106,11 +106,34 @@ public abstract class AbstractFilterablePanel extends HorizontalPanel { filter(); } + /** + * Removes an object and applies the search filter. + */ + public void remove(T object) { + all.remove(object); + filter(); + } + public void addAll(Iterable objects) { Util.addAll(objects, all); filter(); } + /** + * Would better be called {@code clear()}, but {@link #clear} is already the method inherited from {@link Panel}... + * This method removes all entries from this filterable panel. The effect is the same as invoking + * removeAll(all) with all being a copy of what you get when calling {@link #getAll()}. + */ + public void removeAll() { + all.clear(); + filter(); + } + + public void removeAll(Iterable objects) { + Util.removeAll(objects, all); + filter(); + } + public void filter() { filtered.getList().clear(); Util.addAll(filterer.applyFilter(Arrays.asList(getTextBox().getText().split(" ")), all), filtered.getList()); diff --git a/java/com.sap.sse.gwt/src/com/sap/sse/gwt/dispatch/client/Action.java b/java/com.sap.sse.gwt/src/com/sap/sse/gwt/dispatch/client/Action.java index 2a4d955f9d1..cb92d9e4b40 100644 --- a/java/com.sap.sse.gwt/src/com/sap/sse/gwt/dispatch/client/Action.java +++ b/java/com.sap.sse.gwt/src/com/sap/sse/gwt/dispatch/client/Action.java @@ -3,9 +3,29 @@ package com.sap.sse.gwt.dispatch.client; import com.google.gwt.core.shared.GwtIncompatible; import com.google.gwt.user.client.rpc.IsSerializable; import com.sap.sse.gwt.dispatch.client.exceptions.DispatchException; +import com.sap.sse.gwt.dispatch.client.impl.DispatchSystem; +/** + * Action interface that defines actions that can be sent to server using a {@link DispatchSystem}. + * + * The execute method will be executed on the server side and is therefore {@link GwtIncompatible}. + * + * The state defined in the action is the state that will be sent over the wire. Any method (other than execute, which + * is GwtIncompatible) can be called both on the client and on the server side. + * + * @param + * @param + */ public interface Action extends IsSerializable { + /** + * Server side execution of the action. The execute method is GwtIncompatible and will be available only on the + * server side. + * + * @param ctx + * @return + * @throws DispatchException + */ @GwtIncompatible R execute(CTX ctx) throws DispatchException; diff --git a/java/com.sap.sse.gwt/src/com/sap/sse/gwt/dispatch/client/CollectionResult.java b/java/com.sap.sse.gwt/src/com/sap/sse/gwt/dispatch/client/CollectionResult.java index 1b7e711f327..3c15fad3138 100644 --- a/java/com.sap.sse.gwt/src/com/sap/sse/gwt/dispatch/client/CollectionResult.java +++ b/java/com.sap.sse.gwt/src/com/sap/sse/gwt/dispatch/client/CollectionResult.java @@ -2,6 +2,11 @@ package com.sap.sse.gwt.dispatch.client; import java.util.Collection; +/** + * Collection result that can be reused to send a collection of {@link DTO} instances + * + * @param + */ public interface CollectionResult extends DTO, Result { Collection getValues(); } diff --git a/java/com.sap.sse.gwt/src/com/sap/sse/gwt/dispatch/client/DispatchAsync.java b/java/com.sap.sse.gwt/src/com/sap/sse/gwt/dispatch/client/DispatchAsync.java deleted file mode 100644 index 477a63cd4d2..00000000000 --- a/java/com.sap.sse.gwt/src/com/sap/sse/gwt/dispatch/client/DispatchAsync.java +++ /dev/null @@ -1,9 +0,0 @@ -package com.sap.sse.gwt.dispatch.client; - -import com.google.gwt.user.client.rpc.AsyncCallback; - -public interface DispatchAsync { - - > void execute(A action, AsyncCallback callback); - -} diff --git a/java/com.sap.sse.gwt/src/com/sap/sse/gwt/dispatch/client/DispatchSystemAsync.java b/java/com.sap.sse.gwt/src/com/sap/sse/gwt/dispatch/client/DispatchSystemAsync.java new file mode 100644 index 00000000000..6ddb49d1f8d --- /dev/null +++ b/java/com.sap.sse.gwt/src/com/sap/sse/gwt/dispatch/client/DispatchSystemAsync.java @@ -0,0 +1,23 @@ +package com.sap.sse.gwt.dispatch.client; + +import com.google.gwt.user.client.rpc.AsyncCallback; + +/** + * Async interface that defines the dispatch system contract. + * + * @param + */ +public interface DispatchSystemAsync { + + /** + * Send an action to be executed on the server. + * + * @param action + * the action to be executed on the server + * + * @param callback + * the callback that will called upon success or failure. + */ + > void execute(A action, AsyncCallback callback); + +} diff --git a/java/com.sap.sse.gwt/src/com/sap/sse/gwt/dispatch/client/Result.java b/java/com.sap.sse.gwt/src/com/sap/sse/gwt/dispatch/client/Result.java index 229d222e099..738e6b81e6c 100644 --- a/java/com.sap.sse.gwt/src/com/sap/sse/gwt/dispatch/client/Result.java +++ b/java/com.sap.sse.gwt/src/com/sap/sse/gwt/dispatch/client/Result.java @@ -2,6 +2,11 @@ package com.sap.sse.gwt.dispatch.client; import com.google.gwt.user.client.rpc.IsSerializable; +/** + * Result marker interface for the dispatch communication pattern. + * + * Results may be reused across different actions. + */ public interface Result extends IsSerializable { } diff --git a/java/com.sap.sse.gwt/src/com/sap/sse/gwt/dispatch/client/ResultWithTTL.java b/java/com.sap.sse.gwt/src/com/sap/sse/gwt/dispatch/client/ResultWithTTL.java index 31b35316d09..975592414f1 100644 --- a/java/com.sap.sse.gwt/src/com/sap/sse/gwt/dispatch/client/ResultWithTTL.java +++ b/java/com.sap.sse.gwt/src/com/sap/sse/gwt/dispatch/client/ResultWithTTL.java @@ -4,6 +4,11 @@ import com.sap.sse.common.Duration; import com.sap.sse.common.impl.MillisecondsDurationImpl; import com.sap.sse.gwt.dispatch.client.caching.HasClientCacheTotalTimeToLive; +/** + * Result implementation that holds a {@link DTO} with a defined time to live expiration. + * + * @param + */ public class ResultWithTTL implements Result, HasClientCacheTotalTimeToLive { /** max millis the result might be loaded earlier so we do batches **/ diff --git a/java/com.sap.sse.gwt/src/com/sap/sse/gwt/dispatch/client/batching/AutomaticBatchingDispatch.java b/java/com.sap.sse.gwt/src/com/sap/sse/gwt/dispatch/client/batching/AutomaticBatchingDispatch.java index 31a973a8adb..0708d9f0ca3 100644 --- a/java/com.sap.sse.gwt/src/com/sap/sse/gwt/dispatch/client/batching/AutomaticBatchingDispatch.java +++ b/java/com.sap.sse.gwt/src/com/sap/sse/gwt/dispatch/client/batching/AutomaticBatchingDispatch.java @@ -6,15 +6,15 @@ import com.google.gwt.core.client.Scheduler; import com.google.gwt.core.client.Scheduler.ScheduledCommand; import com.google.gwt.user.client.rpc.AsyncCallback; import com.sap.sse.gwt.dispatch.client.Action; -import com.sap.sse.gwt.dispatch.client.DispatchAsync; +import com.sap.sse.gwt.dispatch.client.DispatchSystemAsync; import com.sap.sse.gwt.dispatch.client.DispatchContext; import com.sap.sse.gwt.dispatch.client.Result; -public class AutomaticBatchingDispatch implements DispatchAsync { +public class AutomaticBatchingDispatch implements DispatchSystemAsync { private static final Logger LOG = Logger.getLogger(AutomaticBatchingDispatch.class.getName()); - private final DispatchAsync executionContext; + private final DispatchSystemAsync executionContext; private DispatchCallStack currentCallstack; @@ -29,7 +29,7 @@ public class AutomaticBatchingDispatch implements D * the underlying service implementation to use * */ - public AutomaticBatchingDispatch(DispatchAsync service) { + public AutomaticBatchingDispatch(DispatchSystemAsync service) { this(service, false); } @@ -40,9 +40,10 @@ public class AutomaticBatchingDispatch implements D * * @param service * the underlying service implementation to use - * + * @param processResultsScheduled + * use a {@link Scheduler} to process the results */ - public AutomaticBatchingDispatch(DispatchAsync service, boolean processResultsScheduled) { + public AutomaticBatchingDispatch(DispatchSystemAsync service, boolean processResultsScheduled) { this.executionContext = service; this.processResultsScheduled = processResultsScheduled; } diff --git a/java/com.sap.sse.gwt/src/com/sap/sse/gwt/dispatch/client/batching/BatchAction.java b/java/com.sap.sse.gwt/src/com/sap/sse/gwt/dispatch/client/batching/BatchAction.java index bae7351d45a..0c0c7f683aa 100644 --- a/java/com.sap.sse.gwt/src/com/sap/sse/gwt/dispatch/client/batching/BatchAction.java +++ b/java/com.sap.sse.gwt/src/com/sap/sse/gwt/dispatch/client/batching/BatchAction.java @@ -10,20 +10,20 @@ import com.sap.sse.gwt.dispatch.client.DispatchContext; import com.sap.sse.gwt.dispatch.client.Result; import com.sap.sse.gwt.dispatch.client.exceptions.DispatchException; -public class BatchAction implements Action { +public final class BatchAction implements Action { private static final Logger logger = Logger.getLogger(BatchAction.class.getName()); - private Action[] actions; + private ArrayList> actions = new ArrayList>(); - @SuppressWarnings("unused") - private BatchAction() { + protected BatchAction() { } - @SafeVarargs - public BatchAction(Action... actions) { - this.actions = actions; + public BatchAction(ArrayList> actions) { + if (actions != null) { + this.actions.addAll(actions); + } } - public Action[] getActions() { + public ArrayList> getActions() { return actions; } @@ -31,7 +31,7 @@ public class BatchAction implements Action results = new ArrayList(nrOfActions); final ArrayList exceptions = new ArrayList(nrOfActions); diff --git a/java/com.sap.sse.gwt/src/com/sap/sse/gwt/dispatch/client/batching/BatchResult.java b/java/com.sap.sse.gwt/src/com/sap/sse/gwt/dispatch/client/batching/BatchResult.java index aacd598ac95..6bdad089199 100644 --- a/java/com.sap.sse.gwt/src/com/sap/sse/gwt/dispatch/client/batching/BatchResult.java +++ b/java/com.sap.sse.gwt/src/com/sap/sse/gwt/dispatch/client/batching/BatchResult.java @@ -1,21 +1,21 @@ package com.sap.sse.gwt.dispatch.client.batching; +import java.util.ArrayList; import java.util.Iterator; -import java.util.LinkedList; import java.util.List; +import com.google.gwt.core.shared.GwtIncompatible; import com.sap.sse.gwt.dispatch.client.Result; import com.sap.sse.gwt.dispatch.client.exceptions.DispatchException; -public class BatchResult implements Result { - private LinkedList results = new LinkedList(); +public final class BatchResult implements Result { + private ArrayList results = new ArrayList<>(); + private ArrayList exceptions = new ArrayList<>(); - private LinkedList exceptions = new LinkedList(); - - @SuppressWarnings("unused") - private BatchResult() { + protected BatchResult() { } + @GwtIncompatible public BatchResult(List results, List exceptions) { this.results.addAll(results); this.exceptions.addAll(exceptions); @@ -37,9 +37,20 @@ public class BatchResult implements Result { return results.get(i); } + /** + * Retrieves the result at a given position only if it has the right type. Type safety is ensured by comparing class + * name. We cannot use isAssignableFrom because this is GWT/ client code. + * + * @param i + * result position + * @param type + * required result type + * @return result at given position + */ @SuppressWarnings("unchecked") public T getResult(int i, Class type) { Object result = results.get(i); + if (result != null && type.getName().equals(result.getClass().getName())) return (T) result; return null; diff --git a/java/com.sap.sse.gwt/src/com/sap/sse/gwt/dispatch/client/batching/DispatchCallStack.java b/java/com.sap.sse.gwt/src/com/sap/sse/gwt/dispatch/client/batching/DispatchCallStack.java index 720832a1232..41152a158ea 100644 --- a/java/com.sap.sse.gwt/src/com/sap/sse/gwt/dispatch/client/batching/DispatchCallStack.java +++ b/java/com.sap.sse.gwt/src/com/sap/sse/gwt/dispatch/client/batching/DispatchCallStack.java @@ -1,6 +1,6 @@ package com.sap.sse.gwt.dispatch.client.batching; -import java.util.LinkedList; +import java.util.ArrayList; import com.google.gwt.core.client.Scheduler.ScheduledCommand; import com.google.gwt.user.client.rpc.AsyncCallback; @@ -9,7 +9,7 @@ import com.sap.sse.gwt.dispatch.client.DispatchContext; import com.sap.sse.gwt.dispatch.client.Result; /** - * Convenience class used to aggregate {@link Call} instances. + * Convenience class used to aggregate {@link DispatchCall} instances. * * The class and all methods are private, its use is internal only. * @@ -19,7 +19,7 @@ public final class DispatchCallStack { /** * The list containg all queued actions. */ - private final LinkedList> actionQueue = new LinkedList>(); + private final ArrayList> actionQueue = new ArrayList>(); /** * The batch action holding the all the actions build in the queue. This instance variable is used to lazy @@ -30,7 +30,8 @@ public final class DispatchCallStack { /** * Add a call to the queue. Can only be called as long as the batch action has not been accessed/ initialized. * - * @param call + * @param action + * @param callback */ public , R extends Result> void addCall(A action, AsyncCallback callback) { assert (this.batchAction == null); @@ -38,16 +39,15 @@ public final class DispatchCallStack { } /** - * Return the aggregated calls as {@link BatchAction} instance. The instance is lazy initialized. + * Return the aggregated calls as {@link BatchAction} instance. The instance is initialized lazily. * * @return */ public BatchAction getBatchAction() { if (this.batchAction == null) { - @SuppressWarnings("unchecked") - Action[] actions = new Action[this.actionQueue.size()]; - for (int loop = 0; loop < actions.length; loop++) { - actions[loop] = this.actionQueue.get(loop).getAction(); + ArrayList> actions = new ArrayList>(); + for (DispatchCall dispatchCall : this.actionQueue) { + actions.add(dispatchCall.getAction()); } this.batchAction = new BatchAction(actions); } @@ -67,16 +67,16 @@ public final class DispatchCallStack { } /** - * Process results for the callstack. TODO: check generics usage, get rid of supress warnings + * Process results for the callstack. * * @param batchResult + * @param processResultsScheduled + * use a scheduler to execute the calls */ public void processResult(BatchResult batchResult, boolean processResultsScheduled) { assert (batchResult != null); - int loop = 0; - for (@SuppressWarnings("rawtypes") - DispatchCall call : this.actionQueue) { + for (DispatchCall call : this.actionQueue) { Result result = batchResult.getResult(loop); Throwable exception = batchResult.getException(loop); @@ -90,17 +90,24 @@ public final class DispatchCallStack { } } - @SuppressWarnings({"rawtypes", "unchecked"}) + + /** + * Scheduled command wrapping the callback method call. + */ private class CallbackCommand implements ScheduledCommand { + @SuppressWarnings("rawtypes") private final DispatchCall call; private final Result result; private final Throwable exception; + + @SuppressWarnings("rawtypes") public CallbackCommand(DispatchCall call, Result result, Throwable exception) { this.call = call; this.result = result; this.exception = exception; } + @SuppressWarnings("unchecked") @Override public void execute() { if (hasFailed()) { diff --git a/java/com.sap.sse.gwt/src/com/sap/sse/gwt/dispatch/client/batching/NonBatchableAction.java b/java/com.sap.sse.gwt/src/com/sap/sse/gwt/dispatch/client/batching/NonBatchableAction.java index abea374ea8c..4af4b24a17e 100644 --- a/java/com.sap.sse.gwt/src/com/sap/sse/gwt/dispatch/client/batching/NonBatchableAction.java +++ b/java/com.sap.sse.gwt/src/com/sap/sse/gwt/dispatch/client/batching/NonBatchableAction.java @@ -1,5 +1,8 @@ package com.sap.sse.gwt.dispatch.client.batching; +/** + * Marker interface to identify actions that must not be batched + */ public interface NonBatchableAction { } diff --git a/java/com.sap.sse.gwt/src/com/sap/sse/gwt/dispatch/client/batching/SplitScheduler.java b/java/com.sap.sse.gwt/src/com/sap/sse/gwt/dispatch/client/batching/SplitScheduler.java index a64a4073851..e19424b3c44 100644 --- a/java/com.sap.sse.gwt/src/com/sap/sse/gwt/dispatch/client/batching/SplitScheduler.java +++ b/java/com.sap.sse.gwt/src/com/sap/sse/gwt/dispatch/client/batching/SplitScheduler.java @@ -8,6 +8,9 @@ import com.google.gwt.core.client.Scheduler; import com.google.gwt.core.client.Scheduler.RepeatingCommand; import com.google.gwt.core.client.Scheduler.ScheduledCommand; +/** + * Convenience to enqueue and execute ScheduledCommands using the GWT scheduler. + */ public class SplitScheduler { private static final SplitScheduler INSTANCE = new SplitScheduler(); @@ -16,6 +19,12 @@ public class SplitScheduler { private boolean scheduled = false; + private SplitScheduler() { + } + + /** + * Repeating command instance that picks up the next element in the queue of pending commands and executes it. + */ private final RepeatingCommand repeatingCommand = new RepeatingCommand() { @Override public boolean execute() { @@ -33,13 +42,15 @@ public class SplitScheduler { } }; - private SplitScheduler() { - } - public static SplitScheduler get() { return INSTANCE; } + /** + * Add a command to the queue and executes it using the gwt scheduler. + * + * @param command + */ public void schedule(ScheduledCommand command) { pendingCommands.add(command); diff --git a/java/com.sap.sse.gwt/src/com/sap/sse/gwt/dispatch/client/caching/CachingDispatch.java b/java/com.sap.sse.gwt/src/com/sap/sse/gwt/dispatch/client/caching/CachingDispatch.java index 3673c5eabc0..84cfa625b82 100644 --- a/java/com.sap.sse.gwt/src/com/sap/sse/gwt/dispatch/client/caching/CachingDispatch.java +++ b/java/com.sap.sse.gwt/src/com/sap/sse/gwt/dispatch/client/caching/CachingDispatch.java @@ -8,29 +8,42 @@ import com.google.gwt.user.client.Timer; import com.google.gwt.user.client.rpc.AsyncCallback; import com.sap.sse.common.Duration; import com.sap.sse.gwt.dispatch.client.Action; -import com.sap.sse.gwt.dispatch.client.DispatchAsync; +import com.sap.sse.gwt.dispatch.client.DispatchSystemAsync; import com.sap.sse.gwt.dispatch.client.DispatchContext; import com.sap.sse.gwt.dispatch.client.Result; /** * Delegating dispatch implementation that caches results if actions implement IsClientCache interface. * - * @author pgtaboada */ -public final class CachingDispatch implements DispatchAsync { - +public final class CachingDispatch implements DispatchSystemAsync { private static final Logger LOG = Logger.getLogger(CachingDispatch.class.getName()); - private final CacheCleanupTask invalidationTask; private final HashMap resultsCache = new HashMap<>(); - private final DispatchAsync dispatch; + private final DispatchSystemAsync dispatch; private final int defaultTimeToLive; - public CachingDispatch(DispatchAsync service) { + /** + * Create new caching dispatch instance with default values. + * + * @param service + * the underlying service used to make dispatch calls + */ + public CachingDispatch(DispatchSystemAsync service) { this(service, true, (int) Duration.ONE_MINUTE.times(3).asMillis()); } - public CachingDispatch(DispatchAsync service, boolean enableCleanup, int defaultTimeToLive) { + /** + * Create new caching dispatch instance with given parameters + * + * @param service + * the underlying service used to make dispatch calls + * @param enableCleanup + * enable cleanup cached elements + * @param defaultTimeToLive + * default cached element time to live + */ + public CachingDispatch(DispatchSystemAsync service, boolean enableCleanup, int defaultTimeToLive) { this.dispatch = service; this.defaultTimeToLive = defaultTimeToLive; if (enableCleanup) { @@ -60,21 +73,23 @@ public final class CachingDispatch implements Dispa }; /** - * Perform dispatch call with intercepting callback. + * Perform dispatch call with using an intercepting callback for client cacheable commands. * * @param action * @param callback */ private > void executeAndCache(final A action, final AsyncCallback callback) { - dispatch.execute(action, new InterceptingCallback<>(action, callback)); + if (action instanceof IsClientCacheable) { + dispatch.execute(action, new InterceptingCallback<>(action, callback)); + } else { + dispatch.execute(action, callback); + } } /** * Intercepting callback that stores the result into cache. * - * @author pgtaboada - * * @param * @param */ @@ -89,26 +104,35 @@ public final class CachingDispatch implements Dispa @Override public void onSuccess(R result) { - if (action instanceof IsClientCacheable) { - final IsClientCacheable clientCacheableAction = (IsClientCacheable) action; - final String instanceKey = key(clientCacheableAction); - int cacheTotalTimeToLiveMillis = defaultTimeToLive; - if (result instanceof HasClientCacheTotalTimeToLive) { - cacheTotalTimeToLiveMillis = ((HasClientCacheTotalTimeToLive) result).cacheTotalTimeToLiveMillis(); - } else if (action instanceof HasClientCacheTotalTimeToLive) { - cacheTotalTimeToLiveMillis = ((HasClientCacheTotalTimeToLive) action).cacheTotalTimeToLiveMillis(); - } - resultsCache.put(instanceKey, new ResultHolder(System.currentTimeMillis() - + cacheTotalTimeToLiveMillis, result)); - LOG.finest("Added " + instanceKey + " to cache, ttl: " + cacheTotalTimeToLiveMillis + "ms"); - if (invalidationTask != null && !invalidationTask.isRunning()) { - LOG.finest("Schedule cache cleanup"); - invalidationTask.schedule((int) Duration.ONE_MINUTE.times(5).asMillis()); - } + final IsClientCacheable clientCacheableAction = (IsClientCacheable) action; + final String instanceKey = key(clientCacheableAction); + int cacheTotalTimeToLiveMillis = timeToLive(action, result); + resultsCache.put(instanceKey, new ResultHolder(System.currentTimeMillis() + cacheTotalTimeToLiveMillis, + result)); + LOG.finest("Added " + instanceKey + " to cache, ttl: " + cacheTotalTimeToLiveMillis + "ms"); + if (invalidationTask != null && !invalidationTask.isRunning()) { + LOG.finest("Schedule cache cleanup"); + invalidationTask.schedule((int) Duration.ONE_MINUTE.times(5).asMillis()); } callback.onSuccess(result); } + /** + * Calculate time to live fore result + * + * @param action + * @param result + * @return + */ + private int timeToLive(A action, R result) { + int cacheTotalTimeToLiveMillis = defaultTimeToLive; + if (result instanceof HasClientCacheTotalTimeToLive) { + cacheTotalTimeToLiveMillis = ((HasClientCacheTotalTimeToLive) result).cacheTotalTimeToLiveMillis(); + } else if (action instanceof HasClientCacheTotalTimeToLive) { + cacheTotalTimeToLiveMillis = ((HasClientCacheTotalTimeToLive) action).cacheTotalTimeToLiveMillis(); + } + return cacheTotalTimeToLiveMillis; + } @Override public void onFailure(Throwable caught) { callback.onFailure(caught); @@ -130,8 +154,6 @@ public final class CachingDispatch implements Dispa /** * Holder class used to store results in cache. * - * @author pgtaboada - * */ private static class ResultHolder { final Result payload; @@ -168,8 +190,6 @@ public final class CachingDispatch implements Dispa /** * Removes due elements from resultscache. * - * @author pgtaboada - * */ private class CacheCleanupTask extends Timer { @Override diff --git a/java/com.sap.sse.gwt/src/com/sap/sse/gwt/dispatch/client/caching/HasClientCacheTotalTimeToLive.java b/java/com.sap.sse.gwt/src/com/sap/sse/gwt/dispatch/client/caching/HasClientCacheTotalTimeToLive.java index f6b88528041..75b402ecca7 100644 --- a/java/com.sap.sse.gwt/src/com/sap/sse/gwt/dispatch/client/caching/HasClientCacheTotalTimeToLive.java +++ b/java/com.sap.sse.gwt/src/com/sap/sse/gwt/dispatch/client/caching/HasClientCacheTotalTimeToLive.java @@ -1,9 +1,7 @@ package com.sap.sse.gwt.dispatch.client.caching; /** - * Interface used by actions and results to override default cache time to live. - * - * @author pgtaboada + * Interface used by actions and results to provide cache time to live. * */ public interface HasClientCacheTotalTimeToLive { diff --git a/java/com.sap.sse.gwt/src/com/sap/sse/gwt/dispatch/client/caching/IsClientCacheable.java b/java/com.sap.sse.gwt/src/com/sap/sse/gwt/dispatch/client/caching/IsClientCacheable.java index 6614d218a94..c1d6341048a 100644 --- a/java/com.sap.sse.gwt/src/com/sap/sse/gwt/dispatch/client/caching/IsClientCacheable.java +++ b/java/com.sap.sse.gwt/src/com/sap/sse/gwt/dispatch/client/caching/IsClientCacheable.java @@ -3,13 +3,14 @@ package com.sap.sse.gwt.dispatch.client.caching; /** * Cache interface used by the caching dispatch to identify which command can be cached on client side. * - * @author pgtaboada - * + * Each command must provide an instance key used to store the results in the cache. + * + * The instance key is appended to an class identifying key. */ public interface IsClientCacheable { /** - * The instance specific key used to identify instance specific results in the cache. + * The builder used to identify instance specific results in the cache. * * @return */ diff --git a/java/com.sap.sse.gwt/src/com/sap/sse/gwt/dispatch/client/exceptions/DispatchException.java b/java/com.sap.sse.gwt/src/com/sap/sse/gwt/dispatch/client/exceptions/DispatchException.java index cd86ad240a8..b314c3bae24 100644 --- a/java/com.sap.sse.gwt/src/com/sap/sse/gwt/dispatch/client/exceptions/DispatchException.java +++ b/java/com.sap.sse.gwt/src/com/sap/sse/gwt/dispatch/client/exceptions/DispatchException.java @@ -1,16 +1,25 @@ package com.sap.sse.gwt.dispatch.client.exceptions; +import java.util.UUID; + +import com.google.gwt.core.shared.GwtIncompatible; import com.google.gwt.user.client.rpc.IsSerializable; public class DispatchException extends RuntimeException implements IsSerializable { - private static final long serialVersionUID = 8192187255698006941L; + private String exceptionId; protected DispatchException() { } + @GwtIncompatible public DispatchException(String message) { super(message); + exceptionId = UUID.randomUUID().toString(); + } + + public String getExceptionId() { + return exceptionId; } } diff --git a/java/com.sap.sse.gwt/src/com/sap/sse/gwt/dispatch/client/exceptions/ServerDispatchException.java b/java/com.sap.sse.gwt/src/com/sap/sse/gwt/dispatch/client/exceptions/ServerDispatchException.java index 8c509aba789..7622aa41bbd 100644 --- a/java/com.sap.sse.gwt/src/com/sap/sse/gwt/dispatch/client/exceptions/ServerDispatchException.java +++ b/java/com.sap.sse.gwt/src/com/sap/sse/gwt/dispatch/client/exceptions/ServerDispatchException.java @@ -1,28 +1,17 @@ package com.sap.sse.gwt.dispatch.client.exceptions; -import java.util.UUID; - +import com.google.gwt.core.shared.GwtIncompatible; public class ServerDispatchException extends DispatchException { private static final long serialVersionUID = 8192187255698006941L; - private String uuid; protected ServerDispatchException() { } - public ServerDispatchException(String uuid, Throwable cause) { - super(cause.getMessage()); - this.uuid = uuid; - } - + @GwtIncompatible public ServerDispatchException(Throwable cause) { super(cause.getMessage()); - this.uuid = UUID.randomUUID().toString(); - } - - public String getUuid() { - return uuid; } } diff --git a/java/com.sap.sse.gwt/src/com/sap/sse/gwt/dispatch/client/impl/DispatchSystem.java b/java/com.sap.sse.gwt/src/com/sap/sse/gwt/dispatch/client/impl/DispatchSystem.java index dc3f8175ad1..cba2b45bb63 100644 --- a/java/com.sap.sse.gwt/src/com/sap/sse/gwt/dispatch/client/impl/DispatchSystem.java +++ b/java/com.sap.sse.gwt/src/com/sap/sse/gwt/dispatch/client/impl/DispatchSystem.java @@ -2,9 +2,15 @@ package com.sap.sse.gwt.dispatch.client.impl; import java.util.Date; -import com.sap.sse.gwt.dispatch.client.DispatchAsync; +import com.sap.sse.gwt.dispatch.client.DispatchSystemAsync; import com.sap.sse.gwt.dispatch.client.DispatchContext; -public interface DispatchSystem extends DispatchAsync { +/** + * The dispatch system is the client side implementation of the dispatch communication pattern. + * + * @param + * the context that will be provided to the actions during execution + */ +public interface DispatchSystem extends DispatchSystemAsync { Date getCurrentServerTime(); } diff --git a/java/com.sap.sse.gwt/src/com/sap/sse/gwt/dispatch/client/impl/DispatchSystemImpl.java b/java/com.sap.sse.gwt/src/com/sap/sse/gwt/dispatch/client/impl/DispatchSystemImpl.java index 79000d31e64..ac6d91f6a34 100644 --- a/java/com.sap.sse.gwt/src/com/sap/sse/gwt/dispatch/client/impl/DispatchSystemImpl.java +++ b/java/com.sap.sse.gwt/src/com/sap/sse/gwt/dispatch/client/impl/DispatchSystemImpl.java @@ -1,43 +1,62 @@ package com.sap.sse.gwt.dispatch.client.impl; import java.util.Date; +import java.util.logging.Level; +import java.util.logging.Logger; -import com.google.gwt.core.shared.GWT; +import com.google.gwt.core.client.Scheduler; import com.google.gwt.user.client.rpc.AsyncCallback; import com.sap.sse.gwt.dispatch.client.Action; -import com.sap.sse.gwt.dispatch.client.DispatchAsync; +import com.sap.sse.gwt.dispatch.client.DispatchSystemAsync; import com.sap.sse.gwt.dispatch.client.DispatchContext; import com.sap.sse.gwt.dispatch.client.Result; import com.sap.sse.gwt.dispatch.client.batching.AutomaticBatchingDispatch; import com.sap.sse.gwt.dispatch.client.caching.CachingDispatch; +import com.sap.sse.gwt.dispatch.client.exceptions.DispatchException; import com.sap.sse.gwt.dispatch.client.exceptions.ServerDispatchException; import com.sap.sse.gwt.dispatch.client.rpcimpl.SimpleDispatch; -public class DispatchSystemImpl implements DispatchSystem { - +/** + * Base implementation of a client side dispatch executor. + * + * The dispatch system implements caching {@link CachingDispatch} and automatic batching + * {@link AutomaticBatchingDispatch}. + * + * @param + */ +public abstract class DispatchSystemImpl implements DispatchSystem { + private final Logger LOG = Logger.getLogger(DispatchSystemImpl.class.getName()); private final SimpleDispatch simpleDispatch; - private final DispatchAsync dispatch; + private final DispatchSystemAsync dispatch; public DispatchSystemImpl(String dispatchRPCPath) { this(dispatchRPCPath, false); } + /** + * + * Create a dispatch system + * + * @param dispatchRPCPath + * rpc-servlet path + * @param processResultsScheduled + * use a {@link Scheduler} to process the results + */ public DispatchSystemImpl(String dispatchRPCPath, boolean processResultsScheduled) { simpleDispatch = new SimpleDispatch(dispatchRPCPath); dispatch = new CachingDispatch(new AutomaticBatchingDispatch( simpleDispatch, processResultsScheduled)); + LOG.finest("Started dispatch system for " + dispatchRPCPath); } @Override public > void execute(final A action, final AsyncCallback callback) { - // TODO: client side execution time logging - AsyncCallback wrappedCallback = new AsyncCallback() { + final AsyncCallback wrappedCallback = new AsyncCallback() { @Override public void onFailure(Throwable caught) { - if (caught instanceof ServerDispatchException) { + if (caught instanceof DispatchException) { ServerDispatchException sde = (ServerDispatchException) caught; - // TODO: browser console log - GWT.log("Server exception with id: " + sde.getUuid()); + LOG.log(Level.SEVERE, "Server exception with id: " + sde.getExceptionId()); } callback.onFailure(caught); } diff --git a/java/com.sap.sse.gwt/src/com/sap/sse/gwt/dispatch/client/rpcimpl/DispatchRPC.java b/java/com.sap.sse.gwt/src/com/sap/sse/gwt/dispatch/client/rpcimpl/DispatchRPC.java index 2e828fad41e..464e6a4814f 100644 --- a/java/com.sap.sse.gwt/src/com/sap/sse/gwt/dispatch/client/rpcimpl/DispatchRPC.java +++ b/java/com.sap.sse.gwt/src/com/sap/sse/gwt/dispatch/client/rpcimpl/DispatchRPC.java @@ -4,9 +4,13 @@ import com.google.gwt.user.client.rpc.RemoteService; import com.sap.sse.gwt.dispatch.client.Action; import com.sap.sse.gwt.dispatch.client.DispatchContext; import com.sap.sse.gwt.dispatch.client.Result; -import com.sap.sse.gwt.dispatch.client.ResultWrapper; import com.sap.sse.gwt.dispatch.client.exceptions.DispatchException; +/** + * GWT RPC interfaces for dispatch communication + * + * @param + */ public interface DispatchRPC extends RemoteService { > ResultWrapper execute( diff --git a/java/com.sap.sse.gwt/src/com/sap/sse/gwt/dispatch/client/rpcimpl/DispatchRPCAsync.java b/java/com.sap.sse.gwt/src/com/sap/sse/gwt/dispatch/client/rpcimpl/DispatchRPCAsync.java index 0d0c21254a5..9656ef9cc0b 100644 --- a/java/com.sap.sse.gwt/src/com/sap/sse/gwt/dispatch/client/rpcimpl/DispatchRPCAsync.java +++ b/java/com.sap.sse.gwt/src/com/sap/sse/gwt/dispatch/client/rpcimpl/DispatchRPCAsync.java @@ -4,8 +4,12 @@ import com.google.gwt.user.client.rpc.AsyncCallback; import com.sap.sse.gwt.dispatch.client.Action; import com.sap.sse.gwt.dispatch.client.DispatchContext; import com.sap.sse.gwt.dispatch.client.Result; -import com.sap.sse.gwt.dispatch.client.ResultWrapper; +/** + * Async interface + * + * @param + */ public interface DispatchRPCAsync { > void execute( diff --git a/java/com.sap.sse.gwt/src/com/sap/sse/gwt/dispatch/client/rpcimpl/RequestWrapper.java b/java/com.sap.sse.gwt/src/com/sap/sse/gwt/dispatch/client/rpcimpl/RequestWrapper.java index 504507275bd..bfbf8fdb831 100644 --- a/java/com.sap.sse.gwt/src/com/sap/sse/gwt/dispatch/client/rpcimpl/RequestWrapper.java +++ b/java/com.sap.sse.gwt/src/com/sap/sse/gwt/dispatch/client/rpcimpl/RequestWrapper.java @@ -7,6 +7,16 @@ import com.sap.sse.gwt.dispatch.client.Action; import com.sap.sse.gwt.dispatch.client.DispatchContext; import com.sap.sse.gwt.dispatch.client.Result; +/** + * Wrapper that encapsulates an action to be sent to the server. + * + * @param + * Action + * @param + * Result + * @param + * Execution context + */ public class RequestWrapper, CTX extends DispatchContext> implements IsSerializable { diff --git a/java/com.sap.sse.gwt/src/com/sap/sse/gwt/dispatch/client/ResultWrapper.java b/java/com.sap.sse.gwt/src/com/sap/sse/gwt/dispatch/client/rpcimpl/ResultWrapper.java similarity index 75% rename from java/com.sap.sse.gwt/src/com/sap/sse/gwt/dispatch/client/ResultWrapper.java rename to java/com.sap.sse.gwt/src/com/sap/sse/gwt/dispatch/client/rpcimpl/ResultWrapper.java index f81121da193..be3644c59e1 100644 --- a/java/com.sap.sse.gwt/src/com/sap/sse/gwt/dispatch/client/ResultWrapper.java +++ b/java/com.sap.sse.gwt/src/com/sap/sse/gwt/dispatch/client/rpcimpl/ResultWrapper.java @@ -1,9 +1,15 @@ -package com.sap.sse.gwt.dispatch.client; +package com.sap.sse.gwt.dispatch.client.rpcimpl; import java.util.Date; import com.google.gwt.user.client.rpc.IsSerializable; +import com.sap.sse.gwt.dispatch.client.Result; +/** + * Result wrapper that encapsulates the curent server time. + * + * @param + */ public class ResultWrapper implements IsSerializable { private Date currentServerTime = new Date(); diff --git a/java/com.sap.sse.gwt/src/com/sap/sse/gwt/dispatch/client/rpcimpl/SimpleDispatch.java b/java/com.sap.sse.gwt/src/com/sap/sse/gwt/dispatch/client/rpcimpl/SimpleDispatch.java index b800e474fc0..b5b0db4440f 100644 --- a/java/com.sap.sse.gwt/src/com/sap/sse/gwt/dispatch/client/rpcimpl/SimpleDispatch.java +++ b/java/com.sap.sse.gwt/src/com/sap/sse/gwt/dispatch/client/rpcimpl/SimpleDispatch.java @@ -5,12 +5,16 @@ import com.google.gwt.i18n.client.LocaleInfo; import com.google.gwt.user.client.rpc.AsyncCallback; import com.google.gwt.user.client.rpc.ServiceDefTarget; import com.sap.sse.gwt.dispatch.client.Action; -import com.sap.sse.gwt.dispatch.client.DispatchAsync; +import com.sap.sse.gwt.dispatch.client.DispatchSystemAsync; import com.sap.sse.gwt.dispatch.client.DispatchContext; import com.sap.sse.gwt.dispatch.client.Result; -import com.sap.sse.gwt.dispatch.client.ResultWrapper; -public class SimpleDispatch implements DispatchAsync { +/** + * Simple dispatch implementation that uses GWT RPC internally to communicate with the server + * + * @param + */ +public class SimpleDispatch implements DispatchSystemAsync { private final DispatchRPCAsync dispatchRPC = GWT.create(DispatchRPC.class); @@ -22,7 +26,8 @@ public class SimpleDispatch implements DispatchAsyn @Override public > void execute(A action, final AsyncCallback callback) { - RequestWrapper requestWrapper = new RequestWrapper(action, LocaleInfo.getCurrentLocale() + final RequestWrapper requestWrapper = new RequestWrapper(action, LocaleInfo + .getCurrentLocale() .getLocaleName()); final long clientTimeOnRequestStart = System.currentTimeMillis(); dispatchRPC.execute(requestWrapper, new AsyncCallback>() { diff --git a/java/com.sap.sse.security.ui/src/main/java/com/sap/sse/security/ui/client/AbstractSecureEntryPoint.java b/java/com.sap.sse.security.ui/src/main/java/com/sap/sse/security/ui/client/AbstractSecureEntryPoint.java index 235981885d6..1d9909a951c 100755 --- a/java/com.sap.sse.security.ui/src/main/java/com/sap/sse/security/ui/client/AbstractSecureEntryPoint.java +++ b/java/com.sap.sse.security.ui/src/main/java/com/sap/sse/security/ui/client/AbstractSecureEntryPoint.java @@ -1,6 +1,8 @@ package com.sap.sse.security.ui.client; import com.google.gwt.core.client.EntryPoint; +import com.google.gwt.dom.client.Document; +import com.google.gwt.dom.client.Element; import com.sap.sse.gwt.client.StringMessages; /** @@ -15,8 +17,17 @@ import com.sap.sse.gwt.client.StringMessages; public abstract class AbstractSecureEntryPoint extends com.sap.sse.gwt.client.AbstractEntryPoint implements WithSecurity { private WithSecurity securityProvider; + /** + * Initializes the {@link UserManagementService} and removes the optional loading indicator from the DOM which is + * identified by the "loading" ID. See the Home.html or AdminConsole.html entry point implementations for examples + * of how such a loading indicator can nicely be implemented. + */ protected void doOnModuleLoad() { securityProvider = new DefaultWithSecurityImpl(); + final Element optionalLoadingIndicator = Document.get().getElementById("loading"); + if (optionalLoadingIndicator != null) { + optionalLoadingIndicator.removeFromParent(); + } } @Override diff --git a/java/com.tractrac.clientmodule/META-INF/MANIFEST.MF b/java/com.tractrac.clientmodule/META-INF/MANIFEST.MF index d0f23396912..5238374bdb5 100644 --- a/java/com.tractrac.clientmodule/META-INF/MANIFEST.MF +++ b/java/com.tractrac.clientmodule/META-INF/MANIFEST.MF @@ -2,7 +2,7 @@ Manifest-Version: 1.0 Bundle-ManifestVersion: 2 Bundle-Name: TracTrac Client module Bundle-SymbolicName: com.tractrac.clientmodule -Bundle-Version: 3.1.1 +Bundle-Version: 3.1.3 Bundle-RequiredExecutionEnvironment: JavaSE-1.8 Bundle-ClassPath: ., lib/TracAPI.jar diff --git a/java/com.tractrac.clientmodule/README.txt b/java/com.tractrac.clientmodule/README.txt index 4e5e0c38f1d..895702bd543 100644 --- a/java/com.tractrac.clientmodule/README.txt +++ b/java/com.tractrac.clientmodule/README.txt @@ -16,6 +16,33 @@ It contains also some files: - test.sh -> script that compiles the code in the src folder, creates the test.jar library and execute the code of the example. - Manifest.txt -> manifest used to create the test.jar file +******************************************** +************* TracAPI 3.1.3 **************** +******************************************** +This is a final version. Only fixes bugs in the implementation + +Release date: 25/01/2016 +Build number: 11888 + + 1) Bugs + + - The bug of the previous release (3.1.3) was not fixed. + +******************************************** +************* TracAPI 3.1.2 **************** +******************************************** +This is a final version. Only fixes bugs in the implementation + +Release date: 21/01/2016 +Build number: 11864 + + 1) Bugs + + - The ISubscriber.stop() method never finishes due to a deadlock (it happens sometimes). + There is a deadlock between one of the internal threads responsible to update the progress + and the thread that calls the stop method. The release 3.1.1 fixed a part of the bug but + it continues happening due to a new deadlock (Reported by Axel Uhl, 20/01/2016) + ******************************************** ************* TracAPI 3.1.1 **************** ******************************************** diff --git a/java/com.tractrac.clientmodule/lib/TracAPI-src.jar b/java/com.tractrac.clientmodule/lib/TracAPI-src.jar index 6b8e4560d06..169fe555191 100755 Binary files a/java/com.tractrac.clientmodule/lib/TracAPI-src.jar and b/java/com.tractrac.clientmodule/lib/TracAPI-src.jar differ diff --git a/java/com.tractrac.clientmodule/lib/TracAPI.jar b/java/com.tractrac.clientmodule/lib/TracAPI.jar index 92c5449d953..b2201015269 100644 Binary files a/java/com.tractrac.clientmodule/lib/TracAPI.jar and b/java/com.tractrac.clientmodule/lib/TracAPI.jar differ diff --git a/java/com.tractrac.clientmodule/pom.xml b/java/com.tractrac.clientmodule/pom.xml index 878f6e1465b..8628b049b63 100755 --- a/java/com.tractrac.clientmodule/pom.xml +++ b/java/com.tractrac.clientmodule/pom.xml @@ -8,6 +8,6 @@ 1.0.0-SNAPSHOT com.tractrac.clientmodule - 3.1.1 + 3.1.3 eclipse-plugin diff --git a/mobile/com.sap.sailing.racecommittee.app/src/com/sap/sailing/racecommittee/app/domain/impl/CompetitorsWithIdImpl.java b/mobile/com.sap.sailing.racecommittee.app/src/com/sap/sailing/racecommittee/app/domain/impl/CompetitorsWithIdImpl.java index c4fc49979e4..c2169d77982 100644 --- a/mobile/com.sap.sailing.racecommittee.app/src/com/sap/sailing/racecommittee/app/domain/impl/CompetitorsWithIdImpl.java +++ b/mobile/com.sap.sailing.racecommittee.app/src/com/sap/sailing/racecommittee/app/domain/impl/CompetitorsWithIdImpl.java @@ -2,6 +2,7 @@ package com.sap.sailing.racecommittee.app.domain.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.Util; @@ -19,11 +20,11 @@ public class CompetitorsWithIdImpl { mReason = reason; } - public CompetitorsWithIdImpl(long id, Util.Triple triple) { + public CompetitorsWithIdImpl(long id, CompetitorResult triple) { mId = id; - mKey = triple.getA(); - mText = triple.getB(); - mReason = triple.getC(); + mKey = triple.getCompetitorId(); + mText = triple.getCompetitorDisplayName(); + mReason = triple.getMaxPointsReason(); } public long getId() { diff --git a/mobile/com.sap.sailing.racecommittee.app/src/com/sap/sailing/racecommittee/app/ui/fragments/raceinfo/PositioningFragment.java b/mobile/com.sap.sailing.racecommittee.app/src/com/sap/sailing/racecommittee/app/ui/fragments/raceinfo/PositioningFragment.java index eaab231301d..5fb288029eb 100644 --- a/mobile/com.sap.sailing.racecommittee.app/src/com/sap/sailing/racecommittee/app/ui/fragments/raceinfo/PositioningFragment.java +++ b/mobile/com.sap.sailing.racecommittee.app/src/com/sap/sailing/racecommittee/app/ui/fragments/raceinfo/PositioningFragment.java @@ -12,12 +12,15 @@ import android.view.View; import android.view.ViewGroup; import android.widget.Button; import android.widget.Toast; + import com.h6ah4i.android.widget.advrecyclerview.animator.SwipeDismissItemAnimator; import com.h6ah4i.android.widget.advrecyclerview.draggable.RecyclerViewDragDropManager; import com.h6ah4i.android.widget.advrecyclerview.swipeable.RecyclerViewSwipeManager; import com.h6ah4i.android.widget.advrecyclerview.touchguard.RecyclerViewTouchActionGuardManager; import com.h6ah4i.android.widget.advrecyclerview.utils.WrapperAdapterUtils; +import com.sap.sailing.domain.abstractlog.race.CompetitorResult; import com.sap.sailing.domain.abstractlog.race.CompetitorResults; +import com.sap.sailing.domain.abstractlog.race.impl.CompetitorResultImpl; import com.sap.sailing.domain.abstractlog.race.impl.CompetitorResultsImpl; import com.sap.sailing.domain.base.Competitor; import com.sap.sailing.domain.base.CompetitorStore; @@ -248,7 +251,7 @@ public class PositioningFragment extends BaseFragment private ArrayList initializeFinishList() { ArrayList positioning = new ArrayList<>(); if (getRaceState() != null && getRaceState().getFinishPositioningList() != null) { - for (Util.Triple results : getRaceState().getFinishPositioningList()) { + for (CompetitorResult results : getRaceState().getFinishPositioningList()) { positioning.add(new CompetitorsWithIdImpl(mId, results)); mId++; } @@ -337,15 +340,17 @@ public class PositioningFragment extends BaseFragment } private void setCompetitorToBottomOfPositioningList(CompetitorsWithIdImpl item) { - int lastIndex = getCompetitorResults().size() - 1; + int lastIndex = Util.size(getCompetitorResults()) - 1; mFinishedData.remove(item); mFinishedData.add(lastIndex, item); } private CompetitorResults getCompetitorResults() { CompetitorResults result = new CompetitorResultsImpl(); + int oneBasedRank = 1; for (CompetitorsWithIdImpl item : mFinishedData) { - result.add(new Util.Triple(item.getKey(), item.getText(), item.getReason())); + result.add(new CompetitorResultImpl(item.getKey(), item.getText(), oneBasedRank++, item.getReason(), + /* score */ null, /* finishingTime */ null, /* comment */ null)); } return result; } diff --git a/wiki/onboarding.md b/wiki/onboarding.md index 979177eb53a..7fa16656440 100644 --- a/wiki/onboarding.md +++ b/wiki/onboarding.md @@ -8,7 +8,7 @@ First of all, make sure you've looked at http://www.amazon.de/Patterns-Elements- #### Installations -1. Eclipse (Eclipse Eclipse Committers), http://www.eclipse.org +1. Eclipse (Eclipse for Eclipse Committers, e.g. version "Mars"), http://www.eclipse.org 2. Eclipse Extensions * Install Google plugin for Eclipse (https://developers.google.com/eclipse/docs/download) * Install Eclipse debugger for GWT SuperDevMode (master version: http://p2.sapsailing.com/p2/sdbg; public release: http://sdbg.github.io/p2)