diff --git a/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/CourseDesignerMode.java b/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/CourseDesignerMode.java index 627266e2e18..32f66797e7e 100644 --- a/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/CourseDesignerMode.java +++ b/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/CourseDesignerMode.java @@ -9,15 +9,23 @@ import java.util.List; * When modifying these values also check res/preferences.xml of racecommittee.app! */ public enum CourseDesignerMode { - UNKNOWN("Unknown"), - BY_NAME("By-Name Course Designer"), // O2, O3, I2,... - BY_MAP("By-Map Course Designer"), // Map-based Course Designer - BY_MARKS("By-Marks Course Designer"); // ESS + UNKNOWN("Unknown", /* waypointSequenceValid */ false), + BY_NAME("By-Name Course Designer", /* waypointSequenceValid */ false), // O2, O3, I2,... + BY_MAP("By-Map Course Designer", /* waypointSequenceValid */ true), // Map-based Course Designer + BY_MARKS("By-Marks Course Designer", /* waypointSequenceValid */ true), // ESS + ADMIN_CONSOLE("Administration Console", /* waypointSequenceValid */ true); - private String displayName; + private final String displayName; + + /** + * Some course designers may only be able to tell, say, a name for the new course but not + * necessarily a valid waypoint sequence. This flag tells. + */ + private final boolean waypointSequenceValid; - private CourseDesignerMode(String displayName) { + private CourseDesignerMode(String displayName, boolean waypointSequenceValid) { this.displayName = displayName; + this.waypointSequenceValid = waypointSequenceValid; } @Override @@ -25,6 +33,10 @@ public enum CourseDesignerMode { return displayName; } + public boolean isWaypointSequenceValid() { + return waypointSequenceValid; + } + public static CourseDesignerMode[] validValues() { List validValues = new ArrayList(); for (CourseDesignerMode type : values()) { 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 04b13c5a846..13be7d77169 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 @@ -143,6 +143,7 @@ import com.sap.sailing.domain.base.impl.SailingServerConfigurationImpl; import com.sap.sailing.domain.base.impl.SeriesImpl; import com.sap.sailing.domain.base.impl.VenueImpl; import com.sap.sailing.domain.base.impl.WaypointImpl; +import com.sap.sailing.domain.common.CourseDesignerMode; import com.sap.sailing.domain.common.MarkType; import com.sap.sailing.domain.common.MaxPointsReason; import com.sap.sailing.domain.common.PassingInstruction; @@ -1504,7 +1505,9 @@ public class DomainObjectFactoryImpl implements DomainObjectFactory { private RaceLogCourseDesignChangedEvent loadRaceLogCourseDesignChangedEvent(TimePoint createdAt, AbstractLogEventAuthor author, TimePoint logicalTimePoint, Serializable id, Integer passId, List competitors, DBObject dbObject) { String courseName = (String) dbObject.get(FieldNames.RACE_LOG_COURSE_DESIGN_NAME.name()); CourseBase courseData = loadCourseData((BasicDBList) dbObject.get(FieldNames.RACE_LOG_COURSE_DESIGN.name()), courseName); - return new RaceLogCourseDesignChangedEventImpl(createdAt, logicalTimePoint, author, id, passId, courseData); + final String courseDesignerModeName = (String) dbObject.get(FieldNames.RACE_LOG_COURSE_DESIGNER_MODE.name()); + final CourseDesignerMode courseDesignerMode = courseDesignerModeName == null ? null : CourseDesignerMode.valueOf(courseDesignerModeName); + return new RaceLogCourseDesignChangedEventImpl(createdAt, logicalTimePoint, author, id, passId, courseData, courseDesignerMode); } private RaceLogCourseAreaChangedEvent loadRaceLogCourseAreaChangedEvent(TimePoint createdAt, AbstractLogEventAuthor author, TimePoint logicalTimePoint, Serializable id, Integer passId, List competitors, DBObject dbObject) { 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 index e7c2699cf1e..b94aec6fa43 100644 --- 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 @@ -89,7 +89,7 @@ public enum FieldNames { // race log RACE_LOG_IDENTIFIER, RACE_LOG_EVENT, RACE_LOG_EVENT_PASS_ID, RACE_LOG_EVENT_ID, RACE_LOG_EVENT_CREATED_AT, RACE_LOG_EVENT_AUTHOR_NAME, RACE_LOG_EVENT_AUTHOR_PRIORITY, RACE_LOG_EVENT_INVOLVED_BOATS, RACE_LOG_EVENT_FLAG_UPPER, RACE_LOG_EVENT_FLAG_LOWER, RACE_LOG_EVENT_FLAG_DISPLAYED, - RACE_LOG_EVENT_START_TIME, RACE_LOG_EVENT_CLASS, RACE_LOG_EVENT_NEXT_STATUS, RACE_LOG_COURSE_DESIGN, WAYPOINT_ID, WAYPOINT_NAME, + RACE_LOG_EVENT_START_TIME, RACE_LOG_EVENT_CLASS, RACE_LOG_EVENT_NEXT_STATUS, RACE_LOG_COURSE_DESIGN, RACE_LOG_COURSE_DESIGNER_MODE, WAYPOINT_ID, WAYPOINT_NAME, WAYPOINT_PASSINGINSTRUCTIONS, CONTROLPOINT, CONTROLPOINT_CLASS, MARK_ID, MARK_COLOR, MARK_NAME, MARK_PATTERN, MARK_SHAPE, MARK_TYPE, 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, 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 37e3c3573d5..46900f28ed4 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 @@ -1117,6 +1117,8 @@ public class MongoObjectFactoryImpl implements MongoObjectFactory { 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_DESIGNER_MODE.name(), + courseDesignChangedEvent.getCourseDesignerMode() == null ? null : courseDesignChangedEvent.getCourseDesignerMode().name()); result.put(FieldNames.RACE_LOG_COURSE_DESIGN.name(), storeCourseBase(courseDesignChangedEvent.getCourseDesign())); return result; } 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 5e9ca597b04..cab79b3e678 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 @@ -436,7 +436,7 @@ public class RaceLogRaceTracker implements RaceTracker, GPSFixReceivedListener { private void onCourseDesignChangedEvent(RaceLogCourseDesignChangedEvent event) { if (trackedRace != null) { - CourseBase base = new LastPublishedCourseDesignFinder(params.getRaceLog()).analyze(); + CourseBase base = new LastPublishedCourseDesignFinder(params.getRaceLog(), /* onlyCoursesWithValidWaypointList */ true).analyze(); List> update = new ArrayList<>(); for (Waypoint waypoint : base.getWaypoints()) { update.add(new Util.Pair<>(waypoint.getControlPoint(), waypoint.getPassingInstructions())); @@ -462,7 +462,7 @@ public class RaceLogRaceTracker implements RaceTracker, GPSFixReceivedListener { } BoatClass boatClass = denoteEvent.getBoatClass(); String raceName = denoteEvent.getRaceName(); - CourseBase courseBase = new LastPublishedCourseDesignFinder(raceLog).analyze(); + CourseBase courseBase = new LastPublishedCourseDesignFinder(raceLog, /* onlyCoursesWithValidWaypointList */ true).analyze(); if (courseBase == null) { courseBase = new CourseDataImpl("Default course for " + raceName); logger.log(Level.FINE, "Using empty course in creation of race " + raceName); 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 d11b48e86cc..97368304af2 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 @@ -47,6 +47,7 @@ import com.sap.sailing.domain.base.Regatta; import com.sap.sailing.domain.base.SharedDomainFactory; import com.sap.sailing.domain.base.Waypoint; import com.sap.sailing.domain.base.impl.CourseDataImpl; +import com.sap.sailing.domain.common.CourseDesignerMode; import com.sap.sailing.domain.common.RegattaIdentifier; import com.sap.sailing.domain.common.abstractlog.NotRevokableException; import com.sap.sailing.domain.common.racelog.tracking.CompetitorRegistrationOnRaceLogDisabledException; @@ -194,7 +195,7 @@ public class RaceLogTrackingAdapterImpl implements RaceLogTrackingAdapter { @Override public void copyCourse(RaceLog fromRaceLog, Set toRaceLogs, SharedDomainFactory baseDomainFactory, RacingEventService service) { - CourseBase course = new LastPublishedCourseDesignFinder(fromRaceLog).analyze(); + CourseBase course = new LastPublishedCourseDesignFinder(fromRaceLog, /* onlyCoursesWithValidWaypointList */ true).analyze(); final Set marks = new HashSet<>(); if (course != null) { course.getWaypoints().forEach(wp -> Util.addAll(wp.getMarks(), marks)); @@ -212,7 +213,7 @@ public class RaceLogTrackingAdapterImpl implements RaceLogTrackingAdapter { int passId = toRaceLog.getCurrentPassId(); RaceLogEvent newCourseEvent = new RaceLogCourseDesignChangedEventImpl(now, - service.getServerAuthor(), passId, newCourse); + service.getServerAuthor(), passId, newCourse, CourseDesignerMode.ADMIN_CONSOLE); toRaceLog.add(newCourseEvent); } diff --git a/java/com.sap.sailing.domain.shared.android.test/src/com/sap/sailing/domain/racelog/state/test/RaceStateTest.java b/java/com.sap.sailing.domain.shared.android.test/src/com/sap/sailing/domain/racelog/state/test/RaceStateTest.java index 6d53331d754..a1d5062a69a 100644 --- a/java/com.sap.sailing.domain.shared.android.test/src/com/sap/sailing/domain/racelog/state/test/RaceStateTest.java +++ b/java/com.sap.sailing.domain.shared.android.test/src/com/sap/sailing/domain/racelog/state/test/RaceStateTest.java @@ -37,6 +37,7 @@ import com.sap.sailing.domain.base.configuration.RegattaConfiguration; import com.sap.sailing.domain.base.configuration.impl.EmptyRegattaConfiguration; import com.sap.sailing.domain.base.configuration.impl.RegattaConfigurationImpl; import com.sap.sailing.domain.base.configuration.procedures.ESSConfiguration; +import com.sap.sailing.domain.common.CourseDesignerMode; import com.sap.sailing.domain.common.racelog.Flags; import com.sap.sailing.domain.common.racelog.RaceLogRaceStatus; import com.sap.sailing.domain.common.racelog.RacingProcedureType; @@ -177,7 +178,7 @@ public class RaceStateTest { state.forceNewStartTime(nowMock, new MillisecondsTimePoint(1)); Thread.sleep(100); state.setFinishedTime(new MillisecondsTimePoint(10)); - state.setCourseDesign(nowMock, mock(CourseBase.class)); + state.setCourseDesign(nowMock, mock(CourseBase.class), CourseDesignerMode.ADMIN_CONSOLE); state.setAdvancePass(mock(TimePoint.class)); diff --git a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/race/RaceLogCourseDesignChangedEvent.java b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/race/RaceLogCourseDesignChangedEvent.java index 97592723862..c63555fba5d 100644 --- a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/race/RaceLogCourseDesignChangedEvent.java +++ b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/race/RaceLogCourseDesignChangedEvent.java @@ -1,9 +1,12 @@ package com.sap.sailing.domain.abstractlog.race; import com.sap.sailing.domain.base.CourseBase; +import com.sap.sailing.domain.common.CourseDesignerMode; public interface RaceLogCourseDesignChangedEvent extends RaceLogEvent { CourseBase getCourseDesign(); + + CourseDesignerMode getCourseDesignerMode(); } diff --git a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/race/analyzing/impl/LastPublishedCourseDesignFinder.java b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/race/analyzing/impl/LastPublishedCourseDesignFinder.java index d5101afd45d..6f7e08bd104 100644 --- a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/race/analyzing/impl/LastPublishedCourseDesignFinder.java +++ b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/race/analyzing/impl/LastPublishedCourseDesignFinder.java @@ -4,11 +4,33 @@ import com.sap.sailing.domain.abstractlog.race.RaceLog; import com.sap.sailing.domain.abstractlog.race.RaceLogCourseDesignChangedEvent; import com.sap.sailing.domain.abstractlog.race.RaceLogEvent; import com.sap.sailing.domain.base.CourseBase; +import com.sap.sailing.domain.common.CourseDesignerMode; +/** + * A course design can be defined in the {@link RaceLog} using a {@link RaceLogCourseDesignChangedEvent}. These + * events may carry information about the course designer that was used to create the course. Not all of them + * support defining the waypoint sequence that sets the course. See {@link RaceLogCourseDesignChangedEvent#getCourseDesignerMode()} + * and {@link CourseDesignerMode#isWaypointSequenceValid()}. Callers can tell whether they want to obtain {@link CourseBase} + * objects regardless of whether their waypoint sequence is valid or not. + * + * @author Axel Uhl (d043530) + * + */ public class LastPublishedCourseDesignFinder extends RaceLogAnalyzer { - public LastPublishedCourseDesignFinder(RaceLog raceLog) { + private final boolean onlyCoursesWithValidWaypointList; + + /** + * @param onlyCoursesWithValidWaypointList + * if {@code true}, only {@link RaceLogCourseDesignChangedEvent} objects will be considered whose + * {@link RaceLogCourseDesignChangedEvent#getCourseDesignerMode() course designer mode} + * {@link CourseDesignerMode#isWaypointSequenceValid() guarantees} that the waypoint list is valid and + * shall be applied to a race; otherwise, all other {@link RaceLogCourseDesignChangedEvent} as considered + * as well. + */ + public LastPublishedCourseDesignFinder(RaceLog raceLog, boolean onlyCoursesWithValidWaypointList) { super(raceLog); + this.onlyCoursesWithValidWaypointList = onlyCoursesWithValidWaypointList; } @Override @@ -16,7 +38,10 @@ public class LastPublishedCourseDesignFinder extends RaceLogAnalyzer for (RaceLogEvent event : getAllEventsDescending()) { if (event instanceof RaceLogCourseDesignChangedEvent) { RaceLogCourseDesignChangedEvent courseDesignEvent = (RaceLogCourseDesignChangedEvent) event; - return courseDesignEvent.getCourseDesign(); + if (!onlyCoursesWithValidWaypointList || (courseDesignEvent.getCourseDesignerMode() == null || + courseDesignEvent.getCourseDesignerMode().isWaypointSequenceValid())) { + return courseDesignEvent.getCourseDesign(); + } } } return null; diff --git a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/race/impl/RaceLogCourseDesignChangedEventImpl.java b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/race/impl/RaceLogCourseDesignChangedEventImpl.java index c295cf8d891..11900dd831d 100644 --- a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/race/impl/RaceLogCourseDesignChangedEventImpl.java +++ b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/race/impl/RaceLogCourseDesignChangedEventImpl.java @@ -6,23 +6,27 @@ import com.sap.sailing.domain.abstractlog.AbstractLogEventAuthor; import com.sap.sailing.domain.abstractlog.race.RaceLogCourseDesignChangedEvent; import com.sap.sailing.domain.abstractlog.race.RaceLogEventVisitor; import com.sap.sailing.domain.base.CourseBase; +import com.sap.sailing.domain.common.CourseDesignerMode; import com.sap.sse.common.TimePoint; public class RaceLogCourseDesignChangedEventImpl extends RaceLogEventImpl implements RaceLogCourseDesignChangedEvent { private static final long serialVersionUID = 1565936170747420547L; private final CourseBase courseDesign; + + private final CourseDesignerMode courseDesignerMode; public RaceLogCourseDesignChangedEventImpl(TimePoint createdAt, TimePoint pTimePoint, AbstractLogEventAuthor author, Serializable pId, int pPassId, - CourseBase courseDesign) { + CourseBase courseDesign, CourseDesignerMode courseDesignerMode) { super(createdAt, pTimePoint, author, pId, pPassId); this.courseDesign = courseDesign; + this.courseDesignerMode = courseDesignerMode; } public RaceLogCourseDesignChangedEventImpl(TimePoint logicalTimePoint, AbstractLogEventAuthor author, int pPassId, - CourseBase courseDesign) { - this(now(), logicalTimePoint, author, randId(), pPassId, courseDesign); + CourseBase courseDesign, CourseDesignerMode courseDesignerMode) { + this(now(), logicalTimePoint, author, randId(), pPassId, courseDesign, courseDesignerMode); } @Override @@ -35,8 +39,14 @@ public class RaceLogCourseDesignChangedEventImpl extends RaceLogEventImpl implem return courseDesign; } + @Override + public CourseDesignerMode getCourseDesignerMode() { + return courseDesignerMode; + } + @Override public String getShortInfo() { return "courseDesign=" + courseDesign != null ? courseDesign.getName() : "null"; } -} + +} \ No newline at end of file diff --git a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/race/impl/WeakRaceLogChangedVisitor.java b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/race/impl/WeakRaceLogChangedVisitor.java index a056688314a..7940e5f8979 100755 --- a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/race/impl/WeakRaceLogChangedVisitor.java +++ b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/race/impl/WeakRaceLogChangedVisitor.java @@ -27,7 +27,7 @@ public class WeakRaceLogChangedVisitor extends AbstractRaceLogChangedVisitor { private static ReferenceQueue queue = new ReferenceQueue(); private static Map, WeakRaceLogChangedVisitor> referenceToVisitor = new ConcurrentHashMap, WeakRaceLogChangedVisitor>(); static { - new Thread(WeakRaceLogChangedVisitor.class.getSimpleName() + " weak reference cleaner") { + Thread t = new Thread(WeakRaceLogChangedVisitor.class.getSimpleName() + " weak reference cleaner") { @Override public void run() { while (true) { @@ -42,7 +42,9 @@ public class WeakRaceLogChangedVisitor extends AbstractRaceLogChangedVisitor { } } } - }.start(); + }; + t.setDaemon(true); + t.start(); } private final WeakReference listenerRef; diff --git a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/race/state/RaceState.java b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/race/state/RaceState.java index 38c0cfd5e67..0b35b4d0b6f 100644 --- a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/race/state/RaceState.java +++ b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/race/state/RaceState.java @@ -13,6 +13,7 @@ import com.sap.sailing.domain.abstractlog.race.state.racingprocedure.RacingProce import com.sap.sailing.domain.abstractlog.race.state.racingprocedure.RacingProcedurePrerequisite.Resolver; import com.sap.sailing.domain.abstractlog.race.state.racingprocedure.impl.RacingProcedurePrerequisiteAutoResolver; import com.sap.sailing.domain.base.CourseBase; +import com.sap.sailing.domain.common.CourseDesignerMode; import com.sap.sailing.domain.common.Wind; import com.sap.sailing.domain.common.racelog.Flags; import com.sap.sailing.domain.common.racelog.RacingProcedureType; @@ -172,8 +173,14 @@ public interface RaceState extends ReadonlyRaceState { /** * Sets a new active course design. + * + * @param courseDesignerMode + * the type of course designer through which the course was created; this decides about whether the + * waypoint specification will be considered at all. For example, the "By Marks" course designer does not + * produce a valid waypoints list which therefore must be ignored instead of using it to update a + * TrackedRace's course. */ - void setCourseDesign(TimePoint now, CourseBase courseDesign); + void setCourseDesign(TimePoint now, CourseBase courseDesign, CourseDesignerMode courseDesignerMode); /** * Enters a new wind fix for this race. diff --git a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/race/state/impl/RaceStateImpl.java b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/race/state/impl/RaceStateImpl.java index 96ec8bb31cb..0200a3480d5 100644 --- a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/race/state/impl/RaceStateImpl.java +++ b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/race/state/impl/RaceStateImpl.java @@ -37,6 +37,7 @@ import com.sap.sailing.domain.base.CourseBase; import com.sap.sailing.domain.base.configuration.ConfigurationLoader; import com.sap.sailing.domain.base.configuration.RegattaConfiguration; import com.sap.sailing.domain.base.configuration.impl.EmptyRegattaConfiguration; +import com.sap.sailing.domain.common.CourseDesignerMode; import com.sap.sailing.domain.common.Wind; import com.sap.sailing.domain.common.abstractlog.NotRevokableException; import com.sap.sailing.domain.common.racelog.Flags; @@ -201,8 +202,8 @@ public class RaceStateImpl extends ReadonlyRaceStateImpl implements RaceState { } @Override - public void setCourseDesign(TimePoint timePoint, CourseBase courseDesign) { - raceLog.add(new RaceLogCourseDesignChangedEventImpl(timePoint, author, raceLog.getCurrentPassId(), courseDesign)); + public void setCourseDesign(TimePoint timePoint, CourseBase courseDesign, CourseDesignerMode courseDesignerMode) { + raceLog.add(new RaceLogCourseDesignChangedEventImpl(timePoint, author, raceLog.getCurrentPassId(), courseDesign, courseDesignerMode)); } @Override diff --git a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/race/state/impl/ReadonlyRaceStateImpl.java b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/race/state/impl/ReadonlyRaceStateImpl.java index ee24b42e606..73dd9f713bb 100644 --- a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/race/state/impl/ReadonlyRaceStateImpl.java +++ b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/race/state/impl/ReadonlyRaceStateImpl.java @@ -186,7 +186,7 @@ public class ReadonlyRaceStateImpl implements ReadonlyRaceState, RaceLogChangedL this.protestTimeAnalyzer = new ProtestStartTimeFinder(raceLog); this.finishPositioningListAnalyzer = new FinishPositioningListFinder(raceLog); this.confirmedFinishPositioningListAnalyzer = new ConfirmedFinishPositioningListFinder(raceLog); - this.courseDesignerAnalyzer = new LastPublishedCourseDesignFinder(raceLog); + this.courseDesignerAnalyzer = new LastPublishedCourseDesignFinder(raceLog, /* onlyCoursesWithValidWaypointList */ false); this.lastWindFixAnalyzer = new LastWindFixFinder(raceLog); this.raceStateToObserveListener = new BaseRaceStateChangedListener() { 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 698922f3a08..3f5174a7f4d 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 @@ -339,7 +339,7 @@ public abstract class AbstractRaceColumn extends SimpleAbstractRaceColumn implem } } else { // if no tracked race is found, use marks from race course if present in racelog - LastPublishedCourseDesignFinder courseDesginFinder = new LastPublishedCourseDesignFinder(getRaceLog(fleet)); + LastPublishedCourseDesignFinder courseDesginFinder = new LastPublishedCourseDesignFinder(getRaceLog(fleet), /* onlyCoursesWithValidWaypointList */ true); final CourseBase courseBase = courseDesginFinder.analyze(); if (courseBase != null) { courseBase.getWaypoints().forEach((waypoint) -> Util.addAll(waypoint.getMarks(), result)); diff --git a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/leaderboard/caching/LiveLeaderboardUpdater.java b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/leaderboard/caching/LiveLeaderboardUpdater.java index 5f2db95e2d0..fca7707a2f4 100755 --- a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/leaderboard/caching/LiveLeaderboardUpdater.java +++ b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/leaderboard/caching/LiveLeaderboardUpdater.java @@ -221,6 +221,7 @@ public class LiveLeaderboardUpdater implements Runnable { private synchronized void start() { running = true; thread = new Thread(this, "LiveLeaderboardUpdater for leaderboard "+getLeaderboard().getName()); + thread.setDaemon(true); thread.start(); } 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 cc546138856..1886af12f0d 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 @@ -75,7 +75,7 @@ public class DynamicTrackedRaceLogListener extends BaseRaceLogEventVisitor { } private LastPublishedCourseDesignFinder createCourseDesignFinder(RaceLog raceLog) { - return new LastPublishedCourseDesignFinder(raceLog); + return new LastPublishedCourseDesignFinder(raceLog, /* onlyCoursesWithValidWaypointList */ false); // we also want by-name courses to forward, e.g., to TracTrac } private AbortingFlagFinder createAbortingFlagFinder(RaceLog raceLog) { 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 610f4305165..6cbd5d97fb3 100644 --- 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 @@ -144,6 +144,7 @@ import com.sap.sailing.domain.base.impl.SailingServerConfigurationImpl; import com.sap.sailing.domain.base.impl.SeriesImpl; import com.sap.sailing.domain.base.impl.TeamImpl; import com.sap.sailing.domain.common.Bearing; +import com.sap.sailing.domain.common.CourseDesignerMode; import com.sap.sailing.domain.common.DataImportProgress; import com.sap.sailing.domain.common.DetailType; import com.sap.sailing.domain.common.Distance; @@ -5229,10 +5230,10 @@ public class SailingServiceImpl extends ProxiedRemoteServiceServlet implements S List> courseDTO) throws NotFoundException { RaceLog raceLog = getRaceLog(leaderboardName, raceColumnName, fleetName); String courseName = "Course of " + raceColumnName; - if(!LeaderboardNameConstants.DEFAULT_FLEET_NAME.equals(fleetName)) { - courseName += "- " + fleetName; + if (!LeaderboardNameConstants.DEFAULT_FLEET_NAME.equals(fleetName)) { + courseName += " - " + fleetName; } - CourseBase lastPublishedCourse = new LastPublishedCourseDesignFinder(raceLog).analyze(); + CourseBase lastPublishedCourse = new LastPublishedCourseDesignFinder(raceLog, /* onlyCoursesWithValidWaypointList */ false).analyze(); if (lastPublishedCourse == null) { lastPublishedCourse = new CourseDataImpl(courseName); } @@ -5250,7 +5251,7 @@ public class SailingServiceImpl extends ProxiedRemoteServiceServlet implements S } RaceLogEvent event = new RaceLogCourseDesignChangedEventImpl(MillisecondsTimePoint.now(), - getService().getServerAuthor(), raceLog.getCurrentPassId(), course); + getService().getServerAuthor(), raceLog.getCurrentPassId(), course, CourseDesignerMode.ADMIN_CONSOLE); raceLog.add(event); } @@ -5299,7 +5300,8 @@ public class SailingServiceImpl extends ProxiedRemoteServiceServlet implements S @Override 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(); + // only look for course definitions that really define waypoints; ignore by-name course updates + CourseBase lastPublishedCourse = new LastPublishedCourseDesignFinder(raceLog, /* onlyCoursesWithValidWaypointList */ true).analyze(); if (lastPublishedCourse == null) { lastPublishedCourse = new CourseDataImpl(""); } @@ -6056,7 +6058,7 @@ public class SailingServiceImpl extends ProxiedRemoteServiceServlet implements S for (Fleet fleet : raceColumn.getFleets()) { RaceLog raceLog = raceColumn.getRaceLog(fleet); if (raceLog != raceLogToIgnore) { - LastPublishedCourseDesignFinder finder = new LastPublishedCourseDesignFinder(raceLog); + LastPublishedCourseDesignFinder finder = new LastPublishedCourseDesignFinder(raceLog, /* onlyCoursesWithValidWaypointList */ true); CourseBase course = finder.analyze(); if (course != null) { for (Waypoint waypoint : course.getWaypoints()) { 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 8bd6033f7e4..519b83672b6 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 @@ -62,6 +62,7 @@ import com.sap.sailing.domain.base.CourseBase; 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.common.CourseDesignerMode; import com.sap.sailing.domain.common.MaxPointsReason; import com.sap.sailing.domain.common.Wind; import com.sap.sailing.domain.common.racelog.Flags; @@ -514,7 +515,7 @@ public class TestStoringAndRetrievingRaceLogInLeaderboards extends RaceLogMongoD @Test public void testStoreAndRetrieveSimpleLeaderboardWithRaceLogCourseDesignChangedEvent() { CourseBase course = createCourseBase(); - RaceLogCourseDesignChangedEvent event = new RaceLogCourseDesignChangedEventImpl(now, author, 0, course); + RaceLogCourseDesignChangedEvent event = new RaceLogCourseDesignChangedEventImpl(now, author, 0, course, CourseDesignerMode.ADMIN_CONSOLE); addAndStoreRaceLogEvent(leaderboard, raceColumnName, event); 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 796528a1c40..8d7d476a755 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 @@ -53,6 +53,7 @@ import com.sap.sailing.domain.base.RaceColumn; import com.sap.sailing.domain.base.Regatta; import com.sap.sailing.domain.base.Series; import com.sap.sailing.domain.base.impl.FleetImpl; +import com.sap.sailing.domain.common.CourseDesignerMode; import com.sap.sailing.domain.common.MaxPointsReason; import com.sap.sailing.domain.common.Wind; import com.sap.sailing.domain.common.racelog.Flags; @@ -387,7 +388,7 @@ public class TestStoringAndRetrievingRaceLogInRegatta extends AbstractTestStorin @Test public void testStoreAndRetrieveRegattaWithRaceLogCourseDesignChangedEvent() { CourseBase course = createCourseBase(); - RaceLogCourseDesignChangedEvent event = new RaceLogCourseDesignChangedEventImpl(now, author, 0, course); + RaceLogCourseDesignChangedEvent event = new RaceLogCourseDesignChangedEventImpl(now, author, 0, course, CourseDesignerMode.ADMIN_CONSOLE); addAndStoreRaceLogEvent(regatta, raceColumnName, event); diff --git a/java/com.sap.sailing.server.gateway.serialization.shared.android/src/com/sap/sailing/server/gateway/deserialization/racelog/impl/RaceLogCourseDesignChangedEventDeserializer.java b/java/com.sap.sailing.server.gateway.serialization.shared.android/src/com/sap/sailing/server/gateway/deserialization/racelog/impl/RaceLogCourseDesignChangedEventDeserializer.java index 2f61f1af5be..49b536a7338 100644 --- a/java/com.sap.sailing.server.gateway.serialization.shared.android/src/com/sap/sailing/server/gateway/deserialization/racelog/impl/RaceLogCourseDesignChangedEventDeserializer.java +++ b/java/com.sap.sailing.server.gateway.serialization.shared.android/src/com/sap/sailing/server/gateway/deserialization/racelog/impl/RaceLogCourseDesignChangedEventDeserializer.java @@ -10,6 +10,7 @@ import com.sap.sailing.domain.abstractlog.race.RaceLogEvent; import com.sap.sailing.domain.abstractlog.race.impl.RaceLogCourseDesignChangedEventImpl; import com.sap.sailing.domain.base.Competitor; import com.sap.sailing.domain.base.CourseBase; +import com.sap.sailing.domain.common.CourseDesignerMode; import com.sap.sailing.server.gateway.deserialization.JsonDeserializationException; import com.sap.sailing.server.gateway.deserialization.JsonDeserializer; import com.sap.sailing.server.gateway.deserialization.coursedata.impl.CourseBaseDeserializer; @@ -31,8 +32,9 @@ public class RaceLogCourseDesignChangedEventDeserializer extends BaseRaceLogEven JSONObject jsonCourseDesign = (JSONObject) object.get(RaceLogCourseDesignChangedEventSerializer.FIELD_COURSE_DESIGN); CourseBase courseData = courseDataDeserializer.deserialize(jsonCourseDesign); - - return new RaceLogCourseDesignChangedEventImpl(createdAt, timePoint, author, id, passId, courseData); + final String courseDesignerModeName = (String) object.get(RaceLogCourseDesignChangedEventSerializer.FIELD_COURSE_DESIGNER_MODE); + return new RaceLogCourseDesignChangedEventImpl(createdAt, timePoint, author, id, passId, courseData, + courseDesignerModeName == null ? null : CourseDesignerMode.valueOf(courseDesignerModeName)); } } diff --git a/java/com.sap.sailing.server.gateway.serialization.shared.android/src/com/sap/sailing/server/gateway/serialization/racelog/impl/RaceLogCourseDesignChangedEventSerializer.java b/java/com.sap.sailing.server.gateway.serialization.shared.android/src/com/sap/sailing/server/gateway/serialization/racelog/impl/RaceLogCourseDesignChangedEventSerializer.java index 9b104f509c1..1c62b0ff6d3 100644 --- a/java/com.sap.sailing.server.gateway.serialization.shared.android/src/com/sap/sailing/server/gateway/serialization/racelog/impl/RaceLogCourseDesignChangedEventSerializer.java +++ b/java/com.sap.sailing.server.gateway.serialization.shared.android/src/com/sap/sailing/server/gateway/serialization/racelog/impl/RaceLogCourseDesignChangedEventSerializer.java @@ -12,6 +12,7 @@ public class RaceLogCourseDesignChangedEventSerializer extends BaseRaceLogEventS public static final String VALUE_CLASS = RaceLogCourseDesignChangedEvent.class.getSimpleName(); public static final String FIELD_COURSE_DESIGN = "courseDesign"; + public static final String FIELD_COURSE_DESIGNER_MODE = "courseDesignerMode"; private final JsonSerializer courseBaseSerializer; @@ -30,10 +31,9 @@ public class RaceLogCourseDesignChangedEventSerializer extends BaseRaceLogEventS @Override public JSONObject serialize(RaceLogEvent object) { RaceLogCourseDesignChangedEvent courseChangedEvent = (RaceLogCourseDesignChangedEvent) object; - JSONObject result = super.serialize(courseChangedEvent); result.put(FIELD_COURSE_DESIGN, courseBaseSerializer.serialize(courseChangedEvent.getCourseDesign())); - + result.put(FIELD_COURSE_DESIGNER_MODE, courseChangedEvent.getCourseDesignerMode() == null ? null : courseChangedEvent.getCourseDesignerMode().name()); return result; } diff --git a/java/com.sap.sailing.server.gateway.serialization.test/src/com/sap/sailing/server/gateway/serialization/test/racelog/RaceLogCourseDesignChangedEventSerializerTest.java b/java/com.sap.sailing.server.gateway.serialization.test/src/com/sap/sailing/server/gateway/serialization/test/racelog/RaceLogCourseDesignChangedEventSerializerTest.java index aa606905231..7a05e55e1ba 100644 --- a/java/com.sap.sailing.server.gateway.serialization.test/src/com/sap/sailing/server/gateway/serialization/test/racelog/RaceLogCourseDesignChangedEventSerializerTest.java +++ b/java/com.sap.sailing.server.gateway.serialization.test/src/com/sap/sailing/server/gateway/serialization/test/racelog/RaceLogCourseDesignChangedEventSerializerTest.java @@ -23,6 +23,7 @@ import com.sap.sailing.domain.base.impl.ControlPointWithTwoMarksImpl; import com.sap.sailing.domain.base.impl.CourseDataImpl; import com.sap.sailing.domain.base.impl.MarkImpl; import com.sap.sailing.domain.base.impl.WaypointImpl; +import com.sap.sailing.domain.common.CourseDesignerMode; import com.sap.sailing.domain.common.MarkType; import com.sap.sailing.domain.common.PassingInstruction; import com.sap.sailing.server.gateway.deserialization.JsonDeserializationException; @@ -63,7 +64,7 @@ public class RaceLogCourseDesignChangedEventSerializerTest { factory), new GateDeserializer(factory, new MarkDeserializer(factory)))))); now = MillisecondsTimePoint.now(); - event = new RaceLogCourseDesignChangedEventImpl(now, author, 0, createCourseData()); + event = new RaceLogCourseDesignChangedEventImpl(now, author, 0, createCourseData(), CourseDesignerMode.BY_MARKS); } @Test @@ -75,6 +76,7 @@ public class RaceLogCourseDesignChangedEventSerializerTest { assertEquals(event.getId(), deserializedEvent.getId()); assertEquals(event.getPassId(), deserializedEvent.getPassId()); assertEquals(event.getLogicalTimePoint(), deserializedEvent.getLogicalTimePoint()); + assertEquals(event.getCourseDesignerMode(), deserializedEvent.getCourseDesignerMode()); assertEquals(0, Util.size(event.getInvolvedBoats())); assertEquals(0, Util.size(deserializedEvent.getInvolvedBoats())); 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 ea6d4a1f70f..6ba877577eb 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 @@ -29,6 +29,7 @@ import com.sap.sailing.domain.abstractlog.race.tracking.impl.RaceLogDenoteForTra 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; +import com.sap.sailing.domain.common.CourseDesignerMode; import com.sap.sailing.domain.common.racelog.RaceLogRaceStatus; import com.sap.sailing.domain.common.racelog.RacingProcedureType; import com.sap.sailing.server.gateway.serialization.JsonSerializer; @@ -149,7 +150,7 @@ public class RaceLogEventSerializerTest { @Test public void testChoosesCourseDesignChangedSerializer() { // we use the real event type here because we do not want to re-implement the dispatching. - RaceLogEvent event = new RaceLogCourseDesignChangedEventImpl(null, author, 0, null); + RaceLogEvent event = new RaceLogCourseDesignChangedEventImpl(null, author, 0, null, CourseDesignerMode.ADMIN_CONSOLE); serializer.serialize(event); verify(courseDesignChangedEventSerializer).serialize(event); } diff --git a/java/com.sap.sailing.server.replication.test/src/com/sap/sailing/server/replication/test/RaceLogReplicationTest.java b/java/com.sap.sailing.server.replication.test/src/com/sap/sailing/server/replication/test/RaceLogReplicationTest.java index 1c639b6bf6e..a4711c69dcb 100755 --- a/java/com.sap.sailing.server.replication.test/src/com/sap/sailing/server/replication/test/RaceLogReplicationTest.java +++ b/java/com.sap.sailing.server.replication.test/src/com/sap/sailing/server/replication/test/RaceLogReplicationTest.java @@ -33,6 +33,7 @@ import com.sap.sailing.domain.base.impl.CourseDataImpl; import com.sap.sailing.domain.base.impl.MarkImpl; import com.sap.sailing.domain.base.impl.RegattaImpl; import com.sap.sailing.domain.base.impl.WaypointImpl; +import com.sap.sailing.domain.common.CourseDesignerMode; import com.sap.sailing.domain.common.MarkType; import com.sap.sailing.domain.common.PassingInstruction; import com.sap.sailing.domain.common.racelog.RaceLogRaceStatus; @@ -133,11 +134,11 @@ public class RaceLogReplicationTest extends AbstractLogReplicationTest