From 9984d4d15ad995549b509157ce2ed2798ad577d7 Mon Sep 17 00:00:00 2001 From: fmittag Date: Mon, 22 Jun 2015 11:25:39 +0200 Subject: [PATCH 01/29] fixed calculation of news timepoint in leaderboardUpdate provider --- .../LeaderboardUpdateEventNewsProvider.java | 26 ++++++++++--------- 1 file changed, 14 insertions(+), 12 deletions(-) diff --git a/java/com.sap.sailing.news/src/com/sap/sailing/news/impl/LeaderboardUpdateEventNewsProvider.java b/java/com.sap.sailing.news/src/com/sap/sailing/news/impl/LeaderboardUpdateEventNewsProvider.java index 29f972c1313..a23e0dba314 100644 --- a/java/com.sap.sailing.news/src/com/sap/sailing/news/impl/LeaderboardUpdateEventNewsProvider.java +++ b/java/com.sap.sailing.news/src/com/sap/sailing/news/impl/LeaderboardUpdateEventNewsProvider.java @@ -11,6 +11,7 @@ import com.sap.sailing.domain.base.Event; 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.SettableScoreCorrection; import com.sap.sailing.news.EventNewsItem; import com.sap.sailing.news.EventNewsProvider; import com.sap.sse.common.TimePoint; @@ -28,20 +29,21 @@ public class LeaderboardUpdateEventNewsProvider implements EventNewsProvider { Iterable leaderboardGroups = event.getLeaderboardGroups(); for(LeaderboardGroup leaderboardGroup: leaderboardGroups) { for(Leaderboard leaderboard: leaderboardGroup.getLeaderboards()) { - TimePoint timePointOfLatestModification = leaderboard.getTimePointOfLatestModification(); - if(timePointOfLatestModification == null) { - continue; - } - - String displayName = leaderboard.getDisplayName() != null ?leaderboard.getDisplayName() :leaderboard.getName(); - String boatClassName= null; - if(leaderboard instanceof RegattaLeaderboard) { - BoatClass boatClass = ((RegattaLeaderboard) leaderboard).getRegatta().getBoatClass(); - if(boatClass != null) { - boatClassName = boatClass.getDisplayName(); + SettableScoreCorrection scoreCorrection = leaderboard.getScoreCorrection(); + if(scoreCorrection != null) { + TimePoint timePointOfLatestModification = scoreCorrection.getTimePointOfLastCorrectionsValidity(); + if(timePointOfLatestModification != null) { + String displayName = leaderboard.getDisplayName() != null ?leaderboard.getDisplayName() :leaderboard.getName(); + String boatClassName= null; + if(leaderboard instanceof RegattaLeaderboard) { + BoatClass boatClass = ((RegattaLeaderboard) leaderboard).getRegatta().getBoatClass(); + if(boatClass != null) { + boatClassName = boatClass.getDisplayName(); + } + } + result.add(new LeaderboardUpdateNewsItem(event.getId(), timePointOfLatestModification.asDate(), leaderboard.getName(), displayName, boatClassName)); } } - result.add(new LeaderboardUpdateNewsItem(event.getId(), timePointOfLatestModification.asDate(), leaderboard.getName(), displayName, boatClassName)); } } From 936b1fb9cdf7c5099d37f03886a2ba76c4b342cb Mon Sep 17 00:00:00 2001 From: fmittag Date: Mon, 22 Jun 2015 11:39:51 +0200 Subject: [PATCH 02/29] change the default time to show a race in the live races list from startTime - 4 min to startTime -15 min --- .../sap/sailing/gwt/ui/shared/dispatch/event/RaceContext.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/dispatch/event/RaceContext.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/dispatch/event/RaceContext.java index be2e6608279..f14d9a8d478 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/dispatch/event/RaceContext.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/dispatch/event/RaceContext.java @@ -56,6 +56,7 @@ public class RaceContext { private final RaceLog raceLog; private final ReadonlyRaceState state; private final Event event; + private final long TIME_BEFORE_START_SHOW_RACES_AS_LIVE = 15 * 60 * 1000; // 15 min private final long TIME_TO_SHOW_CANCELED_RACES_AS_LIVE = 5 * 60 * 1000; // 5 min public RaceContext(Event event, Leaderboard leaderboard, RaceColumn raceColumn, Fleet fleet, RaceLogResolver raceLogResolver) { @@ -308,7 +309,7 @@ public class RaceContext { result = trackedRace.isLive(now); } else { // no data from tracking but maybe a manual setting of the start and finish time - TimePoint startOfLivePeriod = startTime.minus(TimingConstants.PRE_START_PHASE_DURATION_IN_MILLIS); + TimePoint startOfLivePeriod = startTime.minus(TIME_BEFORE_START_SHOW_RACES_AS_LIVE); TimePoint endOfLivePeriod = finishTime != null ? finishTime.plus(TimingConstants.IS_LIVE_GRACE_PERIOD_IN_MILLIS) : null; if(now.after(startOfLivePeriod) && (endOfLivePeriod == null || now.before(endOfLivePeriod))) { result = true; From 29952d3fc6828d4a50081442b78fafe1176b6bb0 Mon Sep 17 00:00:00 2001 From: fmittag Date: Mon, 22 Jun 2015 11:45:22 +0200 Subject: [PATCH 03/29] just renamed a constant --- .../sap/sailing/gwt/ui/shared/dispatch/event/RaceContext.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/dispatch/event/RaceContext.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/dispatch/event/RaceContext.java index f14d9a8d478..5b37c6a5957 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/dispatch/event/RaceContext.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/dispatch/event/RaceContext.java @@ -56,7 +56,7 @@ public class RaceContext { private final RaceLog raceLog; private final ReadonlyRaceState state; private final Event event; - private final long TIME_BEFORE_START_SHOW_RACES_AS_LIVE = 15 * 60 * 1000; // 15 min + private final long TIME_BEFORE_START_TO_SHOW_RACES_AS_LIVE = 15 * 60 * 1000; // 15 min private final long TIME_TO_SHOW_CANCELED_RACES_AS_LIVE = 5 * 60 * 1000; // 5 min public RaceContext(Event event, Leaderboard leaderboard, RaceColumn raceColumn, Fleet fleet, RaceLogResolver raceLogResolver) { @@ -309,7 +309,7 @@ public class RaceContext { result = trackedRace.isLive(now); } else { // no data from tracking but maybe a manual setting of the start and finish time - TimePoint startOfLivePeriod = startTime.minus(TIME_BEFORE_START_SHOW_RACES_AS_LIVE); + TimePoint startOfLivePeriod = startTime.minus(TIME_BEFORE_START_TO_SHOW_RACES_AS_LIVE); TimePoint endOfLivePeriod = finishTime != null ? finishTime.plus(TimingConstants.IS_LIVE_GRACE_PERIOD_IN_MILLIS) : null; if(now.after(startOfLivePeriod) && (endOfLivePeriod == null || now.before(endOfLivePeriod))) { result = true; From 405f8c4bf99a70604831525d6076f0312d1bf607 Mon Sep 17 00:00:00 2001 From: Axel Uhl Date: Mon, 22 Jun 2015 14:16:21 +0200 Subject: [PATCH 04/29] fix for bug 2992: mark all leaderboard groups transitively across all events that will be touched by master data serialization as currently under export --- .../masterdataimport/TopLevelMasterData.java | 10 ++- ...ingServer (No Proxy, Jetty on 8889).launch | 64 +++++++++---------- 2 files changed, 41 insertions(+), 33 deletions(-) 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 768b39cc6f3..89690f2690c 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 @@ -41,6 +41,7 @@ import com.sap.sailing.domain.tracking.TrackedRace; import com.sap.sailing.domain.tracking.impl.DynamicGPSFixMovingTrackImpl; import com.sap.sailing.domain.tracking.impl.DynamicGPSFixTrackImpl; import com.sap.sse.common.NoCorrespondingServiceRegisteredException; +import com.sap.sse.common.Util; import com.sap.sse.common.WithID; import com.sap.sse.common.impl.TimeRangeImpl; @@ -255,7 +256,14 @@ public class TopLevelMasterData implements Serializable { } public void setMasterDataExportFlagOnRaceColumns(boolean flagValue) { - for (LeaderboardGroup group : leaderboardGroups) { + // collect all leaderboard groups for all events that will be touched during serialization + final Set allLeaderboardGroups = new HashSet<>(); + for (Entry> i : eventForLeaderboardGroup.entrySet()) { + for (Event e : i.getValue()) { + Util.addAll(e.getLeaderboardGroups(), allLeaderboardGroups); + } + } + for (LeaderboardGroup group : allLeaderboardGroups) { for (Leaderboard leaderboard : group.getLeaderboards()) { for (RaceColumn raceColumn : leaderboard.getRaceColumns()) { raceColumn.setMasterDataExportOngoingThreadFlag(true); diff --git a/java/com.sap.sailing.server/SailingServer (No Proxy, Jetty on 8889).launch b/java/com.sap.sailing.server/SailingServer (No Proxy, Jetty on 8889).launch index 7bdb8892027..d377b79164e 100755 --- a/java/com.sap.sailing.server/SailingServer (No Proxy, Jetty on 8889).launch +++ b/java/com.sap.sailing.server/SailingServer (No Proxy, Jetty on 8889).launch @@ -1,32 +1,32 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + From e2831de2e1463c9d59b2a2318d42e3b594f3b1b4 Mon Sep 17 00:00:00 2001 From: Axel Uhl Date: Mon, 22 Jun 2015 14:50:02 +0200 Subject: [PATCH 05/29] added a failing test case for bug 2995 and prepared a solution by introducing SerializableFunction --- .../test/SerializeRankingMetricTest.java | 22 +++++++++++++++++++ ...OnDistanceAllowancePerNauticalMileMap.java | 9 ++++++++ .../ranking/TimeOnTimeFactorMapping.java | 7 ++++++ .../SailingGWT sdm.launch | 6 +++-- .../sap/sse/util/SerializableFunction.java | 8 +++++++ 5 files changed, 50 insertions(+), 2 deletions(-) create mode 100644 java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/SerializeRankingMetricTest.java create mode 100755 java/com.sap.sailing.domain/src/com/sap/sailing/domain/ranking/TimeOnDistanceAllowancePerNauticalMileMap.java create mode 100755 java/com.sap.sailing.domain/src/com/sap/sailing/domain/ranking/TimeOnTimeFactorMapping.java create mode 100644 java/com.sap.sse/src/com/sap/sse/util/SerializableFunction.java diff --git a/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/SerializeRankingMetricTest.java b/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/SerializeRankingMetricTest.java new file mode 100644 index 00000000000..653b4a4badd --- /dev/null +++ b/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/SerializeRankingMetricTest.java @@ -0,0 +1,22 @@ +package com.sap.sailing.domain.test; + +import static org.junit.Assert.assertNotNull; +import static org.mockito.Mockito.mock; + +import java.io.IOException; + +import org.junit.Test; + +import com.sap.sailing.domain.base.DomainFactory; +import com.sap.sailing.domain.ranking.TimeOnTimeAndDistanceRankingMetric; +import com.sap.sailing.domain.tracking.TrackedRace; + +public class SerializeRankingMetricTest extends AbstractSerializationTest { + @Test + public void testTimeOnTimeAndDistanceRankingMetricSerialization() throws ClassNotFoundException, IOException { + final TrackedRace trackedRace = mock(TrackedRace.class); + final TimeOnTimeAndDistanceRankingMetric rankingMetric = new TimeOnTimeAndDistanceRankingMetric(trackedRace); + TimeOnTimeAndDistanceRankingMetric clone = cloneBySerialization(rankingMetric, DomainFactory.INSTANCE); + assertNotNull(clone); + } +} diff --git a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/ranking/TimeOnDistanceAllowancePerNauticalMileMap.java b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/ranking/TimeOnDistanceAllowancePerNauticalMileMap.java new file mode 100755 index 00000000000..a5c2cd45e51 --- /dev/null +++ b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/ranking/TimeOnDistanceAllowancePerNauticalMileMap.java @@ -0,0 +1,9 @@ +package com.sap.sailing.domain.ranking; + +import com.sap.sailing.domain.base.Competitor; +import com.sap.sse.common.Duration; +import com.sap.sse.util.SerializableFunction; + +public interface TimeOnDistanceAllowancePerNauticalMileMap extends SerializableFunction { + +} diff --git a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/ranking/TimeOnTimeFactorMapping.java b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/ranking/TimeOnTimeFactorMapping.java new file mode 100755 index 00000000000..2843b8a4266 --- /dev/null +++ b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/ranking/TimeOnTimeFactorMapping.java @@ -0,0 +1,7 @@ +package com.sap.sailing.domain.ranking; + +import com.sap.sailing.domain.base.Competitor; +import com.sap.sse.util.SerializableFunction; + +public interface TimeOnTimeFactorMapping extends SerializableFunction { +} diff --git a/java/com.sap.sailing.gwt.ui/SailingGWT sdm.launch b/java/com.sap.sailing.gwt.ui/SailingGWT sdm.launch index 7435c9ab64d..a00d6c0ff91 100755 --- a/java/com.sap.sailing.gwt.ui/SailingGWT sdm.launch +++ b/java/com.sap.sailing.gwt.ui/SailingGWT sdm.launch @@ -16,9 +16,11 @@ - + + + @@ -71,7 +73,7 @@ - + diff --git a/java/com.sap.sse/src/com/sap/sse/util/SerializableFunction.java b/java/com.sap.sse/src/com/sap/sse/util/SerializableFunction.java new file mode 100644 index 00000000000..82f66820ef1 --- /dev/null +++ b/java/com.sap.sse/src/com/sap/sse/util/SerializableFunction.java @@ -0,0 +1,8 @@ +package com.sap.sse.util; + +import java.io.Serializable; +import java.util.function.Function; + +public interface SerializableFunction extends Function, Serializable { + +} From 9cd1ab891952c16b43dff0ffa6245d7b5117b6df Mon Sep 17 00:00:00 2001 From: Axel Uhl Date: Mon, 22 Jun 2015 14:59:10 +0200 Subject: [PATCH 06/29] fix for bug 2995: require handicap functions to be serializable --- .../TestSimpleTimeOnTimeRankingWithOneUpwindLeg.java | 4 ++-- .../TimeOnDistanceAllowancePerNauticalMileMap.java | 2 +- .../ranking/TimeOnTimeAndDistanceRankingMetric.java | 9 ++++----- .../sailing/domain/ranking/TimeOnTimeFactorMapping.java | 1 + 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/ranking/TestSimpleTimeOnTimeRankingWithOneUpwindLeg.java b/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/ranking/TestSimpleTimeOnTimeRankingWithOneUpwindLeg.java index c4f9d04ccf2..cad3f60bd5b 100755 --- a/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/ranking/TestSimpleTimeOnTimeRankingWithOneUpwindLeg.java +++ b/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/ranking/TestSimpleTimeOnTimeRankingWithOneUpwindLeg.java @@ -61,7 +61,7 @@ public class TestSimpleTimeOnTimeRankingWithOneUpwindLeg { private DynamicTrackedRace trackedRace; private Competitor c1, c2; - private void setUp(Function timeOnTimeFactors, Function timeOnDistanceFactors) { + private void setUp(TimeOnTimeFactorMapping timeOnTimeFactors, Function timeOnDistanceFactors) { c1 = TrackBasedTest.createCompetitor("FastBoat"); c2 = TrackBasedTest.createCompetitor("SlowBoat"); trackedRace = createTrackedRace(Arrays.asList(c1, c2), timeOnTimeFactors, timeOnDistanceFactors); @@ -70,7 +70,7 @@ public class TestSimpleTimeOnTimeRankingWithOneUpwindLeg { assertSame(RankingMetrics.TIME_ON_TIME_AND_DISTANCE, trackedRace.getTrackedRegatta().getRegatta().getRankingMetricType()); } - private DynamicTrackedRace createTrackedRace(Iterable competitors, Function timeOnTimeFactors, Function timeOnDistanceFactors) { + private DynamicTrackedRace createTrackedRace(Iterable competitors, TimeOnTimeFactorMapping timeOnTimeFactors, Function timeOnDistanceFactors) { final TimePoint timePointForFixes = MillisecondsTimePoint.now(); BoatClassImpl boatClass = new BoatClassImpl("Some Handicap Boat Class", /* typicallyStartsUpwind */ true); Regatta regatta = new RegattaImpl(EmptyRaceLogStore.INSTANCE, EmptyRegattaLogStore.INSTANCE, diff --git a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/ranking/TimeOnDistanceAllowancePerNauticalMileMap.java b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/ranking/TimeOnDistanceAllowancePerNauticalMileMap.java index a5c2cd45e51..29b2638bd96 100755 --- a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/ranking/TimeOnDistanceAllowancePerNauticalMileMap.java +++ b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/ranking/TimeOnDistanceAllowancePerNauticalMileMap.java @@ -4,6 +4,6 @@ import com.sap.sailing.domain.base.Competitor; import com.sap.sse.common.Duration; import com.sap.sse.util.SerializableFunction; +@FunctionalInterface public interface TimeOnDistanceAllowancePerNauticalMileMap extends SerializableFunction { - } diff --git a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/ranking/TimeOnTimeAndDistanceRankingMetric.java b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/ranking/TimeOnTimeAndDistanceRankingMetric.java index 7b7821f117c..bd69a00b69f 100755 --- a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/ranking/TimeOnTimeAndDistanceRankingMetric.java +++ b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/ranking/TimeOnTimeAndDistanceRankingMetric.java @@ -3,7 +3,6 @@ package com.sap.sailing.domain.ranking; import java.util.Comparator; import java.util.HashMap; import java.util.Map; -import java.util.function.Function; import java.util.function.Supplier; import com.sap.sailing.domain.base.Competitor; @@ -52,9 +51,9 @@ public class TimeOnTimeAndDistanceRankingMetric extends AbstractRankingMetric { public final static RankingMetricConstructor CONSTRUCTOR = TimeOnTimeAndDistanceRankingMetric::new; - private final Function timeOnTimeFactor; + private final TimeOnTimeFactorMapping timeOnTimeFactor; - private final Function timeOnDistanceFactorNauticalMile; + private final TimeOnDistanceAllowancePerNauticalMileMap timeOnDistanceFactorNauticalMile; /** * The regular constructor that can also be used as TimeOnTimeAndDistanceRankingMetric::new @@ -72,8 +71,8 @@ public class TimeOnTimeAndDistanceRankingMetric extends AbstractRankingMetric { * its regatta, handicap mappings can be passed directly and overrule anything defined for the competitor or * on the regatta. */ - public TimeOnTimeAndDistanceRankingMetric(final TrackedRace trackedRace, Function timeOnTimeFactor, - Function timeOnDistanceFactorInSecondsPerNauticalMile) { + public TimeOnTimeAndDistanceRankingMetric(final TrackedRace trackedRace, TimeOnTimeFactorMapping timeOnTimeFactor, + TimeOnDistanceAllowancePerNauticalMileMap timeOnDistanceFactorInSecondsPerNauticalMile) { super(trackedRace); this.timeOnTimeFactor = timeOnTimeFactor; this.timeOnDistanceFactorNauticalMile = timeOnDistanceFactorInSecondsPerNauticalMile; diff --git a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/ranking/TimeOnTimeFactorMapping.java b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/ranking/TimeOnTimeFactorMapping.java index 2843b8a4266..56d178ea157 100755 --- a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/ranking/TimeOnTimeFactorMapping.java +++ b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/ranking/TimeOnTimeFactorMapping.java @@ -3,5 +3,6 @@ package com.sap.sailing.domain.ranking; import com.sap.sailing.domain.base.Competitor; import com.sap.sse.util.SerializableFunction; +@FunctionalInterface public interface TimeOnTimeFactorMapping extends SerializableFunction { } From 37f6f16dc90335d377d6f5ff471cf52836704366 Mon Sep 17 00:00:00 2001 From: Axel Uhl Date: Mon, 22 Jun 2015 15:49:08 +0200 Subject: [PATCH 07/29] trying to solve bug 2996 by first serializing all regattas, similar to how it's done for master data import --- .../server/impl/RacingEventServiceImpl.java | 28 +++++++++---------- 1 file changed, 14 insertions(+), 14 deletions(-) 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 6f8ea7c8fda..59a5e25ee66 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 @@ -2374,13 +2374,6 @@ public class RacingEventServiceImpl implements RacingEventService, ClearStateTes public void serializeForInitialReplicationInternal(ObjectOutputStream oos) throws IOException { StringBuffer logoutput = new StringBuffer(); - logger.info("Serializing events..."); - oos.writeObject(eventsById); - logoutput.append("\nSerialized " + eventsById.size() + " events\n"); - for (Event event : eventsById.values()) { - logoutput.append(String.format("%3s\n", event.toString())); - } - logger.info("Serializing regattas..."); oos.writeObject(regattasByName); logoutput.append("Serialized " + regattasByName.size() + " regattas\n"); @@ -2388,6 +2381,13 @@ public class RacingEventServiceImpl implements RacingEventService, ClearStateTes logoutput.append(String.format("%3s\n", regatta.toString())); } + logger.info("Serializing events..."); + oos.writeObject(eventsById); + logoutput.append("\nSerialized " + eventsById.size() + " events\n"); + for (Event event : eventsById.values()) { + logoutput.append(String.format("%3s\n", event.toString())); + } + logger.info("Serializing regattas observed..."); oos.writeObject(regattasObservedForDefaultLeaderboard); logger.info("Serializing regatta tracking cache..."); @@ -2441,13 +2441,6 @@ public class RacingEventServiceImpl implements RacingEventService, ClearStateTes // de-serialization; this will cause all classes to be visible that this bundle // (com.sap.sailing.server) can see StringBuffer logoutput = new StringBuffer(); - logger.info("Reading all events..."); - eventsById.putAll((Map) ois.readObject()); - logoutput.append("\nReceived " + eventsById.size() + " NEW events\n"); - for (Event event : eventsById.values()) { - logoutput.append(String.format("%3s\n", event.toString())); - } - logger.info("Reading all regattas..."); regattasByName.putAll((Map) ois.readObject()); logoutput.append("Received " + regattasByName.size() + " NEW regattas\n"); @@ -2455,6 +2448,13 @@ public class RacingEventServiceImpl implements RacingEventService, ClearStateTes logoutput.append(String.format("%3s\n", regatta.toString())); } + logger.info("Reading all events..."); + eventsById.putAll((Map) ois.readObject()); + logoutput.append("\nReceived " + eventsById.size() + " NEW events\n"); + for (Event event : eventsById.values()) { + logoutput.append(String.format("%3s\n", event.toString())); + } + // it is important that the leaderboards and tracked regattas are cleared before auto-linking to // old leaderboards takes place which then don't match the new ones logger.info("Reading all dynamic tracked regattas..."); From aa489ab35db59fa3d19ae7c526d9c757bbaebb1a Mon Sep 17 00:00:00 2001 From: Axel Uhl Date: Mon, 22 Jun 2015 16:57:49 +0200 Subject: [PATCH 08/29] eliminated the effects of prematurely merging branch bug2977 into master; watch out when trying to finally merge bug2977 as it may already be considered merged --- .../IsIndividualRecallDisplayedAnalyzer.java | 38 ++++++++++ .../impl/BaseRacingProcedure.java | 76 +++++++++---------- 2 files changed, 72 insertions(+), 42 deletions(-) create mode 100644 java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/race/analyzing/impl/IsIndividualRecallDisplayedAnalyzer.java diff --git a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/race/analyzing/impl/IsIndividualRecallDisplayedAnalyzer.java b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/race/analyzing/impl/IsIndividualRecallDisplayedAnalyzer.java new file mode 100644 index 00000000000..ef15f88cfd0 --- /dev/null +++ b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/race/analyzing/impl/IsIndividualRecallDisplayedAnalyzer.java @@ -0,0 +1,38 @@ +package com.sap.sailing.domain.abstractlog.race.analyzing.impl; + +import com.sap.sailing.domain.abstractlog.race.RaceLog; +import com.sap.sse.common.TimePoint; + +public class IsIndividualRecallDisplayedAnalyzer extends RaceLogAnalyzer { + + private final IndividualRecallFinder displayedFinder; + private final IndividualRecallFinder removedFinder; + + public IsIndividualRecallDisplayedAnalyzer(RaceLog raceLog) { + this(raceLog, null); + } + + public IsIndividualRecallDisplayedAnalyzer(RaceLog raceLog, TimePoint at) { + this(raceLog, new IndividualRecallDisplayedFinder(raceLog, at), new IndividualRecallRemovedFinder(raceLog, at), at); + } + + public IsIndividualRecallDisplayedAnalyzer(RaceLog raceLog, IndividualRecallDisplayedFinder displayedFinder, + IndividualRecallRemovedFinder removedFinder, TimePoint at) { + super(raceLog); + this.displayedFinder = displayedFinder; + this.removedFinder = removedFinder; + } + + @Override + protected Boolean performAnalysis() { + TimePoint displayedAt = displayedFinder.analyze(); + TimePoint removedAt = removedFinder.analyze(); + if (displayedAt != null) { + if (removedAt == null || displayedAt.after(removedAt)) { + return true; + } + } + return false; + } + +} diff --git a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/race/state/racingprocedure/impl/BaseRacingProcedure.java b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/race/state/racingprocedure/impl/BaseRacingProcedure.java index fc04a76fedf..8493a7bb1ac 100644 --- a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/race/state/racingprocedure/impl/BaseRacingProcedure.java +++ b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/race/state/racingprocedure/impl/BaseRacingProcedure.java @@ -15,6 +15,7 @@ import com.sap.sailing.domain.abstractlog.race.analyzing.impl.IndividualRecallDi import com.sap.sailing.domain.abstractlog.race.analyzing.impl.IndividualRecallRemovedFinder; import com.sap.sailing.domain.abstractlog.race.analyzing.impl.IsFinishedAnalyzer; import com.sap.sailing.domain.abstractlog.race.analyzing.impl.IsInFinishingPhaseAnalyzer; +import com.sap.sailing.domain.abstractlog.race.analyzing.impl.IsIndividualRecallDisplayedAnalyzer; import com.sap.sailing.domain.abstractlog.race.analyzing.impl.RaceLogResolver; import com.sap.sailing.domain.abstractlog.race.analyzing.impl.StartTimeFinder; import com.sap.sailing.domain.abstractlog.race.impl.RaceLogChangedVisitor; @@ -28,9 +29,7 @@ import com.sap.sailing.domain.abstractlog.race.state.racingprocedure.RacingProce import com.sap.sailing.domain.abstractlog.race.state.racingprocedure.RacingProcedureChangedListener; import com.sap.sailing.domain.base.configuration.RacingProcedureConfiguration; import com.sap.sailing.domain.common.racelog.Flags; -import com.sap.sse.common.Duration; import com.sap.sse.common.TimePoint; -import com.sap.sse.common.impl.MillisecondsTimePoint; /** * Base class for all your {@link RacingProcedure}s. @@ -42,10 +41,7 @@ import com.sap.sse.common.impl.MillisecondsTimePoint; public abstract class BaseRacingProcedure extends BaseRaceStateChangedListener implements RacingProcedure, RaceLogChangedListener { - /** - * The time since race start after which the X-ray flag has to go down - */ - private final static Duration individualRecallRemovalTimeout = Duration.ONE_MINUTE.times(4); + private final static long individualRecallRemovalTimeout = 4 * 60 * 1000; // minutes * seconds * milliseconds private RaceStateEventScheduler scheduler; @@ -55,35 +51,41 @@ public abstract class BaseRacingProcedure extends BaseRaceStateChangedListener i private final RacingProcedureConfiguration configuration; private final RacingProcedureChangedListeners changedListeners; + private final IsIndividualRecallDisplayedAnalyzer isRecallDisplayedAnalyzer; private final IndividualRecallDisplayedFinder recallDisplayedFinder; private final IndividualRecallRemovedFinder recallRemovedFinder; private final FinishingTimeFinder finishingTimeFinder; private final FinishedTimeFinder finishedTimeFinder; private final RaceLogEventVisitor raceLogListener; - private final StartTimeFinder startTimeFinder; private boolean cachedIsIndividualRecallDisplayed; /** * When calling me, call {@link BaseRacingProcedure#update()} afterwards! - * @param raceLogResolver TODO + * + * @param raceLogResolver + * is required for a {@link StartTimeFinder} in order to make individual recall timeouts depend on start + * time rather than the time the individual recall was issued */ public BaseRacingProcedure(RaceLog raceLog, AbstractLogEventAuthor author, RaceLogEventFactory factory, RacingProcedureConfiguration configuration, RaceLogResolver raceLogResolver) { if (configuration == null) { throw new IllegalArgumentException("configuration must not be null"); } + this.raceLog = raceLog; this.author = author; this.factory = factory; this.configuration = configuration; this.changedListeners = createChangedListenerContainer(); + this.isRecallDisplayedAnalyzer = new IsIndividualRecallDisplayedAnalyzer(raceLog); this.recallDisplayedFinder = new IndividualRecallDisplayedFinder(raceLog); this.recallRemovedFinder = new IndividualRecallRemovedFinder(raceLog); this.finishingTimeFinder = new FinishingTimeFinder(raceLog); this.finishedTimeFinder = new FinishedTimeFinder(raceLog); - this.startTimeFinder = new StartTimeFinder(raceLogResolver, raceLog); + // Use the following in order to initialize a start time finder once it's needed for start time-dependent individual recall timeouts + // this.startTimeFinder = new StartTimeFinder(raceLogResolver, raceLog); this.raceLogListener = new RaceLogChangedVisitor(this); this.raceLog.addListener(raceLogListener); @@ -131,7 +133,7 @@ public abstract class BaseRacingProcedure extends BaseRaceStateChangedListener i break; case RUNNING: if (isIndividualRecallDisplayed()) { - rescheduleIndividualRecallTimeout(); + rescheduleIndividualRecallTimeout(recallDisplayedFinder.analyze()); } break; default: @@ -139,10 +141,6 @@ public abstract class BaseRacingProcedure extends BaseRaceStateChangedListener i } } - private TimePoint getStartTime() { - return startTimeFinder.analyze().getStartTime(); - } - @Override public boolean isIndividualRecallDisplayed() { return cachedIsIndividualRecallDisplayed; @@ -150,10 +148,10 @@ public abstract class BaseRacingProcedure extends BaseRaceStateChangedListener i @Override public boolean isIndividualRecallDisplayed(TimePoint at) { - final TimePoint individualRecallDisplayedTime = getIndividualRecallDisplayedTime(); - final TimePoint individualRecallRemovalTime = getIndividualRecallRemovalTime(); - return (hasIndividualRecall() && individualRecallDisplayedTime != null && !individualRecallDisplayedTime.after(at) && - individualRecallRemovalTime != null && !individualRecallRemovalTime.after(at)); + if (hasIndividualRecall()) { + return new IsIndividualRecallDisplayedAnalyzer(getRaceLog(), at).analyze(); + } + return false; } @Override @@ -166,20 +164,17 @@ public abstract class BaseRacingProcedure extends BaseRaceStateChangedListener i @Override public TimePoint getIndividualRecallRemovalTime() { - final TimePoint result; - final TimePoint raceStartTime = getStartTime(); - final TimePoint removedEvent; - if (hasIndividualRecall() && (removedEvent = recallRemovedFinder.analyze()) != null && (raceStartTime == null || removedEvent.after(raceStartTime))) { - result = removedEvent; - } else { - final TimePoint individualRecallDisplayedTime = getIndividualRecallDisplayedTime(); - if (individualRecallDisplayedTime != null && raceStartTime != null) { - result = raceStartTime.plus(individualRecallRemovalTimeout); - } else { - result = null; + TimePoint displayed = getIndividualRecallDisplayedTime(); + if (hasIndividualRecall()) { + TimePoint removedEvent = recallRemovedFinder.analyze(); + if (removedEvent != null && (displayed == null || removedEvent.after(displayed))) { + return removedEvent; } } - return result; + if (displayed != null) { + return displayed.plus(individualRecallRemovalTimeout); + } + return null; } @Override @@ -217,21 +212,18 @@ public abstract class BaseRacingProcedure extends BaseRaceStateChangedListener i } protected void update() { - // TODO an X-ray up event with a time point in the future will not be recognized here because at the current time the flag is not displayed and no other race log event will trigger the update; we'd need to schedule another state event; as long as clocks are set correctly, additional transmission time will make this unlikely - boolean isRecallDisplayed = isIndividualRecallDisplayed(MillisecondsTimePoint.now()); + boolean isRecallDisplayed = isRecallDisplayedAnalyzer.analyze(); + if (cachedIsIndividualRecallDisplayed != isRecallDisplayed) { cachedIsIndividualRecallDisplayed = isRecallDisplayed; - if (!cachedIsIndividualRecallDisplayed) { - // individual recall was removed; no need to schedule an event for removal + if (cachedIsIndividualRecallDisplayed) { + changedListeners.onIndividualRecallDisplayed(this); + rescheduleIndividualRecallTimeout(recallDisplayedFinder.analyze()); + } else { changedListeners.onIndividualRecallRemoved(this); unscheduleStateEvent(RaceStateEvents.INDIVIDUAL_RECALL_TIMEOUT); } - } - // (re-)schedule the individual recall removal in any case; the removal time may have changed - if (cachedIsIndividualRecallDisplayed) { - changedListeners.onIndividualRecallDisplayed(this); - rescheduleIndividualRecallTimeout(); - } + } // always call listeners for changed flag, as this does not only affect recall, but also // changes start procedure, for which some text elements need to be updated @@ -239,9 +231,9 @@ public abstract class BaseRacingProcedure extends BaseRaceStateChangedListener i changedListeners.onActiveFlagsChanged(this); } - private void rescheduleIndividualRecallTimeout() { + private void rescheduleIndividualRecallTimeout(TimePoint displayTime) { unscheduleStateEvent(RaceStateEvents.INDIVIDUAL_RECALL_TIMEOUT); - scheduleStateEvents(new RaceStateEventImpl(getIndividualRecallRemovalTime(), RaceStateEvents.INDIVIDUAL_RECALL_TIMEOUT)); + scheduleStateEvents(new RaceStateEventImpl(displayTime.plus(individualRecallRemovalTimeout), RaceStateEvents.INDIVIDUAL_RECALL_TIMEOUT)); } protected void scheduleStateEvents(RaceStateEvent stateEvent) { From fa43319bce3958ef6b25ff095923ddd825194f62 Mon Sep 17 00:00:00 2001 From: Axel Uhl Date: Mon, 22 Jun 2015 17:33:35 +0200 Subject: [PATCH 09/29] after-math for bug2992: also add the leaderboard groups explicitly specified for export, even if they don't belong to any event --- .../sap/sailing/domain/masterdataimport/TopLevelMasterData.java | 1 + 1 file changed, 1 insertion(+) 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 89690f2690c..165939aefd7 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 @@ -258,6 +258,7 @@ public class TopLevelMasterData implements Serializable { public void setMasterDataExportFlagOnRaceColumns(boolean flagValue) { // collect all leaderboard groups for all events that will be touched during serialization final Set allLeaderboardGroups = new HashSet<>(); + allLeaderboardGroups.addAll(leaderboardGroups); for (Entry> i : eventForLeaderboardGroup.entrySet()) { for (Event e : i.getValue()) { Util.addAll(e.getLeaderboardGroups(), allLeaderboardGroups); From 240e393ada2cac2d6de8735f4196132e1fcc7d50 Mon Sep 17 00:00:00 2001 From: Axel Uhl Date: Mon, 22 Jun 2015 18:31:32 +0200 Subject: [PATCH 10/29] making RaceRankComparator re-usable for windward distance-based ranking in handicap racing --- .../domain/ranking/AbstractRankingMetric.java | 10 +- .../impl/AbstractRaceRankComparator.java | 122 ++++++++++++++++++ .../tracking/impl/RaceRankComparator.java | 83 +----------- .../tracking/impl/WindwardToGoComparator.java | 0 4 files changed, 134 insertions(+), 81 deletions(-) create mode 100644 java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/impl/AbstractRaceRankComparator.java mode change 100755 => 100644 java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/impl/WindwardToGoComparator.java diff --git a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/ranking/AbstractRankingMetric.java b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/ranking/AbstractRankingMetric.java index a54bafa34ac..e9d3cc9a2b3 100755 --- a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/ranking/AbstractRankingMetric.java +++ b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/ranking/AbstractRankingMetric.java @@ -281,7 +281,8 @@ public abstract class AbstractRankingMetric implements RankingMetric { /** * Constructs a comparator based on the results of * {@link #getWindwardDistanceTraveled(Competitor, TimePoint, WindLegTypeAndLegBearingCache)} where competitors are - * "less" than other competitors ("better") if they have a greater windward distance traveled. + * "less" than other competitors ("better") if they are in a later leg or, if in the same leg, have a greater + * windward distance traveled. If both competitors have already finished the race, the finishing time is compared. */ private Comparator getWindwardDistanceTraveledComparator(final TimePoint timePoint, final WindLegTypeAndLegBearingCache cache) { final Map windwardDistanceTraveledPerCompetitor = new HashMap<>(); @@ -289,9 +290,13 @@ public abstract class AbstractRankingMetric implements RankingMetric { windwardDistanceTraveledPerCompetitor.put(competitor, getWindwardDistanceTraveled(competitor, timePoint, cache)); } final Comparator nullsFirstDistanceComparator = Comparator.nullsFirst(Comparator.naturalOrder()); - return (c1, c2) -> nullsFirstDistanceComparator.compare( + return (c1, c2) -> { + int result = + if (trackedRace.getTrackedLeg(c2, timePoint) != null + nullsFirstDistanceComparator.compare( windwardDistanceTraveledPerCompetitor.get(c2), windwardDistanceTraveledPerCompetitor.get(c1)); + } } /** @@ -510,6 +515,7 @@ public abstract class AbstractRankingMetric implements RankingMetric { final TimePoint whosLegFinishTime = legWho.getFinishTime(); if (whosLegFinishTime != null) { // who's leg finishing time is known; we don't need to extrapolate + // TODO but we probably should still extrapolate based on what we would have known at timePoint; otherwise we'd get unsteady results depending on the time at which we look at this toEndOfLegOrTo = timePoint.until(whosLegFinishTime); } else { assert getWindwardDistanceTraveled(legTo.getCompetitor(), legTo.hasFinishedLeg(timePoint)?legTo.getFinishTime():timePoint, cache).compareTo( diff --git a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/impl/AbstractRaceRankComparator.java b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/impl/AbstractRaceRankComparator.java new file mode 100644 index 00000000000..1841a29df50 --- /dev/null +++ b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/impl/AbstractRaceRankComparator.java @@ -0,0 +1,122 @@ +package com.sap.sailing.domain.tracking.impl; + +import java.util.Collections; +import java.util.Comparator; +import java.util.NavigableSet; +import java.util.SortedSet; + +import com.sap.sailing.domain.base.Competitor; +import com.sap.sailing.domain.base.Course; +import com.sap.sailing.domain.tracking.MarkPassing; +import com.sap.sailing.domain.tracking.TrackedLegOfCompetitor; +import com.sap.sailing.domain.tracking.TrackedRace; +import com.sap.sse.common.TimePoint; + +/** + * Compares two competitors by their ranking in the overall race for a given time point. Competitors who haven't started + * the first leg are all equally ranked last. Competitors in different legs are ranked by inverse leg index: the higher + * the number of the leg the lesser (better) the rank. Competitors in the same leg are ranked by their windward distance + * to go in that leg, requiring wind data or estimates to be available for the given time point. The wind is estimated at + * the middle of the leg for consistent ordering, so the same wind data will be used for comparing all competitors in the + * same leg at a given point in time. + *

+ * + * This comparator assumes that the race's {@link Course} remains unchanged from the time this comparator's constructor + * is invoked and the last call to {@link #compare(Competitor, Competitor)} on this comparator. This should be obvious + * because course changes have an effect on the race's leg structure and therefore on the foundations for ranking. + * Clients should use {@link Course#lockForRead()} and {@link Course#unlockAfterRead()} to frame the construction and + * use of this comparator.

+ * + * Two different competitors may end up being ranked equal by this comparator. So take care and don't use this + * comparator class when inserting into an {@link SortedSet} when you want something like a ranking. It may overwrite + * existing entries. Use {@link Collections#sort(java.util.List, Comparator)} instead. + * + * @author Axel Uhl (d043530) + * + */ +public abstract class AbstractRaceRankComparator> implements Comparator { + private final TrackedRace trackedRace; + private final TimePoint timePoint; + private final DummyMarkPassingWithTimePointOnly markPassingWithTimePoint; + + public AbstractRaceRankComparator(TrackedRace trackedRace, TimePoint timePoint) { + super(); + this.trackedRace = trackedRace; + this.timePoint = timePoint; + this.markPassingWithTimePoint = new DummyMarkPassingWithTimePointOnly(timePoint); + } + + @Override + public int compare(Competitor o1, Competitor o2) { + int result; + if (o1 == o2) { + result = 0; + } else { + NavigableSet o1MarkPassings = trackedRace.getMarkPassings(o1); + NavigableSet o1MarkPassingsBeforeTimePoint; + MarkPassing o1LastMarkPassingBeforeTimePoint = null; + int o1MarkPassingsBeforeTimePointSize; + TrackedLegOfCompetitor o1Leg; + trackedRace.lockForRead(o1MarkPassings); + try { + o1MarkPassingsBeforeTimePoint = o1MarkPassings.headSet( + markPassingWithTimePoint, /* inclusive */true); + o1MarkPassingsBeforeTimePointSize = o1MarkPassingsBeforeTimePoint.size(); + if (o1MarkPassingsBeforeTimePointSize > 0) { + o1LastMarkPassingBeforeTimePoint = o1MarkPassingsBeforeTimePoint.last(); + } + o1Leg = trackedRace.getCurrentLeg(o1, timePoint); + } finally { + trackedRace.unlockAfterRead(o1MarkPassings); + } + NavigableSet o2MarkPassings = trackedRace.getMarkPassings(o2); + NavigableSet o2MarkPassingsBeforeTimePoint; + MarkPassing o2LastMarkPassingBeforeTimePoint = null; + int o2MarkPassingsBeforeTimePointSize; + TrackedLegOfCompetitor o2Leg; + trackedRace.lockForRead(o2MarkPassings); + try { + o2MarkPassingsBeforeTimePoint = o2MarkPassings.headSet(markPassingWithTimePoint, /* inclusive */true); + o2MarkPassingsBeforeTimePointSize = o2MarkPassingsBeforeTimePoint.size(); + if (o2MarkPassingsBeforeTimePointSize > 0) { + o2LastMarkPassingBeforeTimePoint = o2MarkPassingsBeforeTimePoint.last(); + } + o2Leg = trackedRace.getCurrentLeg(o2, timePoint); + } finally { + trackedRace.unlockAfterRead(o2MarkPassings); + } + result = o2MarkPassingsBeforeTimePointSize - o1MarkPassingsBeforeTimePointSize; // inverted: more legs means + // smaller rank + if (result == 0 && o1MarkPassingsBeforeTimePointSize > 0) { + // Competitors are on same leg and both have already started the first leg. + // TrackedLegOfCompetitor comparison also correctly uses finish times for a leg + // in case we have the final leg, so both competitors finished the race. + if (o1Leg == null) { + // both must already have finished race; sort by race finish time: earlier time means smaller + // (better) rank + result = o1LastMarkPassingBeforeTimePoint.getTimePoint().compareTo( + o2LastMarkPassingBeforeTimePoint.getTimePoint()); + } else { + if (o2Leg == null) { + result = 1; // o1Leg != null, so o1 has started leg already, o2 hasn't + } else { + if (o1Leg.getLeg() != o2Leg.getLeg()) { + // strange: both have the same number of mark passings but are in different legs; something is + // broken, but we can only try our best: + result = trackedRace.getRace().getCourse().getLegs().indexOf(o1Leg.getLeg()) - + trackedRace.getRace().getCourse().getLegs().indexOf(o2Leg.getLeg()); + } else { + // competitors are in same leg; compare their windward distance to go + final C wwdtgO1 = getComparisonValueForSameLegLessIsBetter(o1); + final C wwdtgO2 = getComparisonValueForSameLegLessIsBetter(o2); + result = wwdtgO1==null?wwdtgO2==null?0:-1:wwdtgO2==null?1:wwdtgO1.compareTo(wwdtgO2); + } + } + } + } + } + return result; + } + + protected abstract C getComparisonValueForSameLegLessIsBetter(Competitor o1); +} diff --git a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/impl/RaceRankComparator.java b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/impl/RaceRankComparator.java index 820de9b5699..dbfb534114b 100755 --- a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/impl/RaceRankComparator.java +++ b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/impl/RaceRankComparator.java @@ -4,13 +4,11 @@ import java.util.Collections; import java.util.Comparator; import java.util.HashMap; import java.util.Map; -import java.util.NavigableSet; import java.util.SortedSet; import com.sap.sailing.domain.base.Competitor; import com.sap.sailing.domain.base.Course; import com.sap.sailing.domain.common.Distance; -import com.sap.sailing.domain.tracking.MarkPassing; import com.sap.sailing.domain.tracking.TrackedLegOfCompetitor; import com.sap.sailing.domain.tracking.TrackedRace; import com.sap.sailing.domain.tracking.WindLegTypeAndLegBearingCache; @@ -39,17 +37,11 @@ import com.sap.sse.common.TimePoint; * @author Axel Uhl (d043530) * */ -public class RaceRankComparator implements Comparator { - private final TrackedRace trackedRace; - private final TimePoint timePoint; - private final DummyMarkPassingWithTimePointOnly markPassingWithTimePoint; +public class RaceRankComparator extends AbstractRaceRankComparator { private final Map windwardDistanceToGoInLegCache; public RaceRankComparator(TrackedRace trackedRace, TimePoint timePoint, WindLegTypeAndLegBearingCache cache) { - super(); - this.trackedRace = trackedRace; - this.timePoint = timePoint; - this.markPassingWithTimePoint = new DummyMarkPassingWithTimePointOnly(timePoint); + super(trackedRace, timePoint); this.windwardDistanceToGoInLegCache = new HashMap(); for (Competitor competitor : trackedRace.getRace().getCompetitors()) { final TrackedLegOfCompetitor trackedLegOfCompetitor = trackedRace.getTrackedLeg(competitor, timePoint); @@ -61,74 +53,7 @@ public class RaceRankComparator implements Comparator { } @Override - public int compare(Competitor o1, Competitor o2) { - int result; - if (o1 == o2) { - result = 0; - } else { - NavigableSet o1MarkPassings = trackedRace.getMarkPassings(o1); - NavigableSet o1MarkPassingsBeforeTimePoint; - MarkPassing o1LastMarkPassingBeforeTimePoint = null; - int o1MarkPassingsBeforeTimePointSize; - TrackedLegOfCompetitor o1Leg; - trackedRace.lockForRead(o1MarkPassings); - try { - o1MarkPassingsBeforeTimePoint = o1MarkPassings.headSet( - markPassingWithTimePoint, /* inclusive */true); - o1MarkPassingsBeforeTimePointSize = o1MarkPassingsBeforeTimePoint.size(); - if (o1MarkPassingsBeforeTimePointSize > 0) { - o1LastMarkPassingBeforeTimePoint = o1MarkPassingsBeforeTimePoint.last(); - } - o1Leg = trackedRace.getCurrentLeg(o1, timePoint); - } finally { - trackedRace.unlockAfterRead(o1MarkPassings); - } - NavigableSet o2MarkPassings = trackedRace.getMarkPassings(o2); - NavigableSet o2MarkPassingsBeforeTimePoint; - MarkPassing o2LastMarkPassingBeforeTimePoint = null; - int o2MarkPassingsBeforeTimePointSize; - TrackedLegOfCompetitor o2Leg; - trackedRace.lockForRead(o2MarkPassings); - try { - o2MarkPassingsBeforeTimePoint = o2MarkPassings.headSet(markPassingWithTimePoint, /* inclusive */true); - o2MarkPassingsBeforeTimePointSize = o2MarkPassingsBeforeTimePoint.size(); - if (o2MarkPassingsBeforeTimePointSize > 0) { - o2LastMarkPassingBeforeTimePoint = o2MarkPassingsBeforeTimePoint.last(); - } - o2Leg = trackedRace.getCurrentLeg(o2, timePoint); - } finally { - trackedRace.unlockAfterRead(o2MarkPassings); - } - result = o2MarkPassingsBeforeTimePointSize - o1MarkPassingsBeforeTimePointSize; // inverted: more legs means - // smaller rank - if (result == 0 && o1MarkPassingsBeforeTimePointSize > 0) { - // Competitors are on same leg and both have already started the first leg. - // TrackedLegOfCompetitor comparison also correctly uses finish times for a leg - // in case we have the final leg, so both competitors finished the race. - if (o1Leg == null) { - // both must already have finished race; sort by race finish time: earlier time means smaller - // (better) rank - result = o1LastMarkPassingBeforeTimePoint.getTimePoint().compareTo( - o2LastMarkPassingBeforeTimePoint.getTimePoint()); - } else { - if (o2Leg == null) { - result = 1; // o1Leg != null, so o1 has started leg already, o2 hasn't - } else { - if (o1Leg.getLeg() != o2Leg.getLeg()) { - // strange: both have the same number of mark passings but are in different legs; something is - // broken, but we can only try our best: - result = trackedRace.getRace().getCourse().getLegs().indexOf(o1Leg.getLeg()) - - trackedRace.getRace().getCourse().getLegs().indexOf(o2Leg.getLeg()); - } else { - // competitors are in same leg; compare their windward distance to go - final Distance wwdtgO1 = windwardDistanceToGoInLegCache.get(o1); - final Distance wwdtgO2 = windwardDistanceToGoInLegCache.get(o2); - result = wwdtgO1==null?wwdtgO2==null?0:-1:wwdtgO2==null?1:wwdtgO1.compareTo(wwdtgO2); - } - } - } - } - } - return result; + protected Distance getComparisonValueForSameLegLessIsBetter(Competitor o1) { + return windwardDistanceToGoInLegCache.get(o1); } } diff --git a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/impl/WindwardToGoComparator.java b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/impl/WindwardToGoComparator.java old mode 100755 new mode 100644 From 59fd77f276a40e99be5db4d9ed63ca741a9e508b Mon Sep 17 00:00:00 2001 From: Axel Uhl Date: Mon, 22 Jun 2015 18:41:07 +0200 Subject: [PATCH 11/29] use the refactored AbstractRaceRankComparator in AbstractRankingMetric for the getWindwardDistanceTraveledComparator implementation --- .../domain/ranking/AbstractRankingMetric.java | 15 +++++++-------- .../impl/AbstractRaceRankComparator.java | 17 ++++++++++++----- .../tracking/impl/RaceRankComparator.java | 4 ++-- 3 files changed, 21 insertions(+), 15 deletions(-) diff --git a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/ranking/AbstractRankingMetric.java b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/ranking/AbstractRankingMetric.java index e9d3cc9a2b3..298e978de59 100755 --- a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/ranking/AbstractRankingMetric.java +++ b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/ranking/AbstractRankingMetric.java @@ -24,6 +24,7 @@ import com.sap.sailing.domain.tracking.TrackedLegOfCompetitor; import com.sap.sailing.domain.tracking.TrackedRace; import com.sap.sailing.domain.tracking.WindLegTypeAndLegBearingCache; import com.sap.sailing.domain.tracking.WindPositionMode; +import com.sap.sailing.domain.tracking.impl.AbstractRaceRankComparator; import com.sap.sse.common.Duration; import com.sap.sse.common.TimePoint; @@ -289,14 +290,12 @@ public abstract class AbstractRankingMetric implements RankingMetric { for (final Competitor competitor : getCompetitors()) { windwardDistanceTraveledPerCompetitor.put(competitor, getWindwardDistanceTraveled(competitor, timePoint, cache)); } - final Comparator nullsFirstDistanceComparator = Comparator.nullsFirst(Comparator.naturalOrder()); - return (c1, c2) -> { - int result = - if (trackedRace.getTrackedLeg(c2, timePoint) != null - nullsFirstDistanceComparator.compare( - windwardDistanceTraveledPerCompetitor.get(c2), - windwardDistanceTraveledPerCompetitor.get(c1)); - } + return new AbstractRaceRankComparator(trackedRace, timePoint, /* lessIsBetter */ false) { + @Override + protected Distance getComparisonValueForSameLeg(Competitor competitor) { + return windwardDistanceTraveledPerCompetitor.get(competitor); + } + }; } /** diff --git a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/impl/AbstractRaceRankComparator.java b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/impl/AbstractRaceRankComparator.java index 1841a29df50..2863a33c5c1 100644 --- a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/impl/AbstractRaceRankComparator.java +++ b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/impl/AbstractRaceRankComparator.java @@ -38,12 +38,19 @@ public abstract class AbstractRaceRankComparator> implem private final TrackedRace trackedRace; private final TimePoint timePoint; private final DummyMarkPassingWithTimePointOnly markPassingWithTimePoint; + private final boolean lessIsBetter; - public AbstractRaceRankComparator(TrackedRace trackedRace, TimePoint timePoint) { + /** + * @param lessIsBetter + * tells whether lesser return values for {@link #getComparisonValueForSameLeg(Competitor)} denote a + * better competitor ranking or not. + */ + public AbstractRaceRankComparator(TrackedRace trackedRace, TimePoint timePoint, boolean lessIsBetter) { super(); this.trackedRace = trackedRace; this.timePoint = timePoint; this.markPassingWithTimePoint = new DummyMarkPassingWithTimePointOnly(timePoint); + this.lessIsBetter = lessIsBetter; } @Override @@ -107,9 +114,9 @@ public abstract class AbstractRaceRankComparator> implem trackedRace.getRace().getCourse().getLegs().indexOf(o2Leg.getLeg()); } else { // competitors are in same leg; compare their windward distance to go - final C wwdtgO1 = getComparisonValueForSameLegLessIsBetter(o1); - final C wwdtgO2 = getComparisonValueForSameLegLessIsBetter(o2); - result = wwdtgO1==null?wwdtgO2==null?0:-1:wwdtgO2==null?1:wwdtgO1.compareTo(wwdtgO2); + final C wwdtgO1 = getComparisonValueForSameLeg(o1); + final C wwdtgO2 = getComparisonValueForSameLeg(o2); + result = wwdtgO1==null?wwdtgO2==null?0:-1:wwdtgO2==null?1:(lessIsBetter?1:-1)*wwdtgO1.compareTo(wwdtgO2); } } } @@ -118,5 +125,5 @@ public abstract class AbstractRaceRankComparator> implem return result; } - protected abstract C getComparisonValueForSameLegLessIsBetter(Competitor o1); + protected abstract C getComparisonValueForSameLeg(Competitor competitor); } diff --git a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/impl/RaceRankComparator.java b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/impl/RaceRankComparator.java index dbfb534114b..56f6202c8d8 100755 --- a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/impl/RaceRankComparator.java +++ b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/impl/RaceRankComparator.java @@ -41,7 +41,7 @@ public class RaceRankComparator extends AbstractRaceRankComparator { private final Map windwardDistanceToGoInLegCache; public RaceRankComparator(TrackedRace trackedRace, TimePoint timePoint, WindLegTypeAndLegBearingCache cache) { - super(trackedRace, timePoint); + super(trackedRace, timePoint, /* lessIsBetter */ true); this.windwardDistanceToGoInLegCache = new HashMap(); for (Competitor competitor : trackedRace.getRace().getCompetitors()) { final TrackedLegOfCompetitor trackedLegOfCompetitor = trackedRace.getTrackedLeg(competitor, timePoint); @@ -53,7 +53,7 @@ public class RaceRankComparator extends AbstractRaceRankComparator { } @Override - protected Distance getComparisonValueForSameLegLessIsBetter(Competitor o1) { + protected Distance getComparisonValueForSameLeg(Competitor o1) { return windwardDistanceToGoInLegCache.get(o1); } } From 5d9e8863ee5d87959c7250256e2445b5b7bb3aa4 Mon Sep 17 00:00:00 2001 From: Axel Uhl Date: Mon, 22 Jun 2015 20:29:52 +0200 Subject: [PATCH 12/29] reverted to fixed version --- java/com.sap.sailing.gwt.ui/SailingGWT sdm.launch | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) mode change 100755 => 100644 java/com.sap.sailing.gwt.ui/SailingGWT sdm.launch diff --git a/java/com.sap.sailing.gwt.ui/SailingGWT sdm.launch b/java/com.sap.sailing.gwt.ui/SailingGWT sdm.launch old mode 100755 new mode 100644 index a00d6c0ff91..7435c9ab64d --- a/java/com.sap.sailing.gwt.ui/SailingGWT sdm.launch +++ b/java/com.sap.sailing.gwt.ui/SailingGWT sdm.launch @@ -16,11 +16,9 @@ - - + - @@ -73,7 +71,7 @@ - + From fc5b565cfb0e7fdd2966623a040e04a63cc04907 Mon Sep 17 00:00:00 2001 From: Axel Uhl Date: Mon, 22 Jun 2015 20:55:21 +0200 Subject: [PATCH 13/29] fixing bug 2994 by always extrapolating based on average VMG as the competitor hasn't finished the leg at the request time point --- .../sap/sailing/domain/ranking/AbstractRankingMetric.java | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/ranking/AbstractRankingMetric.java b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/ranking/AbstractRankingMetric.java index 298e978de59..437af2fea38 100755 --- a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/ranking/AbstractRankingMetric.java +++ b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/ranking/AbstractRankingMetric.java @@ -512,9 +512,8 @@ public abstract class AbstractRankingMetric implements RankingMetric { if (legTo.hasFinishedLeg(timePoint)) { // calculate actual time it takes who to reach the end of the leg starting at timePoint: final TimePoint whosLegFinishTime = legWho.getFinishTime(); - if (whosLegFinishTime != null) { - // who's leg finishing time is known; we don't need to extrapolate - // TODO but we probably should still extrapolate based on what we would have known at timePoint; otherwise we'd get unsteady results depending on the time at which we look at this + if (whosLegFinishTime != null && !whosLegFinishTime.after(timePoint)) { + // who's leg finishing time is known and is already reached at timePoint; we don't need to extrapolate toEndOfLegOrTo = timePoint.until(whosLegFinishTime); } else { assert getWindwardDistanceTraveled(legTo.getCompetitor(), legTo.hasFinishedLeg(timePoint)?legTo.getFinishTime():timePoint, cache).compareTo( From e102c4d404386af12b97a0456e674b27ac37f18a Mon Sep 17 00:00:00 2001 From: Axel Uhl Date: Mon, 22 Jun 2015 22:34:10 +0200 Subject: [PATCH 14/29] fixing test issues with unserializable Mockito mocks for bug 2995 --- .../test/SerializeRankingMetricTest.java | 33 ++++++++++++++++--- 1 file changed, 29 insertions(+), 4 deletions(-) diff --git a/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/SerializeRankingMetricTest.java b/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/SerializeRankingMetricTest.java index 653b4a4badd..0cee3470389 100644 --- a/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/SerializeRankingMetricTest.java +++ b/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/SerializeRankingMetricTest.java @@ -1,22 +1,47 @@ package com.sap.sailing.domain.test; import static org.junit.Assert.assertNotNull; -import static org.mockito.Mockito.mock; +import static org.junit.Assert.assertTrue; import java.io.IOException; +import java.util.Collections; +import java.util.UUID; import org.junit.Test; +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.Sideline; +import com.sap.sailing.domain.base.Waypoint; +import com.sap.sailing.domain.base.impl.CourseImpl; +import com.sap.sailing.domain.base.impl.RaceDefinitionImpl; +import com.sap.sailing.domain.base.impl.RegattaImpl; +import com.sap.sailing.domain.leaderboard.impl.LowPoint; +import com.sap.sailing.domain.racelog.impl.EmptyRaceLogStore; +import com.sap.sailing.domain.racelog.tracking.EmptyGPSFixStore; +import com.sap.sailing.domain.ranking.RankingMetric; import com.sap.sailing.domain.ranking.TimeOnTimeAndDistanceRankingMetric; +import com.sap.sailing.domain.regattalog.impl.EmptyRegattaLogStore; import com.sap.sailing.domain.tracking.TrackedRace; +import com.sap.sailing.domain.tracking.impl.DynamicTrackedRaceImpl; +import com.sap.sailing.domain.tracking.impl.DynamicTrackedRegattaImpl; +import com.sap.sailing.domain.tracking.impl.EmptyWindStore; public class SerializeRankingMetricTest extends AbstractSerializationTest { @Test public void testTimeOnTimeAndDistanceRankingMetricSerialization() throws ClassNotFoundException, IOException { - final TrackedRace trackedRace = mock(TrackedRace.class); - final TimeOnTimeAndDistanceRankingMetric rankingMetric = new TimeOnTimeAndDistanceRankingMetric(trackedRace); - TimeOnTimeAndDistanceRankingMetric clone = cloneBySerialization(rankingMetric, DomainFactory.INSTANCE); + final BoatClass _49er = DomainFactory.INSTANCE.getOrCreateBoatClass("49er"); + final TrackedRace trackedRace = new DynamicTrackedRaceImpl(new DynamicTrackedRegattaImpl( + new RegattaImpl(EmptyRaceLogStore.INSTANCE, EmptyRegattaLogStore.INSTANCE, "Regatta", /* boatClass */ _49er, + /* startDate */ null, /* endDate */ null, /* trackedRegattaRegistry */ null, + new LowPoint(), UUID.randomUUID(), /* courseArea */ null)), + new RaceDefinitionImpl("Race", new CourseImpl("Course", Collections.emptyList()) , + /* boatClass */ _49er, Collections.emptySet()), + Collections.emptyList(), EmptyWindStore.INSTANCE, EmptyGPSFixStore.INSTANCE, 0l, 0l, 0l, + false, TimeOnTimeAndDistanceRankingMetric::new, null); + RankingMetric clone = cloneBySerialization(trackedRace.getRankingMetric(), DomainFactory.INSTANCE); assertNotNull(clone); + assertTrue(clone instanceof TimeOnTimeAndDistanceRankingMetric); } } From e95c8237b865bab1ba105266c2adafbf346b3a3a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Bro=C3=9F?= Date: Tue, 23 Jun 2015 11:59:21 +0200 Subject: [PATCH 15/29] Fixes several bugs in the buoy positioning app concerning GPS location updates and inital acquiration --- .../app/ui/fragments/BuoyFragment.java | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/mobile/com.sap.sailing.buoy.positioning/src/com/sap/sailing/android/buoy/positioning/app/ui/fragments/BuoyFragment.java b/mobile/com.sap.sailing.buoy.positioning/src/com/sap/sailing/android/buoy/positioning/app/ui/fragments/BuoyFragment.java index 46f75bcabd3..b10ceb8b4b6 100644 --- a/mobile/com.sap.sailing.buoy.positioning/src/com/sap/sailing/android/buoy/positioning/app/ui/fragments/BuoyFragment.java +++ b/mobile/com.sap.sailing.buoy.positioning/src/com/sap/sailing/android/buoy/positioning/app/ui/fragments/BuoyFragment.java @@ -1,5 +1,7 @@ package com.sap.sailing.android.buoy.positioning.app.ui.fragments; +import java.text.DecimalFormat; + import android.content.Context; import android.location.Location; import android.location.LocationListener; @@ -23,14 +25,15 @@ import com.sap.sailing.android.buoy.positioning.app.util.PingHelper; import com.sap.sailing.android.buoy.positioning.app.valueobjects.MarkInfo; import com.sap.sailing.android.buoy.positioning.app.valueobjects.MarkPingInfo; import com.sap.sailing.android.shared.data.LeaderboardInfo; +import com.sap.sailing.android.shared.logging.ExLog; import com.sap.sailing.android.shared.ui.customviews.OpenSansButton; import com.sap.sailing.android.shared.ui.customviews.OpenSansTextView; import com.sap.sailing.android.shared.ui.customviews.SignalQualityIndicatorView; import com.sap.sailing.android.ui.fragments.BaseFragment; -import java.text.DecimalFormat; - public class BuoyFragment extends BaseFragment implements LocationListener { + private static final int GPS_MIN_DISTANCE = 1; + private static final int GPS_MIN_TIME = 1000; private OpenSansTextView markHeaderTextView; private OpenSansTextView latitudeTextView; private OpenSansTextView longitudeTextView; @@ -80,7 +83,7 @@ public class BuoyFragment extends BaseFragment implements LocationListener { signalQualityIndicatorView.setSignalQuality(GPSQuality.noSignal.toInt()); if (mark != null) { markHeaderTextView.setText(mark.getName()); - setUpTextUI(null); + setUpTextUI(lastKnownLocation); GoogleMap map = mapFragment.getMap(); configureMap(map); updateMap(); @@ -124,6 +127,11 @@ public class BuoyFragment extends BaseFragment implements LocationListener { accuracyText += " (" + String.format(accuracyString, accuracyFormatter.format(markPing.getAccuracy())) + ")"; } + + ExLog.w(getActivity(), getTag(), "Setting latitude to: "+latitudeText); + ExLog.w(getActivity(), getTag(), "Setting longitude to: "+longitudeText); + ExLog.w(getActivity(), getTag(), "Setting accuracy to: "+accuracyText); + latitudeTextView.setText(latitudeText); longitudeTextView.setText(longitudeText); accuracyTextView.setText(accuracyText); @@ -179,7 +187,10 @@ public class BuoyFragment extends BaseFragment implements LocationListener { private void initLocationProvider() { locationManager = (LocationManager) getActivity().getSystemService(Context.LOCATION_SERVICE); locationManager.removeUpdates(this); - locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 10000, 10, this); + locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, GPS_MIN_TIME, GPS_MIN_DISTANCE, this); + + Location initialLocation = locationManager.getLastKnownLocation(LocationManager.GPS_PROVIDER); + onLocationChanged(initialLocation); } public void updateMap() { From ead9169276fa061a2afedbe670de6288b53af71c Mon Sep 17 00:00:00 2001 From: Peter Siegmund Date: Tue, 23 Jun 2015 13:58:25 +0200 Subject: [PATCH 16/29] deactivate the Android Emulator Espresso tests - JUnit tests are still running on the local JVM --- configuration/buildAndUpdateProduct.sh | 49 +++++++++++++------------- 1 file changed, 25 insertions(+), 24 deletions(-) diff --git a/configuration/buildAndUpdateProduct.sh b/configuration/buildAndUpdateProduct.sh index 3c405d73557..9ad52b5af9f 100755 --- a/configuration/buildAndUpdateProduct.sh +++ b/configuration/buildAndUpdateProduct.sh @@ -660,30 +660,31 @@ if [[ "$@" == "build" ]] || [[ "$@" == "all" ]]; then if [[ ${PIPESTATUS[0]} != 0 ]]; then exit 103 fi - adb emu kill - echo "Downloading image (sys-img-${ANDROID_ABI}-android-${TEST_API})..." | tee -a $START_DIR/build.log - echo yes | "$ANDROID" update sdk $ANDROID_OPTIONS --filter sys-img-${ANDROID_ABI}-android-${TEST_API} --no-ui --force --all > /dev/null - echo no | "$ANDROID" create avd --name ${AVD_NAME} --target android-${TEST_API} --abi ${ANDROID_ABI} --force -p ${START_DIR}/emulator - echo "Starting emulator..." | tee -a $START_DIR/build.log - emulator -avd ${AVD_NAME} -no-skin -no-audio -no-window & - echo "Waiting for startup..." | tee -a $START_DIR/build.log - adb wait-for-device - sleep 60 - $PROJECT_HOME/configuration/androidWaitForEmulator.sh - if [[ $? != 0 ]]; then - adb emu kill - "$ANDROID" delete avd --name ${AVD_NAME} - exit 102 - fi - adb shell input keyevent 82 & - ./gradlew deviceCheck connectedCheck | tee -a $START_DIR/build.log - if [[ ${PIPESTATUS[0]} != 0 ]]; then - adb emu kill - "$ANDROID" delete avd --name ${AVD_NAME} - exit 101 - fi - adb emu kill - "$ANDROID" delete avd --name ${AVD_NAME} + # TODO find a way that the emulator test is stable in hudson + # adb emu kill + # echo "Downloading image (sys-img-${ANDROID_ABI}-android-${TEST_API})..." | tee -a $START_DIR/build.log + # echo yes | "$ANDROID" update sdk $ANDROID_OPTIONS --filter sys-img-${ANDROID_ABI}-android-${TEST_API} --no-ui --force --all > /dev/null + # echo no | "$ANDROID" create avd --name ${AVD_NAME} --target android-${TEST_API} --abi ${ANDROID_ABI} --force -p ${START_DIR}/emulator + # echo "Starting emulator..." | tee -a $START_DIR/build.log + # emulator -avd ${AVD_NAME} -no-skin -no-audio -no-window & + # echo "Waiting for startup..." | tee -a $START_DIR/build.log + # adb wait-for-device + # sleep 60 + # $PROJECT_HOME/configuration/androidWaitForEmulator.sh + # if [[ $? != 0 ]]; then + # adb emu kill + # "$ANDROID" delete avd --name ${AVD_NAME} + # exit 102 + # fi + # adb shell input keyevent 82 & + # ./gradlew deviceCheck connectedCheck | tee -a $START_DIR/build.log + # if [[ ${PIPESTATUS[0]} != 0 ]]; then + # adb emu kill + # "$ANDROID" delete avd --name ${AVD_NAME} + # exit 101 + # fi + # adb emu kill + # "$ANDROID" delete avd --name ${AVD_NAME} fi else echo "INFO: Deactivating mobile modules" From 104ce07b598bbbff110f4264f0d4154a2497015a Mon Sep 17 00:00:00 2001 From: Frederik Petersen Date: Tue, 23 Jun 2015 16:50:42 +0200 Subject: [PATCH 17/29] Added PolarsChangedListener registerable per boat class --- .../domain/polars/PolarDataService.java | 14 ++++++++++ .../domain/polars/PolarsChangedListener.java | 10 +++++++ .../polars/impl/PolarDataServiceImpl.java | 11 ++++++++ .../CubicRegressionPerCourseProcessor.java | 14 ++++++++++ .../sailing/polars/mining/PolarDataMiner.java | 26 +++++++++++++++++-- ...eedRegressionPerAngleClusterProcessor.java | 14 +++++++++- 6 files changed, 86 insertions(+), 3 deletions(-) create mode 100644 java/com.sap.sailing.domain/src/com/sap/sailing/domain/polars/PolarsChangedListener.java diff --git a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/polars/PolarDataService.java b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/polars/PolarDataService.java index 8d65c64a5af..cd7b5c44c33 100644 --- a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/polars/PolarDataService.java +++ b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/polars/PolarDataService.java @@ -227,6 +227,20 @@ public interface PolarDataService { LegType legType, Tack tack) throws NotEnoughDataHasBeenAddedException; void insertExistingFixes(TrackedRace trackedRace); + + /** + * + * @param boatClass When polars of this boat class change, the listener will be notified. May not be null. + * @param listener may not be null + */ + void registerListener(BoatClass boatClass, PolarsChangedListener listener); + + /** + * + * @param boatClass + * @param listener + */ + void unregisterListener(BoatClass boatClass, PolarsChangedListener listener); } diff --git a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/polars/PolarsChangedListener.java b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/polars/PolarsChangedListener.java new file mode 100644 index 00000000000..f8ab4b274a4 --- /dev/null +++ b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/polars/PolarsChangedListener.java @@ -0,0 +1,10 @@ +package com.sap.sailing.domain.polars; + +public interface PolarsChangedListener { + + /** + * Is called when the polars of the boat class you registered the listener for changed + */ + void polarsChanged(); + +} diff --git a/java/com.sap.sailing.polars/src/com/sap/sailing/polars/impl/PolarDataServiceImpl.java b/java/com.sap.sailing.polars/src/com/sap/sailing/polars/impl/PolarDataServiceImpl.java index 6913ca6b081..4fa72c074cd 100755 --- a/java/com.sap.sailing.polars/src/com/sap/sailing/polars/impl/PolarDataServiceImpl.java +++ b/java/com.sap.sailing.polars/src/com/sap/sailing/polars/impl/PolarDataServiceImpl.java @@ -25,6 +25,7 @@ import com.sap.sailing.domain.common.impl.KnotSpeedWithBearingImpl; import com.sap.sailing.domain.common.tracking.GPSFixMoving; import com.sap.sailing.domain.polars.NotEnoughDataHasBeenAddedException; import com.sap.sailing.domain.polars.PolarDataService; +import com.sap.sailing.domain.polars.PolarsChangedListener; import com.sap.sailing.domain.tracking.TrackedRace; import com.sap.sailing.polars.aggregation.PolarFixAggregator; import com.sap.sailing.polars.aggregation.SimplePolarFixRaceInterval; @@ -206,4 +207,14 @@ public class PolarDataServiceImpl implements PolarDataService { } } + @Override + public void registerListener(BoatClass boatClass, PolarsChangedListener listener) { + polarDataMiner.registerListener(boatClass, listener); + } + + @Override + public void unregisterListener(BoatClass boatClass, PolarsChangedListener listener) { + polarDataMiner.unregisterListener(boatClass, listener); + } + } diff --git a/java/com.sap.sailing.polars/src/com/sap/sailing/polars/mining/CubicRegressionPerCourseProcessor.java b/java/com.sap.sailing.polars/src/com/sap/sailing/polars/mining/CubicRegressionPerCourseProcessor.java index fe92c251752..c3134cfbc1b 100644 --- a/java/com.sap.sailing.polars/src/com/sap/sailing/polars/mining/CubicRegressionPerCourseProcessor.java +++ b/java/com.sap.sailing.polars/src/com/sap/sailing/polars/mining/CubicRegressionPerCourseProcessor.java @@ -4,6 +4,7 @@ import java.util.HashMap; import java.util.HashSet; import java.util.Map; import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; import java.util.logging.Logger; import org.apache.commons.math.analysis.polynomials.PolynomialFunction; @@ -14,6 +15,7 @@ import com.sap.sailing.domain.common.LegType; import com.sap.sailing.domain.common.Speed; import com.sap.sailing.domain.common.Tack; import com.sap.sailing.domain.polars.NotEnoughDataHasBeenAddedException; +import com.sap.sailing.domain.polars.PolarsChangedListener; import com.sap.sse.datamining.AdditionalResultDataBuilder; import com.sap.sse.datamining.components.Processor; import com.sap.sse.datamining.factories.GroupKeyFactory; @@ -25,7 +27,13 @@ public class CubicRegressionPerCourseProcessor implements Processor regressions = new HashMap<>(); + + private ConcurrentHashMap> listeners; + public CubicRegressionPerCourseProcessor(ConcurrentHashMap> listeners) { + this.listeners = listeners; + } + @Override public boolean canProcessElements() { // TODO Auto-generated method stub @@ -46,6 +54,12 @@ public class CubicRegressionPerCourseProcessor implements Processor listenersForBoatClass = listeners.get(fix.getBoatClass()); + if (listenersForBoatClass != null) { + for (PolarsChangedListener listener : listenersForBoatClass) { + listener.polarsChanged(); + } + } } } diff --git a/java/com.sap.sailing.polars/src/com/sap/sailing/polars/mining/PolarDataMiner.java b/java/com.sap.sailing.polars/src/com/sap/sailing/polars/mining/PolarDataMiner.java index 58c6d535ed6..3411cc1878a 100755 --- a/java/com.sap.sailing.polars/src/com/sap/sailing/polars/mining/PolarDataMiner.java +++ b/java/com.sap.sailing.polars/src/com/sap/sailing/polars/mining/PolarDataMiner.java @@ -3,11 +3,13 @@ package com.sap.sailing.polars.mining; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; +import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.Map; import java.util.Queue; import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentLinkedQueue; import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.RejectedExecutionHandler; @@ -40,6 +42,7 @@ import com.sap.sailing.domain.common.impl.PolarSheetsHistogramDataImpl; import com.sap.sailing.domain.common.impl.WindSpeedSteppingWithMaxDistance; import com.sap.sailing.domain.common.tracking.GPSFixMoving; import com.sap.sailing.domain.polars.NotEnoughDataHasBeenAddedException; +import com.sap.sailing.domain.polars.PolarsChangedListener; import com.sap.sailing.domain.tracking.TrackedRace; import com.sap.sailing.polars.impl.CubicEquation; import com.sap.sse.datamining.components.FilterCriterion; @@ -64,6 +67,8 @@ public class PolarDataMiner { private final Queue fixQueue = new ConcurrentLinkedQueue(); private static final Logger logger = Logger.getLogger(PolarDataMiner.class.getSimpleName()); + + private final ConcurrentHashMap> listeners = new ConcurrentHashMap<>(); private ThreadPoolExecutor createExecutor() { return new ThreadPoolExecutor(THREAD_POOL_SIZE, THREAD_POOL_SIZE, 60, TimeUnit.SECONDS, @@ -135,7 +140,7 @@ public class PolarDataMiner { GPSFixMovingWithPolarContext.class, executor, movingAverageGrouperResultReceivers, parameterizedDimensions); - cubicRegressionPerCourseProcessor = new CubicRegressionPerCourseProcessor(); + cubicRegressionPerCourseProcessor = new CubicRegressionPerCourseProcessor(listeners); Collection, ?>> regressionPerCourseGrouperResultReceivers = new ArrayList, ?>>(); regressionPerCourseGrouperResultReceivers.add(cubicRegressionPerCourseProcessor); @@ -147,7 +152,7 @@ public class PolarDataMiner { GPSFixMovingWithPolarContext.class, executor, regressionPerCourseGrouperResultReceivers, parameterizedDimensionsForCubicRegression); ClusterGroup angleClusterGroup = createAngleClusterGroup(); - speedRegressionPerAngleClusterProcessor = new SpeedRegressionPerAngleClusterProcessor(angleClusterGroup); + speedRegressionPerAngleClusterProcessor = new SpeedRegressionPerAngleClusterProcessor(angleClusterGroup, listeners); Collection, ?>> regressionPerAngleClusterGrouperResultReceivers = new ArrayList, ?>>(); regressionPerAngleClusterGrouperResultReceivers.add(speedRegressionPerAngleClusterProcessor); @@ -436,4 +441,21 @@ public class PolarDataMiner { } } } + + public void registerListener(BoatClass boatClass, PolarsChangedListener listener) { + Set listenersForBoatClass = listeners.get(boatClass); + if (listenersForBoatClass == null) { + Map mapForConcurrency = new ConcurrentHashMap<>(); + listenersForBoatClass = Collections.newSetFromMap(mapForConcurrency); + listeners.put(boatClass, listenersForBoatClass); + } + listenersForBoatClass.add(listener); + } + + public void unregisterListener(BoatClass boatClass, PolarsChangedListener listener) { + Set listenersForBoatClass = listeners.get(boatClass); + if (listenersForBoatClass != null) { + listenersForBoatClass.remove(listener); + } + } } diff --git a/java/com.sap.sailing.polars/src/com/sap/sailing/polars/mining/SpeedRegressionPerAngleClusterProcessor.java b/java/com.sap.sailing.polars/src/com/sap/sailing/polars/mining/SpeedRegressionPerAngleClusterProcessor.java index e1fb5b9e1b4..3b58c9428e9 100644 --- a/java/com.sap.sailing.polars/src/com/sap/sailing/polars/mining/SpeedRegressionPerAngleClusterProcessor.java +++ b/java/com.sap.sailing.polars/src/com/sap/sailing/polars/mining/SpeedRegressionPerAngleClusterProcessor.java @@ -2,6 +2,8 @@ package com.sap.sailing.polars.mining; import java.util.HashMap; import java.util.Map; +import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; import java.util.logging.Logger; import org.apache.commons.math.analysis.polynomials.PolynomialFunction; @@ -14,6 +16,7 @@ import com.sap.sailing.domain.common.Speed; import com.sap.sailing.domain.common.impl.DegreeBearingImpl; import com.sap.sailing.domain.common.impl.KnotSpeedImpl; import com.sap.sailing.domain.polars.NotEnoughDataHasBeenAddedException; +import com.sap.sailing.domain.polars.PolarsChangedListener; import com.sap.sailing.polars.regression.IncrementalLeastSquares; import com.sap.sailing.polars.regression.impl.IncrementalAnyOrderLeastSquaresImpl; import com.sap.sse.datamining.AdditionalResultDataBuilder; @@ -33,9 +36,12 @@ public class SpeedRegressionPerAngleClusterProcessor implements Processor fixCountPerBoatClass = new HashMap<>(); private final ClusterGroup angleClusterGroup; + + private final ConcurrentHashMap> listeners; - public SpeedRegressionPerAngleClusterProcessor(ClusterGroup angleClusterGroup) { + public SpeedRegressionPerAngleClusterProcessor(ClusterGroup angleClusterGroup, ConcurrentHashMap> listeners) { this.angleClusterGroup = angleClusterGroup; + this.listeners = listeners; } @Override @@ -64,6 +70,12 @@ public class SpeedRegressionPerAngleClusterProcessor implements Processor listenersForBoatClass = listeners.get(fix.getBoatClass()); + if (listenersForBoatClass != null) { + for (PolarsChangedListener listener : listenersForBoatClass) { + listener.polarsChanged(); + } + } } /** From 6c6dac9e37957379ccde22fde5bf07cdf7f1237c Mon Sep 17 00:00:00 2001 From: Frank Mittag Date: Tue, 23 Jun 2015 15:15:02 +0000 Subject: [PATCH 18/29] Updated kieler woche 2015 (markdown) --- wiki/kieler-woche-2015.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/wiki/kieler-woche-2015.md b/wiki/kieler-woche-2015.md index 19d03533140..1e20cb28d54 100644 --- a/wiki/kieler-woche-2015.md +++ b/wiki/kieler-woche-2015.md @@ -19,6 +19,11 @@ for fast and available switching. The DB they use is called `KW2015`, and so is - External IP: 54.76.169.213 - Internal IP: 172.31.30.73 +### Master 3 Server (64GB) +- Admin Console at http://ec2-54-171-148-10.eu-west-1.compute.amazonaws.com:8888/gwt/AdminConsole.html +- External IP: 54.171.148.10 +- Internal IP: 172.31.26.119 + ### "Current" Master Whichever master is current, we map the main Apache URL http://kielerwoche2015-master.sapsailing.com to it. This is also the URL to use for Tablet and Smartphone configurations. From 7a931a12599d3b35aa44738002e8c837f1518491 Mon Sep 17 00:00:00 2001 From: Frank Mittag Date: Tue, 23 Jun 2015 16:25:54 +0000 Subject: [PATCH 19/29] Updated kieler woche 2015 (markdown) --- wiki/kieler-woche-2015.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/wiki/kieler-woche-2015.md b/wiki/kieler-woche-2015.md index 1e20cb28d54..193d6be4595 100644 --- a/wiki/kieler-woche-2015.md +++ b/wiki/kieler-woche-2015.md @@ -3,18 +3,18 @@ ## Server Landscape We run four servers for the event: -- on EC2: **Master 1**, **Master 2**, **Replica 1** and **Replica 2** with an **ELB** in front, +- on EC2: **Master 1**, **Master 2**, **Master 3**, **Replica 1** and **Replica 2** with an **ELB** in front, - ELB canonical name is KW2015-553831863.eu-west-1.elb.amazonaws.com - locally: **Cube-Server** for fast and available switching. The DB they use is called `KW2015`, and so is the replication channel. The git branch we use to merge the features we want to deploy to the event servers is called `kielerwoche2015` and the git tag used to build a release for it is called `kielerwoche2015-release`. See http://hudson.sapsailing.com/job/SAPSailingAnalytics-kielerwoche2015/ and http://hudson.sapsailing.com/job/SAPSailingAnalytics-kielerwoche2015-release/, respectively, for their Hudson jobs. -### Master 1 Server +### Master 1 Server (32GB) - Admin Console at http://ec2-54-154-151-10.eu-west-1.compute.amazonaws.com:8888/gwt/AdminConsole.html - External IP: 54.154.151.10 - Internal IP: 172.31.24.187 -### Master 2 Server +### Master 2 Server (32GB) - Admin Console at http://ec2-54-76-169-213.eu-west-1.compute.amazonaws.com:8888/gwt/AdminConsole.html - External IP: 54.76.169.213 - Internal IP: 172.31.30.73 From 50260e45c0c2503217ee2480f5cf5f6d07fba12d Mon Sep 17 00:00:00 2001 From: Axel Uhl Date: Tue, 23 Jun 2015 20:11:08 +0200 Subject: [PATCH 20/29] fixing bug 3001 by pre-calculating the windward distances for each competitor before starting hte sorter --- .../sailing/server/impl/RacingEventServiceImpl.java | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) 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 59a5e25ee66..f1a4c1b491c 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 @@ -88,6 +88,7 @@ import com.sap.sailing.domain.base.impl.EventImpl; import com.sap.sailing.domain.base.impl.RegattaImpl; import com.sap.sailing.domain.base.impl.RemoteSailingServerReferenceImpl; import com.sap.sailing.domain.common.DataImportProgress; +import com.sap.sailing.domain.common.Distance; import com.sap.sailing.domain.common.LeaderboardNameConstants; import com.sap.sailing.domain.common.Position; import com.sap.sailing.domain.common.RegattaAndRaceIdentifier; @@ -3218,9 +3219,13 @@ public class RacingEventServiceImpl implements RacingEventService, ClearStateTes public Iterable getCompetitorInOrderOfWindwardDistanceTraveledFarthestFirst(TrackedRace trackedRace, TimePoint timePoint) { final RankingInfo rankingInfo = trackedRace.getRankingMetric().getRankingInfo(timePoint); final List result = new ArrayList<>(); - Util.addAll(trackedRace.getRace().getCompetitors(), result); - result.sort((c1, c2) -> rankingInfo.getCompetitorRankingInfo().apply(c2).getWindwardDistanceSailed().compareTo( - rankingInfo.getCompetitorRankingInfo().apply(c1).getWindwardDistanceSailed())); + final Map windwardDistanceSailedPerCompetitor = new HashMap<>(); + for (final Competitor competitor : trackedRace.getRace().getCompetitors()) { + result.add(competitor); + windwardDistanceSailedPerCompetitor.put(competitor, rankingInfo.getCompetitorRankingInfo().apply(competitor).getWindwardDistanceSailed()); + } + result.sort((c1, c2) -> windwardDistanceSailedPerCompetitor.get(c2).compareTo( + windwardDistanceSailedPerCompetitor.get(c1))); return result; } From 2116c2db02142a94beb325e84f760d958070784f Mon Sep 17 00:00:00 2001 From: Axel Uhl Date: Tue, 23 Jun 2015 20:23:50 +0200 Subject: [PATCH 21/29] fixing bug 3002 by checking startTimePoint for null and returning null instead of asking leg type for a null time point --- .../server/simulation/SimulationServiceImpl.java | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/java/com.sap.sailing.server/src/com/sap/sailing/server/simulation/SimulationServiceImpl.java b/java/com.sap.sailing.server/src/com/sap/sailing/server/simulation/SimulationServiceImpl.java index ebddc01cbee..39d0b8e0ec2 100644 --- a/java/com.sap.sailing.server/src/com/sap/sailing/server/simulation/SimulationServiceImpl.java +++ b/java/com.sap.sailing.server/src/com/sap/sailing/server/simulation/SimulationServiceImpl.java @@ -379,9 +379,13 @@ public class SimulationServiceImpl implements SimulationService { // determine legtype upwind/downwind/reaching LegType legType = null; - try { - legType = trackedRace.getTrackedLeg(leg).getLegType(startTimePoint); - } catch (NoWindException e) { + if (startTimePoint != null) { + try { + legType = trackedRace.getTrackedLeg(leg).getLegType(startTimePoint); + } catch (NoWindException e) { + return null; + } + } else { return null; } From 91af95af74bbbf3d6514d997f6e49cd86a59f3e3 Mon Sep 17 00:00:00 2001 From: Axel Uhl Date: Wed, 24 Jun 2015 01:15:05 +0200 Subject: [PATCH 22/29] in CompactGPSFixImpl keep original TimePoint reference, avoiding billions of CompactTimePoint object creations; This seems too expensive, particularly in live mode. A distinction may be possible in the future between live races and replay races where for replay races the time point is also "compactified" where access isn't that frequent and server load isn't that high. See bug 3003. --- .../tracking/impl/CompactGPSFixImpl.java | 16 +---- ...ver (No Proxy, Remote Debug SAP VM).launch | 62 +++++++++---------- 2 files changed, 34 insertions(+), 44 deletions(-) diff --git a/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/tracking/impl/CompactGPSFixImpl.java b/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/tracking/impl/CompactGPSFixImpl.java index 16a009c6e86..567d2aa1ca7 100755 --- a/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/tracking/impl/CompactGPSFixImpl.java +++ b/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/tracking/impl/CompactGPSFixImpl.java @@ -8,7 +8,6 @@ import com.sap.sailing.domain.common.SpeedWithBearing; import com.sap.sailing.domain.common.impl.AbstractSpeedWithAbstractBearingImpl; import com.sap.sailing.domain.common.tracking.GPSFix; import com.sap.sse.common.TimePoint; -import com.sap.sse.common.impl.AbstractTimePoint; /** * A compact representation of a GPS fix which collects all primitive-typed attributes in one object to avoid @@ -42,7 +41,7 @@ public class CompactGPSFixImpl extends AbstractGPSFixImpl { private final double latDeg; private final double lngDeg; - private final long timePointAsMillis; + private final TimePoint timePoint; /** * Tells if in the containing {@link DynamicGPSFixTrackImpl} this fix is considered valid. This cache @@ -78,15 +77,6 @@ public class CompactGPSFixImpl extends AbstractGPSFixImpl { } } - private class CompactTimePoint extends AbstractTimePoint implements TimePoint { - private static final long serialVersionUID = -2470922642359937437L; - - @Override - public long asMillis() { - return timePointAsMillis; - } - } - private class CompactEstimatedSpeedBearing extends AbstractBearing { private static final long serialVersionUID = 8549231429037883121L; @@ -113,7 +103,7 @@ public class CompactGPSFixImpl extends AbstractGPSFixImpl { public CompactGPSFixImpl(Position position, TimePoint timePoint) { latDeg = position.getLatDeg(); lngDeg = position.getLngDeg(); - timePointAsMillis = timePoint==null?-1:timePoint.asMillis(); + this.timePoint = timePoint; } public CompactGPSFixImpl(GPSFix gpsFix) { @@ -132,7 +122,7 @@ public class CompactGPSFixImpl extends AbstractGPSFixImpl { @Override public TimePoint getTimePoint() { - return new CompactTimePoint(); + return timePoint; } @Override diff --git a/java/com.sap.sailing.server/SailingServer (No Proxy, Remote Debug SAP VM).launch b/java/com.sap.sailing.server/SailingServer (No Proxy, Remote Debug SAP VM).launch index 680a7d606b5..91ed503a8b6 100755 --- a/java/com.sap.sailing.server/SailingServer (No Proxy, Remote Debug SAP VM).launch +++ b/java/com.sap.sailing.server/SailingServer (No Proxy, Remote Debug SAP VM).launch @@ -1,31 +1,31 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + From c50288f6238ac626cf170be203d2e3e743b3d200 Mon Sep 17 00:00:00 2001 From: Axel Uhl Date: Wed, 24 Jun 2015 01:55:41 +0200 Subject: [PATCH 23/29] fixed typo in a toString() method --- .../abstractlog/race/impl/SimpleRaceLogIdentifierImpl.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/race/impl/SimpleRaceLogIdentifierImpl.java b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/race/impl/SimpleRaceLogIdentifierImpl.java index 14c9f1762bb..079e380d480 100644 --- a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/race/impl/SimpleRaceLogIdentifierImpl.java +++ b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/race/impl/SimpleRaceLogIdentifierImpl.java @@ -30,7 +30,7 @@ public class SimpleRaceLogIdentifierImpl implements SimpleRaceLogIdentifier { @Override public String toString() { - return "SimpleRaceLogIdentifier [regattaLikeParentName=" + regattaLikeParentName + ", raceCloumnName=" + raceColumnName + return "SimpleRaceLogIdentifier [regattaLikeParentName=" + regattaLikeParentName + ", raceColumnName=" + raceColumnName + ", fleetName=" + fleetName + "]"; } From c68179dd9abd7c3055f5c5f731a5a92402264568 Mon Sep 17 00:00:00 2001 From: Axel Uhl Date: Wed, 24 Jun 2015 09:57:47 +0200 Subject: [PATCH 24/29] conserve some memory by avoiding Double auto-boxing in polar service --- .../com/sap/sailing/server/impl/RacingEventServiceImpl.java | 3 +++ .../com/sap/sailing/simulator/impl/PolarDiagramBase.java | 6 +++--- 2 files changed, 6 insertions(+), 3 deletions(-) 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 f1a4c1b491c..d25f8466ba8 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 @@ -2505,6 +2505,9 @@ public class RacingEventServiceImpl implements RacingEventService, ClearStateTes logger.info("Reading competitors..."); for (Competitor competitor : ((CompetitorStore) ois.readObject()).getCompetitors()) { DynamicCompetitor dynamicCompetitor = (DynamicCompetitor) competitor; + // the following should actually be redundant because during de-serialization the Competitor objects, + // whose classes implement IsManagedByCache, should already have been got/created from/in the + // competitor store competitorStore.getOrCreateCompetitor(dynamicCompetitor.getId(), dynamicCompetitor.getName(), dynamicCompetitor.getColor(), dynamicCompetitor.getEmail(), dynamicCompetitor.getFlagImage(), dynamicCompetitor.getTeam(), dynamicCompetitor.getBoat(), dynamicCompetitor.getTimeOnTimeFactor(), diff --git a/java/com.sap.sailing.simulator/src/com/sap/sailing/simulator/impl/PolarDiagramBase.java b/java/com.sap.sailing.simulator/src/com/sap/sailing/simulator/impl/PolarDiagramBase.java index 26a0a4446a0..9d8e60ebb63 100644 --- a/java/com.sap.sailing.simulator/src/com/sap/sailing/simulator/impl/PolarDiagramBase.java +++ b/java/com.sap.sailing.simulator/src/com/sap/sailing/simulator/impl/PolarDiagramBase.java @@ -816,15 +816,15 @@ public class PolarDiagramBase implements PolarDiagram, Serializable { @Override public int compare(Bearing o1, Bearing o2) { - Double d1 = o1.getDegrees(); + double d1 = o1.getDegrees(); if (d1 < 0) { d1 = 360 + d1; } - Double d2 = o2.getDegrees(); + double d2 = o2.getDegrees(); if (d2 < 0) { d2 = 360 + d2; } - return d1.compareTo(d2); + return d1 < d2 ? -1 : d1 == d2 ? 0 : 1; } }; From ddcfc62f77e4f798feb0ea0a68886572a88f8911 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Bro=C3=9F?= Date: Wed, 24 Jun 2015 11:54:37 +0200 Subject: [PATCH 25/29] Fixes null pointer exception if there is no lastKnownLocation --- .../buoy/positioning/app/ui/fragments/BuoyFragment.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/mobile/com.sap.sailing.buoy.positioning/src/com/sap/sailing/android/buoy/positioning/app/ui/fragments/BuoyFragment.java b/mobile/com.sap.sailing.buoy.positioning/src/com/sap/sailing/android/buoy/positioning/app/ui/fragments/BuoyFragment.java index b10ceb8b4b6..a346e10fe9f 100644 --- a/mobile/com.sap.sailing.buoy.positioning/src/com/sap/sailing/android/buoy/positioning/app/ui/fragments/BuoyFragment.java +++ b/mobile/com.sap.sailing.buoy.positioning/src/com/sap/sailing/android/buoy/positioning/app/ui/fragments/BuoyFragment.java @@ -190,7 +190,10 @@ public class BuoyFragment extends BaseFragment implements LocationListener { locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, GPS_MIN_TIME, GPS_MIN_DISTANCE, this); Location initialLocation = locationManager.getLastKnownLocation(LocationManager.GPS_PROVIDER); - onLocationChanged(initialLocation); + + if (initialLocation != null) { + onLocationChanged(initialLocation); + } } public void updateMap() { From 5b20d92d09e1a4e026ead8694f8edf2b67ae9830 Mon Sep 17 00:00:00 2001 From: fmittag Date: Wed, 24 Jun 2015 14:04:11 +0200 Subject: [PATCH 26/29] some UI cleanup in RegattaStructureImport panel --- .../adminconsole/AdminConsoleEntryPoint.java | 2 +- .../StructureImportManagementPanel.java | 68 +++++++++++-------- .../sailing/gwt/ui/client/StringMessages.java | 3 +- .../gwt/ui/client/StringMessages.properties | 3 +- .../ui/client/StringMessages_de.properties | 3 +- .../ui/client/StringMessages_ru.properties | 3 +- .../ui/client/StringMessages_zh.properties | 3 +- 7 files changed, 50 insertions(+), 35 deletions(-) diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/AdminConsoleEntryPoint.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/AdminConsoleEntryPoint.java index fbc4d4f6105..7140acfc830 100755 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/AdminConsoleEntryPoint.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/AdminConsoleEntryPoint.java @@ -189,7 +189,7 @@ public class AdminConsoleEntryPoint extends AbstractSailingEntryPoint implements StructureImportManagementPanel structureImportUrlsManagementPanel = new StructureImportManagementPanel(sailingService, this, getStringMessages(), this, eventManagementPanel); panel.addToTabPanel(connectorsTabPanel, new DefaultRefreshableAdminConsolePanel(structureImportUrlsManagementPanel), - getStringMessages().structureImportUrls(), Permission.MANAGE_STRUCTURE_IMPORT_URLS); + getStringMessages().manage2Sail() + " " + getStringMessages().regattaStructureImport(), Permission.MANAGE_STRUCTURE_IMPORT_URLS); /* ADVANCED */ diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/StructureImportManagementPanel.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/StructureImportManagementPanel.java index 752505f41b9..7bcb7107698 100755 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/StructureImportManagementPanel.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/StructureImportManagementPanel.java @@ -10,7 +10,6 @@ import java.util.Map; import java.util.Map.Entry; import java.util.Set; -import com.google.gwt.dom.client.Style.Unit; import com.google.gwt.event.dom.client.ChangeEvent; import com.google.gwt.event.dom.client.ChangeHandler; import com.google.gwt.event.dom.client.ClickEvent; @@ -18,16 +17,18 @@ 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.CaptionPanel; import com.google.gwt.user.client.ui.FlexTable; import com.google.gwt.user.client.ui.FlowPanel; import com.google.gwt.user.client.ui.Grid; -import com.google.gwt.user.client.ui.HasVerticalAlignment; 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.Panel; +import com.google.gwt.user.client.ui.SimplePanel; 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.google.gwt.view.client.SelectionChangeEvent; import com.google.gwt.view.client.SelectionChangeEvent.Handler; import com.sap.sailing.domain.common.RankingMetrics; @@ -49,7 +50,7 @@ import com.sap.sse.gwt.client.controls.busyindicator.BusyIndicator; import com.sap.sse.gwt.client.controls.busyindicator.SimpleBusyIndicator; import com.sap.sse.gwt.client.dialog.DataEntryDialog.DialogCallback; -public class StructureImportManagementPanel extends FlowPanel implements RegattaStructureProvider { +public class StructureImportManagementPanel extends SimplePanel implements RegattaStructureProvider { private final SailingServiceAsync sailingService; private final ErrorReporter errorReporter; private final StringMessages stringMessages; @@ -59,7 +60,7 @@ public class StructureImportManagementPanel extends FlowPanel implements Regatta private final BusyIndicator busyIndicator; private TextBox jsonURLTextBox; private TextBox eventIDTextBox; - + private CaptionPanel regattaImportPanel; private Button listRegattasButton; private Button importDetailsButton; private VerticalPanel editSeriesPanel; @@ -105,7 +106,12 @@ public class StructureImportManagementPanel extends FlowPanel implements Regatta this.regattaListComposite = new StructureImportListComposite(this.sailingService, new RegattaSelectionModel( true), this.regattaRefresher, this, this.errorReporter, this.stringMessages); regattaListComposite.ensureDebugId("RegattaListComposite"); - createUI(); + + VerticalPanel mainPanel = new VerticalPanel(); + setWidget(mainPanel); + mainPanel.setWidth("100%"); + + createUI(mainPanel); regattaListComposite.addSelectionChangeHandler(new Handler() { @Override public void onSelectionChange(SelectionChangeEvent event) { @@ -116,12 +122,10 @@ public class StructureImportManagementPanel extends FlowPanel implements Regatta regattaStructureGrid = new FlexTable(); } - private void createUI() { + private void createUI(VerticalPanel mainPanel) { final Panel progressPanel = new FlowPanel(); progressPanel.add(busyIndicator); - Grid URLgrid = new Grid(2, 2); - Label eventIDLabel = new Label(stringMessages.event() + ":"); - Label jsonURLLabel = new Label(stringMessages.jsonUrl() + ":"); + eventIDTextBox = new TextBox(); eventIDTextBox.addChangeHandler(new ChangeHandler() { @Override @@ -161,33 +165,39 @@ public class StructureImportManagementPanel extends FlowPanel implements Regatta listRegattasAndTheirStructures(); } }); - VerticalPanel vp = new VerticalPanel(); - HorizontalPanel buttonPanel = new HorizontalPanel(); - URLgrid.setWidget(0, 0, eventIDLabel); - URLgrid.setWidget(0, 1, eventIDTextBox); - URLgrid.setWidget(1, 0, jsonURLLabel); - URLgrid.setWidget(1, 1, jsonURLTextBox); - vp.add(URLgrid); - vp.add(buttonPanel); - buttonPanel.add(listRegattasButton); - buttonPanel.add(importDetailsButton); - Grid grid = new Grid(1, 1); - vp.add(grid); + Grid eventURLGrid = new Grid(3, 2); + eventURLGrid.setWidget(0, 0, new Label(stringMessages.manage2Sail() + " " + stringMessages.event() + " " + stringMessages.id() + ":")); + eventURLGrid.setWidget(0, 1, eventIDTextBox); + eventURLGrid.setWidget(1, 0, new Label(stringMessages.jsonUrl() + ":")); + eventURLGrid.setWidget(1, 1, jsonURLTextBox); + eventURLGrid.setWidget(2, 1, listRegattasButton); + + mainPanel.add(progressPanel); + mainPanel.add(eventURLGrid); + + regattaImportPanel = new CaptionPanel(stringMessages.manage2Sail() + " " + stringMessages.event()); + mainPanel.add(regattaImportPanel); + VerticalPanel regattaImportContentPanel = new VerticalPanel(); + regattaImportPanel.setContentWidget(regattaImportContentPanel); - grid.setWidget(0, 0, regattaListComposite); - grid.getRowFormatter().setVerticalAlign(0, HasVerticalAlignment.ALIGN_TOP); - grid.getColumnFormatter().getElement(0/** 1 */).getStyle().setPaddingTop(2.0, Unit.EM); editSeriesPanel = new VerticalPanel(); - add(progressPanel); - add(vp); - add(editSeriesPanel); + + HorizontalPanel hPanel = new HorizontalPanel(); + hPanel.setSpacing(10); + hPanel.add(regattaListComposite); + hPanel.setCellWidth(regattaListComposite, "50%"); + hPanel.add(editSeriesPanel); + hPanel.setCellWidth(editSeriesPanel, "50%"); + + regattaImportContentPanel.add(hPanel); + regattaImportContentPanel.add(importDetailsButton); } /** * Adds an event selector and a "create new event" button to the {@link #editSeriesPanel} in its first row */ - private void createEventSelectionAndCreateEventButtonUI() { + private Widget createEventSelectionAndCreateEventButtonUI() { Grid grid = new Grid(1, 2); sailingEventsListBox = new ListBox(); sailingEventsListBox.setMultipleSelect(false); @@ -223,7 +233,7 @@ public class StructureImportManagementPanel extends FlowPanel implements Regatta } } }); - + return grid; } private void openEventCreateDialog() { 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 e44c20db76d..5219b6bc838 100755 --- 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 @@ -11,6 +11,7 @@ import com.sap.sse.gwt.client.DefaultRule_1_0n; public interface StringMessages extends com.sap.sse.gwt.client.StringMessages, com.sap.sse.gwt.adminconsole.StringMessages { public static final StringMessages INSTANCE = GWT.create(StringMessages.class); + String manage2Sail(); String tracTracEvents(); String swissTimingEvents(); String trackedBefore(); @@ -1164,7 +1165,7 @@ public interface StringMessages extends com.sap.sse.gwt.client.StringMessages, c @Override String errorCommunicatingWithServer(); String userManagement(); - String structureImportUrls(); + String regattaStructureImport(); String filteredBy(); String filterBy(); String editSeries(); 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 cf07bc30979..f4ecf8168c3 100755 --- 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,3 +1,4 @@ +manage2Sail=Manage2Sail tracTracEvents=TracTrac Events swissTimingEvents=SwissTiming Events trackedBefore=History of tracked events @@ -1134,7 +1135,7 @@ remoteProcedureCall=Remote Procedure Call serverReplies=Server replies errorCommunicatingWithServer=Error communicating with server userManagement=User Management -structureImportUrls=Regatta Structure Import +regattaStructureImport=Regatta Structure Import filteredBy=filtered by editSeries=Edit Series pleaseSelectAtLeastOneRegatta=Please select at least one regatta 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 89c846cffd4..047ab9163f4 100755 --- 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,3 +1,4 @@ +manage2Sail=Manage2Sail createNewEvent=Create New EventtracTracEvents=TracTrac Events swissTimingEvents=SwissTiming Events trackedBefore=Historie verfolgter Events @@ -1128,7 +1129,7 @@ remoteProcedureCall=Entfernter Prozeduraufruf serverReplies=Server antwortet errorCommunicatingWithServer=Fehler bei der Kommunikation mit dem Server userManagement=Benutzerverwaltung -structureImportUrls=Regattastruktur-Import +regattaStructureImport=Regattastruktur-Import editSeries=Serie bearbeiten filteredBy=gefiltert nach pleaseSelectAtLeastOneRegatta=Bitte wenigstens eine Regatta auswählen 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 e66d5993e43..b8b91defd14 100755 --- 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,4 +1,5 @@ # If you want new properties translated then sent this over GMR (Mark Angell ) +manage2Sail=Manage2Sail tracTracEvents=События Трак Трак swissTimingEvents=События Swiss Timing trackedBefore=Ранее Отслеженные @@ -1076,7 +1077,7 @@ remoteProcedureCall=Remote Procedure Call serverReplies=Server replies errorCommunicatingWithServer=Error communicating with server userManagement=User Management -structureImportUrls=Regatta structure import +regattaStructureImport=Regatta structure import editSeries=Edit Series filteredBy=filtered by pleaseSelectAtLeastOneRegatta=Please select at least one regatta 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 5258afc357f..45d412ca874 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,3 +1,4 @@ +manage2Sail=Manage2Sail enableRaceFilter=Enable filter finishLine=终点线 raceLabel=比赛轮次 @@ -460,7 +461,7 @@ createFlexibleLeaderboard=Create flexible leaderboard unknown=Unknown furtherSignalsAshore=Further signals ashore pleaseSelectAtLeastOneRegatta=Please select at least one regatta -structureImportUrls=Regatta Structure Import +regattaStructureImport=Regatta Structure Import raceAbandoned=放弃 sheetName=Sheet name rrs26Start=RRS26 start From f9b06480b6a87e90a64d3601f1cc12f61874ec89 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Bro=C3=9F?= Date: Wed, 24 Jun 2015 17:46:27 +0200 Subject: [PATCH 27/29] Fix debug output of buoy tender app --- .../shared/services/sending/MessageSendingService.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mobile/com.sap.sailing.android.shared/src/com/sap/sailing/android/shared/services/sending/MessageSendingService.java b/mobile/com.sap.sailing.android.shared/src/com/sap/sailing/android/shared/services/sending/MessageSendingService.java index 926bb8c7071..ee19b1e0ed3 100644 --- a/mobile/com.sap.sailing.android.shared/src/com/sap/sailing/android/shared/services/sending/MessageSendingService.java +++ b/mobile/com.sap.sailing.android.shared/src/com/sap/sailing/android/shared/services/sending/MessageSendingService.java @@ -286,7 +286,7 @@ public class MessageSendingService extends Service implements MessageSendingList int resendMillis = PrefUtils.getInt(this, R.string.preference_messageResendIntervalMillis_key, R.integer.preference_messageResendIntervalMillis_default); if (!success) { - ExLog.i(this, "MS", "success"); + ExLog.i(this, "MS", "!success"); reportApiConnectivity(APIConnectivity.transmissionError); ExLog.w(this, TAG, "Error while posting intent to server. Will persist intent..."); try { @@ -302,7 +302,7 @@ public class MessageSendingService extends Service implements MessageSendingList reportUnsentGPSFixesCount(); serviceLogger.onMessageSentFailed(); } else { - ExLog.i(this, "MS", "!success"); + ExLog.i(this, "MS", "success"); reportApiConnectivity(APIConnectivity.transmissionSuccess); ExLog.i(this, TAG, "Message successfully sent."); if (persistenceManager.areIntentsDelayed()) { From 9c3230e0cfeffb508403052d6c0234b0cb5b38b8 Mon Sep 17 00:00:00 2001 From: fmittag Date: Wed, 24 Jun 2015 18:21:30 +0200 Subject: [PATCH 28/29] added an getShortInfo() for the ProtestStartTimeEvent to see more info in the RaceLogDialog in the admin console --- .../race/impl/RaceLogProtestStartTimeEventImpl.java | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/race/impl/RaceLogProtestStartTimeEventImpl.java b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/race/impl/RaceLogProtestStartTimeEventImpl.java index 5035bbde253..0fe7db6e07f 100644 --- a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/race/impl/RaceLogProtestStartTimeEventImpl.java +++ b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/race/impl/RaceLogProtestStartTimeEventImpl.java @@ -30,4 +30,9 @@ public class RaceLogProtestStartTimeEventImpl extends RaceLogEventImpl implement return protestStartTime; } + @Override + public String getShortInfo() { + return "protestStartTime=" + protestStartTime; + } + } From 676efead1f69ffe93cf38f89ee649918a37733a2 Mon Sep 17 00:00:00 2001 From: Axel Uhl Date: Thu, 25 Jun 2015 07:58:15 +0200 Subject: [PATCH 29/29] added missing course read lock acquisition in AbstractRankingMetric; see also bug 3006 #3 --- .../domain/ranking/AbstractRankingMetric.java | 49 +++++++++++-------- 1 file changed, 28 insertions(+), 21 deletions(-) diff --git a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/ranking/AbstractRankingMetric.java b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/ranking/AbstractRankingMetric.java index 437af2fea38..63a9d72fdc8 100755 --- a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/ranking/AbstractRankingMetric.java +++ b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/ranking/AbstractRankingMetric.java @@ -10,6 +10,7 @@ import java.util.function.Supplier; import java.util.stream.StreamSupport; import com.sap.sailing.domain.base.Competitor; +import com.sap.sailing.domain.base.Course; import com.sap.sailing.domain.base.Leg; import com.sap.sailing.domain.base.Waypoint; import com.sap.sailing.domain.base.impl.CompetitorImpl; @@ -605,33 +606,39 @@ public abstract class AbstractRankingMetric implements RankingMetric { } else { Distance d = Distance.NULL; boolean count = false; // start counting only once the "from" waypoint has been found - for (final TrackedLeg trackedLeg : getTrackedRace().getTrackedLegs()) { - count = count || trackedLeg.getLeg().getFrom() == from; - if (count) { - final TrackedLegOfCompetitor trackedLegOfCompetitor = trackedLeg.getTrackedLeg(competitor); - if (trackedLegOfCompetitor.hasStartedLeg(timePoint)) { - if (!trackedLegOfCompetitor.hasFinishedLeg(timePoint)) { - // partial distance sailed: - final Position estimatedPosition = getTrackedRace().getTrack(competitor).getEstimatedPosition(timePoint, /* extrapolate */ true); - if (estimatedPosition != null) { - final Distance windwardDistanceFromLegStart = trackedLeg.getWindwardDistanceFromLegStart(estimatedPosition, cache); - final Distance legWindwardDistance = trackedLeg.getWindwardDistance(cache); - if (legWindwardDistance.compareTo(windwardDistanceFromLegStart) < 0) { - d = d.add(legWindwardDistance); - } else { - // if the competitor is currently at the mark rounding, the windward distance within the leg may - // be negative; don't reduce the distance in this case - if (windwardDistanceFromLegStart.getMeters() > 0) { - d = d.add(windwardDistanceFromLegStart); + final Course course = getTrackedRace().getRace().getCourse(); + course.lockForRead(); + try { + for (final TrackedLeg trackedLeg : getTrackedRace().getTrackedLegs()) { + count = count || trackedLeg.getLeg().getFrom() == from; + if (count) { + final TrackedLegOfCompetitor trackedLegOfCompetitor = trackedLeg.getTrackedLeg(competitor); + if (trackedLegOfCompetitor.hasStartedLeg(timePoint)) { + if (!trackedLegOfCompetitor.hasFinishedLeg(timePoint)) { + // partial distance sailed: + final Position estimatedPosition = getTrackedRace().getTrack(competitor).getEstimatedPosition(timePoint, /* extrapolate */ true); + if (estimatedPosition != null) { + final Distance windwardDistanceFromLegStart = trackedLeg.getWindwardDistanceFromLegStart(estimatedPosition, cache); + final Distance legWindwardDistance = trackedLeg.getWindwardDistance(cache); + if (legWindwardDistance.compareTo(windwardDistanceFromLegStart) < 0) { + d = d.add(legWindwardDistance); + } else { + // if the competitor is currently at the mark rounding, the windward distance within the leg may + // be negative; don't reduce the distance in this case + if (windwardDistanceFromLegStart.getMeters() > 0) { + d = d.add(windwardDistanceFromLegStart); + } } } + break; + } else { + d = d.add(trackedLeg.getWindwardDistance(cache)); } - break; - } else { - d = d.add(trackedLeg.getWindwardDistance(cache)); } } } + } finally { + course.unlockAfterRead(); } result = d; }