Merge remote-tracking branch 'origin/master' into design2015

This commit is contained in:
Steffen Schaefer committed 2015-07-20 15:48:25 +02:00
commit 0f0cda0980
38 files changed
+275 -125

No files matched your search

@@ -4,6 +4,7 @@ import java.io.Serializable;
import java.util.List;
import java.util.UUID;
import com.sap.sailing.domain.abstractlog.race.analyzing.impl.RaceLogResolver;
import com.sap.sailing.domain.base.configuration.DeviceConfigurationMatcher;
import com.sap.sailing.domain.common.MarkType;
import com.sap.sailing.domain.common.PassingInstruction;
@@ -108,4 +109,6 @@ public interface SharedDomainFactory extends CompetitorFactory {
ControlPointWithTwoMarks getOrCreateControlPointWithTwoMarks(Serializable id, String name, Mark left, Mark right);
ControlPointWithTwoMarks getOrCreateControlPointWithTwoMarks(String id, String name, Mark left, Mark right);
RaceLogResolver getRaceLogResolver();
}
@@ -16,6 +16,7 @@ import java.util.concurrent.ConcurrentHashMap;
import java.util.logging.Level;
import java.util.logging.Logger;
import com.sap.sailing.domain.abstractlog.race.analyzing.impl.RaceLogResolver;
import com.sap.sailing.domain.base.BoatClass;
import com.sap.sailing.domain.base.Competitor;
import com.sap.sailing.domain.base.CompetitorStore;
@@ -106,14 +107,18 @@ public class SharedDomainFactoryImpl implements SharedDomainFactory {
private final Set<String> mayStartWithNoUpwindLeg;
private final RaceLogResolver raceLogResolver;
/**
* Uses a transient competitor store
* @param raceLogResolver TODO
*/
public SharedDomainFactoryImpl() {
this(new TransientCompetitorStoreImpl());
public SharedDomainFactoryImpl(RaceLogResolver raceLogResolver) {
this(new TransientCompetitorStoreImpl(), raceLogResolver);
}
public SharedDomainFactoryImpl(CompetitorStore competitorStore) {
public SharedDomainFactoryImpl(CompetitorStore competitorStore, RaceLogResolver raceLogResolver) {
this.raceLogResolver = raceLogResolver;
waypointCacheReferenceQueue = new ReferenceQueue<Waypoint>();
nationalityCache = new HashMap<String, Nationality>();
markCache = new HashMap<Serializable, Mark>();
@@ -386,4 +391,8 @@ public class SharedDomainFactoryImpl implements SharedDomainFactory {
return markCache.get(markIdCache.get(toStringRepresentationOfID));
}
@Override
public RaceLogResolver getRaceLogResolver() {
return raceLogResolver;
}
}
@@ -17,7 +17,7 @@ public class DomainFactoryTest {
@Before
public void before() {
com.sap.sailing.domain.base.DomainFactory baseDomainFactory = new com.sap.sailing.domain.base.impl.DomainFactoryImpl();
com.sap.sailing.domain.base.DomainFactory baseDomainFactory = new com.sap.sailing.domain.base.impl.DomainFactoryImpl((srlid)->null);
swissTimingDomainFactory = new com.sap.sailing.domain.swisstimingadapter.impl.DomainFactoryImpl(
baseDomainFactory);
}
@@ -63,7 +63,7 @@ public class CompetitorListenerTest extends AbstractSerializationTest {
@Before
public void setUp() {
baseDomainFactory = new DomainFactoryImpl();
baseDomainFactory = new DomainFactoryImpl((srlid)->null);
competitor = TrackBasedTest.createCompetitor("Hasso");
nationalityChanged = false;
whatChangedNationality = null;
@@ -251,7 +251,7 @@ public class CompetitorListenerTest extends AbstractSerializationTest {
@Test
public void testCompetitorSerializationLosesAllExternalListeners() throws ClassNotFoundException, IOException {
DomainFactory baseDomainFactory = new DomainFactoryImpl();
DomainFactory baseDomainFactory = new DomainFactoryImpl((srlid)->null);
DynamicCompetitor clonedCompetitor = cloneBySerialization(competitor, baseDomainFactory);
clonedCompetitor.setName("Dr. Hasso Plattner");
clonedCompetitor.getBoat().setSailId("POR 40");
@@ -80,7 +80,7 @@ public class CourseUpdateTest extends AbstractTracTracLiveTest {
@Before
public void setUp() throws MalformedURLException, IOException, InterruptedException, URISyntaxException, SubscriberInitializationException, ParseException, CreateModelException {
super.setUp();
domainFactory = new DomainFactoryImpl(new com.sap.sailing.domain.base.impl.DomainFactoryImpl());
domainFactory = new DomainFactoryImpl(new com.sap.sailing.domain.base.impl.DomainFactoryImpl((srlid)->null));
domainRegatta = domainFactory.getOrCreateDefaultRegatta(EmptyRaceLogStore.INSTANCE, EmptyRegattaLogStore.INSTANCE,
getTracTracRace(), /* trackedRegattaRegistry */ null);
trackedRegatta = new DynamicTrackedRegattaImpl(domainRegatta);
@@ -118,7 +118,7 @@ public class LeaderboardCourseChangeTest {
ThresholdBasedResultDiscardingRule rule = new ThresholdBasedResultDiscardingRuleImpl(ruleRaw);
Leaderboard leaderboard = new RegattaLeaderboardImpl(mockedRegatta, rule);
DomainFactory baseDomainFactory = new DomainFactoryImpl();
DomainFactory baseDomainFactory = new DomainFactoryImpl((srlid)->null);
LeaderboardDTO leaderboardDTO = leaderboard.getLeaderboardDTO(timePoint, raceColumnNames, false,
trackedRegattaRegistry, baseDomainFactory, /* fillNetPointsUncorrected */ false);
@@ -39,7 +39,7 @@ public class MultipleClassesInRegattaTest {
@Before
public void setUp() {
domainFactory = new DomainFactoryImpl(new com.sap.sailing.domain.base.impl.DomainFactoryImpl());
domainFactory = new DomainFactoryImpl(new com.sap.sailing.domain.base.impl.DomainFactoryImpl((srlid)->null));
}
@Test
@@ -59,7 +59,7 @@ public class OfflineSerializationTest extends AbstractSerializationTest {
*/
@Test
public void testHashCodeOfSerializedPairIsConsistent() throws ClassNotFoundException, IOException {
DomainFactory receiverDomainFactory = new DomainFactoryImpl();
DomainFactory receiverDomainFactory = new DomainFactoryImpl((srlid)->null);
final Throwable s1 = new Throwable();
final Throwable s2 = new Throwable();
com.sap.sse.common.Util.Pair<Throwable, Throwable> p =
@@ -91,7 +91,7 @@ public class OfflineSerializationTest extends AbstractSerializationTest {
*/
@Test
public void testSerializingIntArray() throws ClassNotFoundException, IOException {
DomainFactory receiverDomainFactory = new DomainFactoryImpl();
DomainFactory receiverDomainFactory = new DomainFactoryImpl((srlid)->null);
int[] intArray = new int[] { 5, 8 };
int[] clone = cloneBySerialization(intArray, receiverDomainFactory);
assertTrue(Arrays.equals(intArray, clone));
@@ -99,7 +99,7 @@ public class OfflineSerializationTest extends AbstractSerializationTest {
@Test
public void testSerializingEventWithLeaderboardGroups() throws ClassNotFoundException, IOException {
DomainFactory receiverDomainFactory = new DomainFactoryImpl();
DomainFactory receiverDomainFactory = new DomainFactoryImpl((srlid)->null);
Event e = new EventImpl("Event Name", MillisecondsTimePoint.now(), MillisecondsTimePoint.now().plus(
Duration.ONE_DAY.times(10)), "At Home", /* is public */true, UUID.randomUUID());
LeaderboardGroup lg1 = new LeaderboardGroupImpl("LG1", "LG1 Description", /* displayName */ null, /* displayGroupsInReverseOrder */ false, Collections.<Leaderboard> emptyList());
@@ -117,7 +117,7 @@ public class OfflineSerializationTest extends AbstractSerializationTest {
*/
@Test
public void testSerializingResultDiscardingRuleImpl() throws ClassNotFoundException, IOException {
DomainFactory receiverDomainFactory = new DomainFactoryImpl();
DomainFactory receiverDomainFactory = new DomainFactoryImpl((srlid)->null);
ThresholdBasedResultDiscardingRuleImpl rdri = new ThresholdBasedResultDiscardingRuleImpl(new int[] { 5, 8 });
ThresholdBasedResultDiscardingRuleImpl clone = cloneBySerialization(rdri, receiverDomainFactory);
assertTrue(Arrays.equals(rdri.getDiscardIndexResultsStartingWithHowManyRaces(),
@@ -136,7 +136,7 @@ public class OfflineSerializationTest extends AbstractSerializationTest {
final double FACTOR = 2.0;
overallLeaderboard.getRaceColumnByName("Test Leaderboard").setFactor(FACTOR);
DomainFactory receiverDomainFactory = new DomainFactoryImpl();
DomainFactory receiverDomainFactory = new DomainFactoryImpl((srlid)->null);
LeaderboardGroup clone = cloneBySerialization(leaderboardGroup, receiverDomainFactory);
assertEquals(FACTOR, overallLeaderboard.getRaceColumnByName("Test Leaderboard").getFactor(), 0.00000001);
assertEquals(FACTOR, clone.getOverallLeaderboard().getRaceColumnByName("Test Leaderboard").getFactor(), 0.00000001);
@@ -144,8 +144,8 @@ public class OfflineSerializationTest extends AbstractSerializationTest {
@Test
public void testIdentityStabilityOfMarkSerialization() throws ClassNotFoundException, IOException {
DomainFactory senderDomainFactory = new DomainFactoryImpl();
DomainFactory receiverDomainFactory = new DomainFactoryImpl();
DomainFactory senderDomainFactory = new DomainFactoryImpl((srlid)->null);
DomainFactory receiverDomainFactory = new DomainFactoryImpl((srlid)->null);
Mark sendersMark1 = senderDomainFactory.getOrCreateMark("TestBuoy1");
Mark receiversMark1 = cloneBySerialization(sendersMark1, receiverDomainFactory);
Mark receiversSecondCopyOfMark1 = cloneBySerialization(sendersMark1, receiverDomainFactory);
@@ -154,8 +154,8 @@ public class OfflineSerializationTest extends AbstractSerializationTest {
@Test
public void testIdentityStabilityOfWaypointSerialization() throws ClassNotFoundException, IOException {
DomainFactory senderDomainFactory = new DomainFactoryImpl();
DomainFactory receiverDomainFactory = new DomainFactoryImpl();
DomainFactory senderDomainFactory = new DomainFactoryImpl((srlid)->null);
DomainFactory receiverDomainFactory = new DomainFactoryImpl((srlid)->null);
Mark sendersMark1 = senderDomainFactory.getOrCreateMark("TestBuoy1");
Waypoint sendersWaypoint1 = senderDomainFactory.createWaypoint(sendersMark1, /*passingInstruction*/null);
Waypoint receiversWaypoint1 = cloneBySerialization(sendersWaypoint1, receiverDomainFactory);
@@ -165,8 +165,8 @@ public class OfflineSerializationTest extends AbstractSerializationTest {
@Test
public void testIdentityStabilityOfBoatClassSerialization() throws ClassNotFoundException, IOException {
DomainFactory senderDomainFactory = new DomainFactoryImpl();
DomainFactory receiverDomainFactory = new DomainFactoryImpl();
DomainFactory senderDomainFactory = new DomainFactoryImpl((srlid)->null);
DomainFactory receiverDomainFactory = new DomainFactoryImpl((srlid)->null);
BoatClass sendersBoatClass1 = senderDomainFactory.getOrCreateBoatClass("49er", /* typicallyStartsUpwind */ true);
BoatClass receiversBoatClass1 = cloneBySerialization(sendersBoatClass1, receiverDomainFactory);
BoatClass receiversSecondCopyOfBoatClass1 = cloneBySerialization(sendersBoatClass1, receiverDomainFactory);
@@ -175,8 +175,8 @@ public class OfflineSerializationTest extends AbstractSerializationTest {
@Test
public void testIdentityStabilityOfNationalitySerialization() throws ClassNotFoundException, IOException {
DomainFactory senderDomainFactory = new DomainFactoryImpl();
DomainFactory receiverDomainFactory = new DomainFactoryImpl();
DomainFactory senderDomainFactory = new DomainFactoryImpl((srlid)->null);
DomainFactory receiverDomainFactory = new DomainFactoryImpl((srlid)->null);
Nationality sendersNationality1 = senderDomainFactory.getOrCreateNationality("GER");
Nationality receiversNationality1 = cloneBySerialization(sendersNationality1, receiverDomainFactory);
Nationality receiversSecondCopyOfNationality1 = cloneBySerialization(sendersNationality1, receiverDomainFactory);
@@ -185,8 +185,8 @@ public class OfflineSerializationTest extends AbstractSerializationTest {
@Test
public void testIdentityStabilityOfCompetitorSerialization() throws ClassNotFoundException, IOException {
DomainFactory senderDomainFactory = new DomainFactoryImpl();
DomainFactory receiverDomainFactory = new DomainFactoryImpl();
DomainFactory senderDomainFactory = new DomainFactoryImpl((srlid)->null);
DomainFactory receiverDomainFactory = new DomainFactoryImpl((srlid)->null);
String competitorName = "Tina Maximiliane Lutz";
Competitor sendersCompetitor1 = new CompetitorImpl(123, competitorName, Color.RED, null, null, new TeamImpl("STG", Collections.singleton(
new PersonImpl(competitorName, senderDomainFactory.getOrCreateNationality("GER"),
@@ -201,8 +201,8 @@ public class OfflineSerializationTest extends AbstractSerializationTest {
@Test
public void ensureSameObjectWrittenTwiceComesOutIdentical() throws ClassNotFoundException, IOException {
final DomainFactoryImpl senderDomainFactory = new DomainFactoryImpl();
DomainFactory receiverDomainFactory = new DomainFactoryImpl();
final DomainFactoryImpl senderDomainFactory = new DomainFactoryImpl((srlid)->null);
DomainFactory receiverDomainFactory = new DomainFactoryImpl((srlid)->null);
Nationality n = senderDomainFactory.getOrCreateNationality("GER");
Object[] copies = cloneManyBySerialization(receiverDomainFactory, n, n);
assertEquals(2, copies.length);
@@ -86,7 +86,7 @@ public abstract class OnlineTracTracBasedTest extends AbstractTracTracLiveTest {
@Before
public void setUp() throws MalformedURLException, IOException, InterruptedException, URISyntaxException, ParseException, SubscriberInitializationException, CreateModelException {
domainFactory = new DomainFactoryImpl(new com.sap.sailing.domain.base.impl.DomainFactoryImpl());
domainFactory = new DomainFactoryImpl(new com.sap.sailing.domain.base.impl.DomainFactoryImpl((srlid)->null));
// keep superclass implementation from automatically setting up for a Weymouth event and force subclasses
// to select a race
}
@@ -219,7 +219,7 @@ public abstract class OnlineTracTracBasedTest extends AbstractTracTracLiveTest {
throws FileNotFoundException, MalformedURLException, URISyntaxException, SubscriberInitializationException, CreateModelException {
super.setUp(paramUrl, liveUri, storedUri);
if (domainFactory == null) {
domainFactory = new DomainFactoryImpl(new com.sap.sailing.domain.base.impl.DomainFactoryImpl());
domainFactory = new DomainFactoryImpl(new com.sap.sailing.domain.base.impl.DomainFactoryImpl((srlid)->null));
}
domainEvent = domainFactory.getOrCreateDefaultRegatta(EmptyRaceLogStore.INSTANCE, EmptyRegattaLogStore.INSTANCE,
getTracTracRace(), /* trackedRegattaRegistry */ null);
@@ -38,7 +38,7 @@ public class UnicodeCharactersInCompetitorNamesTest {
@Before
public void setUp() {
domainFactory = new DomainFactoryImpl(new com.sap.sailing.domain.base.impl.DomainFactoryImpl());
domainFactory = new DomainFactoryImpl(new com.sap.sailing.domain.base.impl.DomainFactoryImpl((srlid)->null));
}
public static void main(String[] args) throws URISyntaxException, IOException, InterruptedException, CreateModelException, SubscriberInitializationException {
@@ -23,6 +23,7 @@ import com.sap.sailing.domain.base.RaceDefinition;
import com.sap.sailing.domain.base.Regatta;
import com.sap.sailing.domain.base.RegattaListener;
import com.sap.sailing.domain.base.Series;
import com.sap.sailing.domain.base.SharedDomainFactory;
import com.sap.sailing.domain.base.Sideline;
import com.sap.sailing.domain.base.SpeedWithConfidence;
import com.sap.sailing.domain.base.Waypoint;
@@ -75,6 +76,7 @@ import com.sap.sailing.domain.tracking.WindTrack;
import com.sap.sailing.domain.tracking.WindWithConfidence;
import com.sap.sailing.domain.tracking.impl.WindTrackImpl;
import com.sap.sse.common.Duration;
import com.sap.sse.common.IsManagedByCache;
import com.sap.sse.common.TimePoint;
import com.sap.sse.common.Util;
@@ -985,4 +987,9 @@ public class MockedTrackedRace implements DynamicTrackedRace {
public RankingMetric getRankingMetric() {
return null;
}
@Override
public IsManagedByCache<SharedDomainFactory> resolve(SharedDomainFactory domainFactory) {
return this;
}
}
@@ -14,6 +14,7 @@ import com.sap.sailing.domain.base.Leg;
import com.sap.sailing.domain.base.Mark;
import com.sap.sailing.domain.base.RaceDefinition;
import com.sap.sailing.domain.base.Regatta;
import com.sap.sailing.domain.base.SharedDomainFactory;
import com.sap.sailing.domain.base.Sideline;
import com.sap.sailing.domain.base.SpeedWithConfidence;
import com.sap.sailing.domain.base.Waypoint;
@@ -57,6 +58,7 @@ import com.sap.sailing.domain.tracking.WindTrack;
import com.sap.sailing.domain.tracking.WindWithConfidence;
import com.sap.sailing.domain.tracking.impl.DynamicTrackedRegattaImpl;
import com.sap.sse.common.Duration;
import com.sap.sse.common.IsManagedByCache;
import com.sap.sse.common.TimePoint;
import com.sap.sse.common.Util;
@@ -646,4 +648,9 @@ public class MockedTrackedRaceWithStartTimeAndRanks implements TrackedRace {
@Override
public void detachRaceExecutionOrderProvider(RaceExecutionOrderProvider raceExecutionOrderProvider) {
}
@Override
public IsManagedByCache<SharedDomainFactory> resolve(SharedDomainFactory domainFactory) {
return this;
}
}
@@ -31,7 +31,7 @@ public interface DomainFactory extends SharedDomainFactory {
* the <code>RacingEventService.getBaseDomainFactory()</code> instead which should be the single instance used
* by all other services linked to the <code>RacingEventService</code>.
*/
static DomainFactory INSTANCE = new DomainFactoryImpl();
static DomainFactory INSTANCE = new DomainFactoryImpl((srlid)->null);
MarkPassing createMarkPassing(TimePoint timePoint, Waypoint waypoint, Competitor competitor);
@@ -8,6 +8,7 @@ import java.util.Iterator;
import java.util.List;
import java.util.logging.Logger;
import com.sap.sailing.domain.abstractlog.race.analyzing.impl.RaceLogResolver;
import com.sap.sailing.domain.base.Competitor;
import com.sap.sailing.domain.base.CompetitorStore;
import com.sap.sailing.domain.base.DomainFactory;
@@ -67,12 +68,12 @@ public class DomainFactoryImpl extends SharedDomainFactoryImpl implements Domain
/**
* Uses a transient competitor store
*/
public DomainFactoryImpl() {
super(new TransientCompetitorStoreImpl());
public DomainFactoryImpl(RaceLogResolver raceLogResolver) {
super(new TransientCompetitorStoreImpl(), raceLogResolver);
}
public DomainFactoryImpl(CompetitorStore competitorStore) {
super(competitorStore);
public DomainFactoryImpl(CompetitorStore competitorStore, RaceLogResolver raceLogResolver) {
super(competitorStore, raceLogResolver);
}
@Override
@@ -1670,8 +1670,9 @@ public abstract class AbstractSimpleLeaderboardImpl implements Leaderboard, Race
result.estimatedTimeToNextWaypointInSeconds = estimatedTimeToNextMarkInSeconds==null?null:estimatedTimeToNextMarkInSeconds.asSeconds();
result.timeInMilliseconds = time.asMillis();
result.finished = trackedLeg.hasFinishedLeg(timePoint);
final TimePoint legFinishTime = trackedLeg.getFinishTime();
result.correctedTotalTime = trackedLeg.hasStartedLeg(timePoint) ? trackedLeg.getTrackedLeg().getTrackedRace().getRankingMetric().getCorrectedTime(trackedLeg.getCompetitor(),
trackedLeg.hasFinishedLeg(timePoint) ? trackedLeg.getFinishTime() : timePoint, cache) : null;
trackedLeg.hasFinishedLeg(timePoint) ? legFinishTime : timePoint, cache) : null;
// fetch the leg gap in own corrected time from the ranking metric
final Duration gapToLeaderInOwnTime = trackedLeg.getTrackedLeg().getTrackedRace().getRankingMetric().
getLegGapToLegLeaderInOwnTime(trackedLeg, timePoint, rankingInfo, cache);
@@ -1721,8 +1722,8 @@ public abstract class AbstractSimpleLeaderboardImpl implements Leaderboard, Race
case TACK:
case JIBE:
case PENALTY_CIRCLE:
if (!maneuver.getTimePoint().before(startOfLeg) && (!trackedLeg.hasFinishedLeg(timePoint) ||
maneuver.getTimePoint().before(trackedLeg.getFinishTime()))) {
if (!maneuver.getTimePoint().before(startOfLeg) && (legFinishTime == null || legFinishTime.after(timePoint) ||
maneuver.getTimePoint().before(legFinishTime))) {
if (maneuver.getManeuverLoss() != null) {
result.numberOfManeuvers.put(maneuver.getType(),
result.numberOfManeuvers.get(maneuver.getType()) + 1);
@@ -1,6 +1,7 @@
package com.sap.sailing.domain.leaderboard.impl;
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.Set;
import com.sap.sailing.domain.base.Competitor;
@@ -43,7 +44,7 @@ public class PerSeriesResultDiscardingRuleImpl implements ResultDiscardingRule {
}
private Iterable<RaceColumn> getColumnsToConsiderInSeries(Series series, Iterable<RaceColumn> allRaceColumnsToConsider) {
Set<RaceColumn> result = new HashSet<>();
Set<RaceColumn> result = new LinkedHashSet<>();
for (RaceColumn seriesColumn : series.getRaceColumns()) {
if (Util.contains(allRaceColumnsToConsider, seriesColumn)) {
result.add(seriesColumn);
@@ -593,7 +593,9 @@ public abstract class AbstractRankingMetric implements RankingMetric {
* For each leg the total windward distance sailed is limited to the leg's windward distance at its
* {@link TrackedLeg#getReferenceTimePoint() reference time point}. This ensures that significantly "overstaying" the lay lines
* doesn't let a competitor rank better than one who already passed the mark but traveled little windward distance in
* the next leg.
* the next leg.<p>
*
* If mark positions along the way are not known, the windward distance of those legs will be counted as 0.
*
* @param timePoint needed to determine <code>competitor</code>'s position at that time point; note that the
* time point for wind approximation is taken to be a reference time point selected based on the mark passings
@@ -620,7 +622,7 @@ public abstract class AbstractRankingMetric implements RankingMetric {
if (estimatedPosition != null) {
final Distance windwardDistanceFromLegStart = trackedLeg.getWindwardDistanceFromLegStart(estimatedPosition, cache);
final Distance legWindwardDistance = trackedLeg.getWindwardDistance(cache);
if (legWindwardDistance.compareTo(windwardDistanceFromLegStart) < 0) {
if (legWindwardDistance != null && 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
@@ -632,7 +634,10 @@ public abstract class AbstractRankingMetric implements RankingMetric {
}
break;
} else {
d = d.add(trackedLeg.getWindwardDistance(cache));
final Distance legWindwardDistance = trackedLeg.getWindwardDistance(cache);
if (legWindwardDistance != null) {
d = d.add(legWindwardDistance);
}
}
}
}
@@ -17,6 +17,7 @@ import com.sap.sailing.domain.base.Leg;
import com.sap.sailing.domain.base.Mark;
import com.sap.sailing.domain.base.RaceDefinition;
import com.sap.sailing.domain.base.Regatta;
import com.sap.sailing.domain.base.SharedDomainFactory;
import com.sap.sailing.domain.base.Sideline;
import com.sap.sailing.domain.base.SpeedWithConfidence;
import com.sap.sailing.domain.base.Waypoint;
@@ -46,6 +47,7 @@ import com.sap.sailing.domain.ranking.RankingMetric;
import com.sap.sailing.domain.ranking.RankingMetric.RankingInfo;
import com.sap.sailing.domain.tracking.impl.TrackedRaceImpl;
import com.sap.sse.common.Duration;
import com.sap.sse.common.IsManagedByCache;
import com.sap.sse.common.TimePoint;
import com.sap.sse.common.Util;
@@ -64,7 +66,7 @@ import com.sap.sse.common.Util;
* @author Axel Uhl (d043530)
*
*/
public interface TrackedRace extends Serializable {
public interface TrackedRace extends Serializable, IsManagedByCache<SharedDomainFactory> {
final long MAX_TIME_BETWEEN_START_AND_FIRST_MARK_PASSING_IN_MILLISECONDS = 30000;
final long DEFAULT_LIVE_DELAY_IN_MILLISECONDS = 5000;
@@ -454,27 +454,30 @@ public class TrackedLegImpl implements TrackedLeg {
Distance getWindwardDistance(final Position pos1, final Position pos2, TimePoint at, WindPositionMode windPositionMode, WindLegTypeAndLegBearingCache cache) {
Distance result;
try {
final LegType legType = cache.getLegType(this, at);
if (legType != LegType.REACHING) { // upwind or downwind
final Position effectivePosition = getEffectiveWindPosition(
() -> pos1.translateGreatCircle(pos1.getBearingGreatCircle(pos2), pos1.getDistance(pos2).scale(0.5)),
at, windPositionMode);
Wind wind = getTrackedRace().getWind(effectivePosition, at);
if (wind == null) {
result = pos2.alongTrackDistance(pos1, cache.getLegBearing(this, at));
if (pos1 == null || pos2 == null) {
result = null;
} else {
try {
final LegType legType = cache.getLegType(this, at);
if (legType != LegType.REACHING) { // upwind or downwind
final Position effectivePosition = getEffectiveWindPosition(() -> pos1.translateGreatCircle(
pos1.getBearingGreatCircle(pos2), pos1.getDistance(pos2).scale(0.5)), at, windPositionMode);
Wind wind = getTrackedRace().getWind(effectivePosition, at);
if (wind == null) {
result = pos2.alongTrackDistance(pos1, cache.getLegBearing(this, at));
} else {
Position projectionToLineThroughPos2 = pos1.projectToLineThrough(pos2, wind.getBearing());
result = pos2.alongTrackDistance(projectionToLineThroughPos2,
legType == LegType.UPWIND ? wind.getFrom() : wind.getBearing());
}
} else {
Position projectionToLineThroughPos2 = pos1.projectToLineThrough(pos2, wind.getBearing());
result = pos2.alongTrackDistance(projectionToLineThroughPos2,
legType == LegType.UPWIND ? wind.getFrom() : wind.getBearing());
// reaching leg, return distance projected onto leg's bearing
result = pos2.alongTrackDistance(pos1, cache.getLegBearing(this, at));
}
} else {
// reaching leg, return distance projected onto leg's bearing
} catch (NoWindException e) {
// no wind information; use along-track distance as fallback
result = pos2.alongTrackDistance(pos1, cache.getLegBearing(this, at));
}
} catch (NoWindException e) {
// no wind information; use along-track distance as fallback
result = pos2.alongTrackDistance(pos1, cache.getLegBearing(this, at));
}
return result;
}
@@ -54,6 +54,7 @@ import com.sap.sailing.domain.base.CourseListener;
import com.sap.sailing.domain.base.Leg;
import com.sap.sailing.domain.base.Mark;
import com.sap.sailing.domain.base.RaceDefinition;
import com.sap.sailing.domain.base.SharedDomainFactory;
import com.sap.sailing.domain.base.Sideline;
import com.sap.sailing.domain.base.SpeedWithBearingWithConfidence;
import com.sap.sailing.domain.base.SpeedWithConfidence;
@@ -134,6 +135,7 @@ import com.sap.sailing.domain.tracking.WindStore;
import com.sap.sailing.domain.tracking.WindTrack;
import com.sap.sailing.domain.tracking.WindWithConfidence;
import com.sap.sse.common.Duration;
import com.sap.sse.common.IsManagedByCache;
import com.sap.sse.common.NoCorrespondingServiceRegisteredException;
import com.sap.sse.common.TimePoint;
import com.sap.sse.common.Timed;
@@ -1022,14 +1024,16 @@ public abstract class TrackedRaceImpl extends TrackedRaceWithWindEssentials impl
&& timePoint.compareTo(markPassings.last().getTimePoint()) > 0) {
// competitor has finished race at or before the requested time point; use time point of crossing the finish line
end = markPassings.last().getTimePoint();
} else if ((trackedLegOfCompetitor=getTrackedLeg(competitor, timePoint)) == null ||
(!trackedLegOfCompetitor.hasFinishedLeg(getEndOfTracking())
&& ((getEndOfTracking() != null && timePoint.after(getEndOfTracking()))
|| getStatus().getStatus() == TrackedRaceStatusEnum.FINISHED))) {
// If the race is no longer tracking and hence no more data can be expected, and the competitor
// hasn't finished a leg after the requested time point, no valid distance traveled can be determined
// for the competitor in this race the the time point requested
end = null;
} else {
final TimePoint endOfTracking = getEndOfTracking();
if ((trackedLegOfCompetitor=getTrackedLeg(competitor, timePoint)) == null ||
(endOfTracking != null && !trackedLegOfCompetitor.hasFinishedLeg(endOfTracking)
&& (timePoint.after(endOfTracking) || getStatus().getStatus() == TrackedRaceStatusEnum.FINISHED))) {
// If the race is no longer tracking and hence no more data can be expected, and the competitor
// hasn't finished a leg after the requested time point, no valid distance traveled can be determined
// for the competitor in this race the the time point requested
end = null;
}
}
if (end == null) {
result = null;
@@ -3692,4 +3696,14 @@ public abstract class TrackedRaceImpl extends TrackedRaceWithWindEssentials impl
public void setRaceLogResolver(RaceLogResolver raceLogResolver) {
this.raceLogResolver = raceLogResolver;
}
/**
* When given the opportunity to resolve after de-serialization, grabs the {@link RaceLogResolver} from the
* {@link SharedDomainFactory} because the field is transient and needs filling after de-serialization.
*/
@Override
public IsManagedByCache<SharedDomainFactory> resolve(SharedDomainFactory domainFactory) {
this.raceLogResolver = domainFactory.getRaceLogResolver();
return this;
}
}
@@ -17,6 +17,7 @@ import com.sap.sailing.domain.base.Leg;
import com.sap.sailing.domain.base.Mark;
import com.sap.sailing.domain.base.RaceDefinition;
import com.sap.sailing.domain.base.Regatta;
import com.sap.sailing.domain.base.SharedDomainFactory;
import com.sap.sailing.domain.base.Sideline;
import com.sap.sailing.domain.base.SpeedWithConfidence;
import com.sap.sailing.domain.base.Waypoint;
@@ -63,6 +64,7 @@ import com.sap.sailing.domain.tracking.WindTrack;
import com.sap.sailing.domain.tracking.WindWithConfidence;
import com.sap.sailing.domain.tracking.impl.WindTrackImpl;
import com.sap.sse.common.Duration;
import com.sap.sse.common.IsManagedByCache;
import com.sap.sse.common.TimePoint;
import com.sap.sse.common.Util;
@@ -783,4 +785,9 @@ public class MockedTrackedRace implements DynamicTrackedRace {
@Override
public void attachRaceExecutionProvider(RaceExecutionOrderProvider raceExecutionOrderProvider) {
}
@Override
public IsManagedByCache<SharedDomainFactory> resolve(SharedDomainFactory domainFactory) {
return this;
}
}
@@ -3,6 +3,7 @@
<booleanAttribute key="com.google.gdt.eclipse.core.RUN_SERVER" value="false"/>
<stringAttribute key="com.google.gdt.eclipse.suiteMainTypeProcessor.PREVIOUSLY_SET_MAIN_TYPE_NAME" value="com.google.gwt.dev.GWTShell"/>
<booleanAttribute key="com.google.gdt.eclipse.suiteWarArgumentProcessor.IS_WAR_FROM_PROJECT_PROPERTIES" value="true"/>
<booleanAttribute key="com.google.gwt.eclipse.core.CODE_SERVER_PORT_AUTO" value="true"/>
<listAttribute key="com.google.gwt.eclipse.core.ENTRY_POINT_MODULES">
<listEntry value="com.sap.sailing.gwt.ui.EmbeddedMapAndWindChart"/>
<listEntry value="com.sap.sailing.gwt.ui.RaceBoard"/>
@@ -71,7 +72,7 @@
<booleanAttribute key="org.eclipse.jdt.launching.DEFAULT_CLASSPATH" value="false"/>
<stringAttribute key="org.eclipse.jdt.launching.JRE_CONTAINER" value="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8"/>
<stringAttribute key="org.eclipse.jdt.launching.MAIN_TYPE" value="com.google.gwt.dev.DevMode"/>
<stringAttribute key="org.eclipse.jdt.launching.PROGRAM_ARGUMENTS" value="-superDevMode -incremental -workDir &quot;${project_loc:com.sap.sailing.gwt.ui}/.tmp/gwt-work&quot; -war &quot;${project_loc:com.sap.sailing.gwt.ui}&quot; -noserver -remoteUI &quot;${gwt_remote_ui_server_port}:${unique_id}&quot; -logLevel INFO -codeServerPort 9997 -startupUrl /gwt/Home.html com.sap.sailing.gwt.home.Home -startupUrl /gwt/AdminConsole.html com.sap.sailing.gwt.ui.AdminConsole -startupUrl /gwt/LeaderboardEditing.html com.sap.sailing.gwt.ui.LeaderboardEditing -startupUrl /gwt/Leaderboard.html com.sap.sailing.gwt.ui.Leaderboard -startupUrl /gwt/Spectator.html com.sap.sailing.gwt.ui.Spectator -startupUrl /gwt/EmbeddedMapAndWindChart com.sap.sailing.gwt.ui.EmbeddedMapAndWindChart -startupUrl /gwt/RaceBoard.html com.sap.sailing.gwt.ui.RaceBoard -startupUrl /gwt/PolarSheets.html com.sap.sailing.gwt.ui.PolarSheets -startupUrl /gwt/RegattaOverview.html com.sap.sailing.gwt.regattaoverview.RegattaOverview -startupUrl /gwt/DataMining.html com.sap.sailing.gwt.ui.DataMining -startupUrl /gwt/Simulator.html com.sap.sailing.gwt.ui.Simulator -startupUrl /gwt/VideoPopup.html com.sap.sailing.gwt.ui.VideoPopup com.sap.sailing.gwt.home.Desktop com.sap.sailing.gwt.home.Home com.sap.sailing.gwt.ui.AdminConsole com.sap.sailing.gwt.AutoPlay com.sap.sailing.gwt.ui.YoutubePopup com.sap.sailing.gwt.ui.Simulator com.sap.sailing.gwt.ui.Leaderboard com.sap.sailing.gwt.ui.PolarSheets com.sap.sailing.gwt.regattaoverview.RegattaOverview com.sap.sailing.gwt.ui.Spectator com.sap.sailing.gwt.ui.LeaderboardEditing com.sap.sailing.gwt.ui.DataMining com.sap.sailing.gwt.ui.RaceBoard com.sap.sailing.gwt.ui.EmbeddedMapAndWindChart"/>
<stringAttribute key="org.eclipse.jdt.launching.PROGRAM_ARGUMENTS" value="-superDevMode -incremental -workDir &quot;${project_loc:com.sap.sailing.gwt.ui}/.tmp/gwt-work&quot; -war &quot;${project_loc:com.sap.sailing.gwt.ui}&quot; -noserver -remoteUI &quot;${gwt_remote_ui_server_port}:${unique_id}&quot; -logLevel INFO -codeServerPort auto -startupUrl /gwt/Home.html com.sap.sailing.gwt.home.Home -startupUrl /gwt/AdminConsole.html com.sap.sailing.gwt.ui.AdminConsole -startupUrl /gwt/LeaderboardEditing.html com.sap.sailing.gwt.ui.LeaderboardEditing -startupUrl /gwt/Leaderboard.html com.sap.sailing.gwt.ui.Leaderboard -startupUrl /gwt/Spectator.html com.sap.sailing.gwt.ui.Spectator -startupUrl /gwt/EmbeddedMapAndWindChart com.sap.sailing.gwt.ui.EmbeddedMapAndWindChart -startupUrl /gwt/RaceBoard.html com.sap.sailing.gwt.ui.RaceBoard -startupUrl /gwt/PolarSheets.html com.sap.sailing.gwt.ui.PolarSheets -startupUrl /gwt/RegattaOverview.html com.sap.sailing.gwt.regattaoverview.RegattaOverview -startupUrl /gwt/DataMining.html com.sap.sailing.gwt.ui.DataMining -startupUrl /gwt/Simulator.html com.sap.sailing.gwt.ui.Simulator -startupUrl /gwt/VideoPopup.html com.sap.sailing.gwt.ui.VideoPopup com.sap.sailing.gwt.home.Desktop com.sap.sailing.gwt.home.Home com.sap.sailing.gwt.ui.AdminConsole com.sap.sailing.gwt.AutoPlay com.sap.sailing.gwt.ui.YoutubePopup com.sap.sailing.gwt.ui.Simulator com.sap.sailing.gwt.ui.Leaderboard com.sap.sailing.gwt.ui.PolarSheets com.sap.sailing.gwt.regattaoverview.RegattaOverview com.sap.sailing.gwt.ui.Spectator com.sap.sailing.gwt.ui.LeaderboardEditing com.sap.sailing.gwt.ui.DataMining com.sap.sailing.gwt.ui.RaceBoard com.sap.sailing.gwt.ui.EmbeddedMapAndWindChart"/>
<stringAttribute key="org.eclipse.jdt.launching.PROJECT_ATTR" value="com.sap.sailing.gwt.ui"/>
<stringAttribute key="org.eclipse.jdt.launching.VM_ARGUMENTS" value="-Xms1024m -Xmx3072m"/>
</launchConfiguration>
@@ -36,7 +36,7 @@ public class StoreCompetitorTest extends AbstractMongoDBTest {
@Before
public void setUp() {
// clear the domainFactory competitor store for a clean start:
domainFactory = new DomainFactoryImpl();
domainFactory = new DomainFactoryImpl((srlid)->null);
}
private void dropCompetitorCollection() {
@@ -347,7 +347,7 @@ public class TestStoringAndRetrievingLeaderboards extends AbstractMongoDBTest {
final int[] discardIndexResultsStartingWithHowManyRaces = new int[] { 5, 8 };
FlexibleLeaderboardImpl leaderboard = new FlexibleLeaderboardImpl(leaderboardName, new ThresholdBasedResultDiscardingRuleImpl(discardIndexResultsStartingWithHowManyRaces),
new LowPoint(), null);
final DomainFactory domainFactory = new DomainFactoryImpl();
final DomainFactory domainFactory = new DomainFactoryImpl((srlid)->null);
// create the competitor through the competitor store/factory here so that the DomainObjectFactory finds it and
// resolves the score corrections appropriate
Competitor competitor = domainFactory.getOrCreateCompetitor(123, "$$$Dr. Wolfgang+Hunger$$$", Color.RED, "someone@nowhere.de", null, new TeamImpl("STG", Collections.singleton(
@@ -1,7 +1,10 @@
package com.sap.sailing.server.replication.test;
import com.sap.sailing.domain.abstractlog.race.analyzing.impl.RaceLogResolver;
import com.sap.sailing.domain.base.CompetitorStore;
import com.sap.sailing.domain.base.DomainFactory;
import com.sap.sailing.domain.base.impl.DomainFactoryImpl;
import com.sap.sailing.domain.persistence.DomainObjectFactory;
import com.sap.sailing.domain.persistence.MongoObjectFactory;
import com.sap.sailing.domain.persistence.PersistenceFactory;
import com.sap.sailing.domain.persistence.media.MediaDBFactory;
@@ -9,6 +12,7 @@ import com.sap.sailing.domain.racelog.tracking.EmptyGPSFixStore;
import com.sap.sailing.domain.tracking.impl.EmptyWindStore;
import com.sap.sailing.server.RacingEventService;
import com.sap.sailing.server.impl.RacingEventServiceImpl;
import com.sap.sailing.server.impl.RacingEventServiceImpl.ConstructorParameters;
import com.sap.sse.mongodb.MongoDBService;
public abstract class AbstractServerReplicationTest extends com.sap.sse.replication.testsupport.AbstractServerWithSingleServiceReplicationTest<RacingEventService, RacingEventServiceImpl> {
@@ -42,17 +46,35 @@ public abstract class AbstractServerReplicationTest extends com.sap.sse.replicat
@Override
public RacingEventServiceImpl createNewMaster() {
return new RacingEventServiceImpl(PersistenceFactory.INSTANCE.getDomainObjectFactory(mongoDBService,
DomainFactory.INSTANCE), mongoObjectFactory, MediaDBFactory.INSTANCE.getMediaDB(mongoDBService),
EmptyWindStore.INSTANCE, EmptyGPSFixStore.INSTANCE);
return new RacingEventServiceImpl((final RaceLogResolver raceLogResolver)-> {
return new ConstructorParameters() {
private final DomainFactory baseDomainFactory = new DomainFactoryImpl(raceLogResolver);
@Override public DomainObjectFactory getDomainObjectFactory() { return PersistenceFactory.INSTANCE.getDomainObjectFactory(mongoDBService, baseDomainFactory); }
@Override public MongoObjectFactory getMongoObjectFactory() { return mongoObjectFactory; }
@Override public DomainFactory getBaseDomainFactory() { return baseDomainFactory; }
@Override public CompetitorStore getCompetitorStore() { return getBaseDomainFactory().getCompetitorStore(); }
};
}, MediaDBFactory.INSTANCE.getMediaDB(mongoDBService), EmptyWindStore.INSTANCE, EmptyGPSFixStore.INSTANCE, null);
}
@Override
public RacingEventServiceImpl createNewReplica() {
return new RacingEventServiceImpl(PersistenceFactory.INSTANCE.getDomainObjectFactory(mongoDBService,
// replica gets its own base DomainFactory:
new DomainFactoryImpl()), mongoObjectFactory, MediaDBFactory.INSTANCE.getMediaDB(mongoDBService),
EmptyWindStore.INSTANCE, EmptyGPSFixStore.INSTANCE);
return new RacingEventServiceImpl(
(final RaceLogResolver raceLogResolver) -> {
return new RacingEventServiceImpl.ConstructorParameters() {
private final DomainObjectFactory domainObjectFactory =
PersistenceFactory.INSTANCE.getDomainObjectFactory(mongoDBService,
// replica gets its own base DomainFactory:
new DomainFactoryImpl(raceLogResolver));
@Override public DomainObjectFactory getDomainObjectFactory() { return domainObjectFactory; }
@Override public MongoObjectFactory getMongoObjectFactory() { return mongoObjectFactory; }
@Override public DomainFactory getBaseDomainFactory() { return domainObjectFactory.getBaseDomainFactory(); }
@Override public CompetitorStore getCompetitorStore() { return getBaseDomainFactory().getCompetitorStore(); }
};
}, MediaDBFactory.INSTANCE.getMediaDB(mongoDBService), EmptyWindStore.INSTANCE, EmptyGPSFixStore.INSTANCE,
/* serviceFinderFactory */ null);
}
}
}
@@ -77,7 +77,7 @@ public class DelayedLeaderboardCorrectionsReplicationTest extends AbstractServer
// then start initial load, wait until finished; then link a tracked race to leaderboard's RaceColumn on master and
// verify that on the replica it is associated to the RaceColumn as well, and the DelayedLeaderboardCorrections are
// resolved properly on the replica.
final DomainFactory domainFactory = new DomainFactoryImpl();
final DomainFactory domainFactory = new DomainFactoryImpl((srlid)->null);
BoatClass boatClass = domainFactory.getOrCreateBoatClass("29erXX", /* typicallyStartsUpwind */ true);
DynamicCompetitor hasso = AbstractLeaderboardTest.createCompetitor("Dr. Hasso Plattner"); // don't create competitor using CompetitorStore
final DynamicTrackedRace q2YellowTrackedRace = new MockedTrackedRaceWithFixedRank(hasso, /* rank */ 1, /* started */ false, boatClass) {
@@ -105,7 +105,7 @@ public class DelayedLeaderboardCorrectionsReplicationTest extends AbstractServer
// re-load new master from persistence
master = createRacingEventServiceWithOneMockedTrackedRace(q2YellowTrackedRace, domainFactory);
DomainFactoryImpl replicaDomainFactory = new DomainFactoryImpl();
DomainFactoryImpl replicaDomainFactory = new DomainFactoryImpl((srlid)->null);
replica = createRacingEventServiceWithOneMockedTrackedRace(q2YellowTrackedRace, replicaDomainFactory);
final Leaderboard masterLeaderboardReloaded = master.getLeaderboardByName(leaderboardName);
assertNotNull(masterLeaderboardReloaded);
@@ -78,8 +78,7 @@ public class ServerReplicationTest extends AbstractServerReplicationTest {
@Test
public void testWaypointRemovalReplication() throws InterruptedException {
final String boatClassName = "49er";
// FIXME use master DomainFactory; see bug 592
final DomainFactory masterDomainFactory = DomainFactory.INSTANCE;
final DomainFactory masterDomainFactory = testSetUp.getMaster().getBaseDomainFactory();
BoatClass boatClass = masterDomainFactory.getOrCreateBoatClass(boatClassName);
final String baseEventName = "Test Event";
AddDefaultRegatta addRegattaOperation = new AddDefaultRegatta(RegattaImpl.getDefaultName(baseEventName, boatClassName), boatClassName,
@@ -61,6 +61,7 @@ public class SimpleRabbitMQTest {
new Thread(consumer2).start();
String message = "Hello World!";
channel.basicPublish(EXCHANGE_NAME, /* queue name */ "", null, message.getBytes());
Thread.sleep(1000);
consumer1.waitUntilReceived(1000);
consumer2.waitUntilReceived(1000);
assertEquals(message, received.get(consumer1));
@@ -76,13 +76,13 @@ public class TrackedRaceContentsReplicationTest extends AbstractServerReplicatio
super.setUp();
final String boatClassName = "49er";
// FIXME use master DomainFactory; see bug 592
final DomainFactory masterDomainFactory = DomainFactory.INSTANCE;
final DomainFactory masterDomainFactory = testSetUp.getMaster().getBaseDomainFactory();
BoatClass boatClass = masterDomainFactory.getOrCreateBoatClass(boatClassName, /* typicallyStartsUpwind */true);
competitor = masterDomainFactory.getCompetitorStore().getOrCreateCompetitor("GER 61", "Tina Lutz", Color.RED, "someone@nowhere.de", null, new TeamImpl("Tina Lutz + Susann Beucke",
(List<PersonImpl>) Arrays.asList(new PersonImpl[] { new PersonImpl("Tina Lutz", DomainFactory.INSTANCE.getOrCreateNationality("GER"), null, null),
new PersonImpl("Tina Lutz", DomainFactory.INSTANCE.getOrCreateNationality("GER"), null, null) }),
new PersonImpl("Rigo de Mas", DomainFactory.INSTANCE.getOrCreateNationality("NED"), null, null)),
new BoatImpl("GER 61", DomainFactory.INSTANCE.getOrCreateBoatClass("470", /* typicallyStartsUpwind */ true), "GER 61"),
(List<PersonImpl>) Arrays.asList(new PersonImpl[] { new PersonImpl("Tina Lutz", masterDomainFactory.getOrCreateNationality("GER"), null, null),
new PersonImpl("Tina Lutz", masterDomainFactory.getOrCreateNationality("GER"), null, null) }),
new PersonImpl("Rigo de Mas", masterDomainFactory.getOrCreateNationality("NED"), null, null)),
new BoatImpl("GER 61", masterDomainFactory.getOrCreateBoatClass("470", /* typicallyStartsUpwind */ true), "GER 61"),
/* timeOnTimeFactor */ null, /* timeOnDistanceAllowanceInSecondsPerNauticalMile */ null);
final String baseEventName = "Test Event";
AddDefaultRegatta addEventOperation = new AddDefaultRegatta(RegattaImpl.getDefaultName(baseEventName, boatClassName), boatClassName,
@@ -75,8 +75,7 @@ public class TrackedRaceWithGPSFixStoreContentsReplicationTest extends AbstractS
/* dropDB */true, /* master=null means create a new one */null,
/* replica=null means create a new one */null);
final String boatClassName = "49er";
// FIXME use master DomainFactory; see bug 592
final DomainFactory masterDomainFactory = DomainFactory.INSTANCE;
final DomainFactory masterDomainFactory = testSetUp.getMaster().getBaseDomainFactory();
BoatClass boatClass = masterDomainFactory.getOrCreateBoatClass(boatClassName, /* typicallyStartsUpwind */true);
competitor = masterDomainFactory.getCompetitorStore().getOrCreateCompetitor("GER 61", "Tina Lutz", Color.RED, "someone@nowhere.de", null, new TeamImpl("Tina Lutz + Susann Beucke",
(List<PersonImpl>) Arrays.asList(new PersonImpl[] { new PersonImpl("Tina Lutz", DomainFactory.INSTANCE.getOrCreateNationality("GER"), null, null),
@@ -145,5 +144,9 @@ public class TrackedRaceWithGPSFixStoreContentsReplicationTest extends AbstractS
}
}
@Test
public void testTrackedRaceHasValidRaceLogResolverAfterDeserialization() {
TrackedRace replicaTrackedRace = replica.getTrackedRace(raceIdentifier);
assertNotNull(replicaTrackedRace.getRaceLogResolver());
}
}
@@ -52,14 +52,14 @@ public class CompetitorStoreTest {
@Test
public void testPersistentCompetitorStore() {
CompetitorStore persistentStore1 = new PersistentCompetitorStore(
PersistenceFactory.INSTANCE.getDefaultMongoObjectFactory(), /* clearStore */true, null);
PersistenceFactory.INSTANCE.getDefaultMongoObjectFactory(), /* clearStore */true, null, /* raceLogResolver */ (srlid)->null);
DynamicCompetitor template = AbstractLeaderboardTest.createCompetitor("Test Competitor");
Competitor competitor = persistentStore1.getOrCreateCompetitor(template.getId(), template.getName(),
template.getColor(), template.getEmail(), template.getFlagImage(), template.getTeam(),
template.getBoat(), /* timeOnTimeFactor */ 1.234, /* timeOnDistanceAllowanceInSecondsPerNauticalMile */ Duration.ONE_SECOND.times(730));
CompetitorStore persistentStore2 = new PersistentCompetitorStore(
PersistenceFactory.INSTANCE.getDefaultMongoObjectFactory(), /* clearStore */false, null);
PersistenceFactory.INSTANCE.getDefaultMongoObjectFactory(), /* clearStore */false, null, /* raceLogResolver */ (srlid)->null);
Competitor competitor2 = persistentStore2.getExistingCompetitorById(template.getId());
assertNotSame(competitor2, template); // the new store loads new instances from the database
assertEquals(template.getId(), competitor2.getId());
@@ -741,7 +741,7 @@ public class MasterDataImportTest {
public void testMasterDataImportForRaceLogEventsReferencingCompetitors() throws MalformedURLException, IOException,
InterruptedException, ClassNotFoundException {
// Setup source service
DomainFactory sourceDomainFactory = new DomainFactoryImpl();
DomainFactory sourceDomainFactory = new DomainFactoryImpl((srlid)->null);
RacingEventService sourceService = new RacingEventServiceImpl(
PersistenceFactory.INSTANCE.getDomainObjectFactory(MongoDBService.INSTANCE, sourceDomainFactory),
PersistenceFactory.INSTANCE.getMongoObjectFactory(MongoDBService.INSTANCE),
@@ -5,6 +5,7 @@ import java.io.ObjectInputStream;
import java.io.Serializable;
import java.net.URI;
import com.sap.sailing.domain.abstractlog.race.analyzing.impl.RaceLogResolver;
import com.sap.sailing.domain.base.Competitor;
import com.sap.sailing.domain.base.CompetitorStore;
import com.sap.sailing.domain.base.DomainFactory;
@@ -40,8 +41,9 @@ public class PersistentCompetitorStore extends TransientCompetitorStoreImpl impl
* if <code>true</code>, the persistent competitor store is initially cleared, with all persistent
* competitor data removed; use with caution!
*/
public PersistentCompetitorStore(MongoObjectFactory storeTo, boolean clear, TypeBasedServiceFinderFactory serviceFinderFactory) {
DomainFactoryImpl baseDomainFactory = new DomainFactoryImpl(this);
public PersistentCompetitorStore(MongoObjectFactory storeTo, boolean clear,
TypeBasedServiceFinderFactory serviceFinderFactory, RaceLogResolver raceLogResolver) {
DomainFactoryImpl baseDomainFactory = new DomainFactoryImpl(this, raceLogResolver);
this.loadFrom = PersistenceFactory.INSTANCE.getDomainObjectFactory(MongoDBService.INSTANCE, baseDomainFactory, serviceFinderFactory);
this.storeTo = storeTo;
if (clear) {
@@ -34,6 +34,7 @@ import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.function.Function;
import java.util.logging.Level;
import java.util.logging.Logger;
@@ -52,6 +53,7 @@ import com.sap.sailing.domain.abstractlog.race.RaceLog;
import com.sap.sailing.domain.abstractlog.race.RaceLogEvent;
import com.sap.sailing.domain.abstractlog.race.RaceLogEventVisitor;
import com.sap.sailing.domain.abstractlog.race.SimpleRaceLogIdentifier;
import com.sap.sailing.domain.abstractlog.race.analyzing.impl.RaceLogResolver;
import com.sap.sailing.domain.abstractlog.race.state.RaceState;
import com.sap.sailing.domain.abstractlog.race.state.ReadonlyRaceState;
import com.sap.sailing.domain.abstractlog.race.state.impl.RaceStateImpl;
@@ -396,6 +398,23 @@ public class RacingEventServiceImpl implements RacingEventService, ClearStateTes
private final JoinedClassLoader joinedClassLoader;
/**
* Providing the constructor parameters for a new {@link RacingEventServiceImpl} instance is a bit tricky
* in some cases because containment and initialization order of some types is fairly tightly coupled.
* There is a dependency of many such objects on an instance of {@link RaceLogResolver} which is implemented
* by {@link RacingEventServiceImpl}. However, therefore, this instance only becomes available in the
* innermost constructor.
*
* @author Axel Uhl (d043530)
*
*/
public static interface ConstructorParameters {
DomainObjectFactory getDomainObjectFactory();
MongoObjectFactory getMongoObjectFactory();
com.sap.sailing.domain.base.DomainFactory getBaseDomainFactory();
CompetitorStore getCompetitorStore();
}
/**
* Constructs a {@link DomainFactory base domain factory} that uses this object's {@link #competitorStore competitor
* store} for competitor management. This base domain factory is then also used for the construction of the
@@ -421,29 +440,41 @@ public class RacingEventServiceImpl implements RacingEventService, ClearStateTes
* be cleared before the service starts.
*
* @param clearPersistentCompetitorStore
* if <code>true</code>, the {@link PersistentCompetitorStore} is created empty, with the correcponding
* if <code>true</code>, the {@link PersistentCompetitorStore} is created empty, with the corresponding
* database collection cleared as well. Use with caution! When used with <code>false</code>, competitors
* created and stored during previous service executions will initially be loaded.
*/
public RacingEventServiceImpl(boolean clearPersistentCompetitorStore,
TypeBasedServiceFinderFactory serviceFinderFactory) {
this(new PersistentCompetitorStore(
PersistenceFactory.INSTANCE.getDefaultMongoObjectFactory(serviceFinderFactory),
clearPersistentCompetitorStore, serviceFinderFactory), null, null, serviceFinderFactory);
public RacingEventServiceImpl(boolean clearPersistentCompetitorStore, final TypeBasedServiceFinderFactory serviceFinderFactory) {
this((final RaceLogResolver raceLogResolver)-> {
return new ConstructorParameters() {
private final MongoObjectFactory mongoObjectFactory = PersistenceFactory.INSTANCE.getDefaultMongoObjectFactory(serviceFinderFactory);
private final PersistentCompetitorStore competitorStore = new PersistentCompetitorStore(
PersistenceFactory.INSTANCE.getDefaultMongoObjectFactory(serviceFinderFactory),
clearPersistentCompetitorStore, serviceFinderFactory, raceLogResolver);
@Override public DomainObjectFactory getDomainObjectFactory() { return competitorStore.getDomainObjectFactory(); }
@Override public MongoObjectFactory getMongoObjectFactory() { return mongoObjectFactory; }
@Override public DomainFactory getBaseDomainFactory() { return competitorStore.getBaseDomainFactory(); }
@Override public CompetitorStore getCompetitorStore() { return competitorStore; }
};
}, MediaDBFactory.INSTANCE.getDefaultMediaDB(), null, null, serviceFinderFactory);
}
private RacingEventServiceImpl(boolean clearPersistentCompetitorStore, WindStore windStore,
GPSFixStore gpsFixStore, TypeBasedServiceFinderFactory serviceFinderFactory) {
this(new PersistentCompetitorStore(
PersistenceFactory.INSTANCE.getDefaultMongoObjectFactory(serviceFinderFactory),
clearPersistentCompetitorStore, serviceFinderFactory), windStore, gpsFixStore, serviceFinderFactory);
}
private RacingEventServiceImpl(final boolean clearPersistentCompetitorStore, WindStore windStore,
GPSFixStore gpsFixStore, final TypeBasedServiceFinderFactory serviceFinderFactory) {
this((final RaceLogResolver raceLogResolver)-> {
return new ConstructorParameters() {
private final MongoObjectFactory mongoObjectFactory = PersistenceFactory.INSTANCE.getDefaultMongoObjectFactory(serviceFinderFactory);
private final PersistentCompetitorStore competitorStore = new PersistentCompetitorStore(
mongoObjectFactory,
clearPersistentCompetitorStore, serviceFinderFactory, raceLogResolver);
private RacingEventServiceImpl(PersistentCompetitorStore persistentCompetitorStore, WindStore windStore,
GPSFixStore gpsFixStore, TypeBasedServiceFinderFactory serviceFinderFactory) {
this(persistentCompetitorStore.getDomainObjectFactory(), persistentCompetitorStore.getMongoObjectFactory(),
persistentCompetitorStore.getBaseDomainFactory(), MediaDBFactory.INSTANCE.getDefaultMediaDB(),
persistentCompetitorStore, windStore, gpsFixStore, serviceFinderFactory);
@Override public DomainObjectFactory getDomainObjectFactory() { return competitorStore.getDomainObjectFactory(); }
@Override public MongoObjectFactory getMongoObjectFactory() { return mongoObjectFactory; }
@Override public DomainFactory getBaseDomainFactory() { return competitorStore.getBaseDomainFactory(); }
@Override public CompetitorStore getCompetitorStore() { return competitorStore; }
};
}, MediaDBFactory.INSTANCE.getDefaultMediaDB(), windStore, gpsFixStore, serviceFinderFactory);
}
/**
@@ -452,10 +483,30 @@ public class RacingEventServiceImpl implements RacingEventService, ClearStateTes
* be used for testing because it provides a transient {@link CompetitorStore} as required for competitor
* persistence.
*/
public RacingEventServiceImpl(DomainObjectFactory domainObjectFactory, MongoObjectFactory mongoObjectFactory,
public RacingEventServiceImpl(Function<RaceLogResolver, DomainObjectFactory> domainObjectFactoryProvider,
final MongoObjectFactory mongoObjectFactory, MediaDB mediaDB, WindStore windStore, GPSFixStore gpsFixStore) {
this((final RaceLogResolver raceLogResolver)-> {
return new ConstructorParameters() {
private final DomainObjectFactory domainObjectFactory = domainObjectFactoryProvider.apply(raceLogResolver);
@Override public DomainObjectFactory getDomainObjectFactory() { return domainObjectFactory; }
@Override public MongoObjectFactory getMongoObjectFactory() { return mongoObjectFactory; }
@Override public DomainFactory getBaseDomainFactory() { return domainObjectFactory.getBaseDomainFactory(); }
@Override public CompetitorStore getCompetitorStore() { return getBaseDomainFactory().getCompetitorStore(); }
};
}, mediaDB, windStore, gpsFixStore, null);
}
public RacingEventServiceImpl(final DomainObjectFactory domainObjectFactory, MongoObjectFactory mongoObjectFactory,
MediaDB mediaDB, WindStore windStore, GPSFixStore gpsFixStore) {
this(domainObjectFactory, mongoObjectFactory, domainObjectFactory.getBaseDomainFactory(), mediaDB,
domainObjectFactory.getBaseDomainFactory().getCompetitorStore(), windStore, gpsFixStore, null);
this((final RaceLogResolver raceLogResolver)-> {
return new ConstructorParameters() {
@Override public DomainObjectFactory getDomainObjectFactory() { return domainObjectFactory; }
@Override public MongoObjectFactory getMongoObjectFactory() { return mongoObjectFactory; }
@Override public DomainFactory getBaseDomainFactory() { return domainObjectFactory.getBaseDomainFactory(); }
@Override public CompetitorStore getCompetitorStore() { return getBaseDomainFactory().getCompetitorStore(); }
};
}, mediaDB, windStore, gpsFixStore, null);
}
/**
@@ -467,14 +518,18 @@ public class RacingEventServiceImpl implements RacingEventService, ClearStateTes
* of {@link DeviceIdentifier}s of specific device types or the managing of the device-to-competitor
* associations per race tracked.
*/
private RacingEventServiceImpl(DomainObjectFactory domainObjectFactory, MongoObjectFactory mongoObjectFactory,
com.sap.sailing.domain.base.DomainFactory baseDomainFactory, MediaDB mediaDb,
CompetitorStore competitorStore, WindStore windStore, GPSFixStore gpsFixStore,
TypeBasedServiceFinderFactory serviceFinderFactory) {
public RacingEventServiceImpl(Function<RaceLogResolver, ConstructorParameters> constructorParametersProvider, MediaDB mediaDb,
WindStore windStore, GPSFixStore gpsFixStore, TypeBasedServiceFinderFactory serviceFinderFactory) {
logger.info("Created " + this);
final ConstructorParameters constructorParameters = constructorParametersProvider.apply(this);
this.domainObjectFactory = constructorParameters.getDomainObjectFactory();
this.masterDataClassLoaders.add(this.getClass().getClassLoader());
joinedClassLoader = new JoinedClassLoader(masterDataClassLoaders);
this.operationsSentToMasterForReplication = new HashSet<>();
this.baseDomainFactory = constructorParameters.getBaseDomainFactory();
this.mongoObjectFactory = constructorParameters.getMongoObjectFactory();
this.mediaDB = mediaDb;
this.competitorStore = constructorParameters.getCompetitorStore();
if (windStore == null) {
try {
windStore = MongoWindStoreFactory.INSTANCE.getMongoWindStore(mongoObjectFactory, domainObjectFactory);
@@ -482,11 +537,6 @@ public class RacingEventServiceImpl implements RacingEventService, ClearStateTes
throw new RuntimeException(e);
}
}
this.baseDomainFactory = baseDomainFactory;
this.domainObjectFactory = domainObjectFactory;
this.mongoObjectFactory = mongoObjectFactory;
this.mediaDB = mediaDb;
this.competitorStore = competitorStore;
this.competitorStore.addCompetitorUpdateListener(new CompetitorUpdateListener() {
@Override
public void competitorUpdated(Competitor competitor) {
@@ -14,6 +14,7 @@ import com.sap.sailing.domain.base.Leg;
import com.sap.sailing.domain.base.Mark;
import com.sap.sailing.domain.base.RaceDefinition;
import com.sap.sailing.domain.base.Regatta;
import com.sap.sailing.domain.base.SharedDomainFactory;
import com.sap.sailing.domain.base.Sideline;
import com.sap.sailing.domain.base.SpeedWithConfidence;
import com.sap.sailing.domain.base.Waypoint;
@@ -56,6 +57,7 @@ import com.sap.sailing.domain.tracking.WindWithConfidence;
import com.sap.sailing.domain.tracking.impl.DynamicTrackedRegattaImpl;
import com.sap.sailing.domain.tracking.impl.EmptyWindStore;
import com.sap.sse.common.Duration;
import com.sap.sse.common.IsManagedByCache;
import com.sap.sse.common.TimePoint;
import com.sap.sse.common.Util;
@@ -621,4 +623,9 @@ public class DummyTrackedRace extends TrackedRaceWithWindEssentials {
@Override
public void detachRaceExecutionOrderProvider(RaceExecutionOrderProvider raceExecutionOrderProvider) {
}
@Override
public IsManagedByCache<SharedDomainFactory> resolve(SharedDomainFactory domainFactory) {
return this;
}
}
@@ -132,7 +132,8 @@ public class PathImpl implements Path, Serializable {
if ((this.pathPoints.get(idx).getTimePoint().asMillis() >= nextTimePoint.asMillis())||(idx == this.pathPoints.size()-1)) {
if (idx == this.pathPoints.size()-1) {
// for the last step, next-time-point needs to be aligned to the time-range of the course
if (nextTimePoint.after(endTime)) {
nextTimePoint = endTime;
}