Merge remote-tracking branch 'origin/master'

This commit is contained in:
Nick committed 2015-07-04 21:16:46 +02:00
commit 15fe949b4b
36 files changed
+549 -204

No files matched your search

@@ -1289,7 +1289,7 @@ public class MongoObjectFactoryImpl implements MongoObjectFactory {
logger.info("Removing persistent competitor info for competitor "+competitor.getName()+" with ID "+competitor.getId());
DBCollection collection = database.getCollection(CollectionNames.COMPETITORS.name());
DBObject query = (DBObject) JSON.parse(CompetitorJsonSerializer.getCompetitorIdQuery(competitor).toString());
collection.remove(query);
collection.remove(query, WriteConcern.SAFE);
}
@Override
@@ -409,20 +409,17 @@ public class RaceLogRaceTracker implements RaceTracker, GPSFixReceivedListener {
}
private void onCourseDesignChangedEvent(RaceLogCourseDesignChangedEvent event) {
if (trackedRace == null)
return;
CourseBase base = new LastPublishedCourseDesignFinder(params.getRaceLog()).analyze();
List<Util.Pair<ControlPoint, PassingInstruction>> update = new ArrayList<>();
for (Waypoint waypoint : base.getWaypoints()) {
update.add(new Util.Pair<>(waypoint.getControlPoint(), waypoint.getPassingInstructions()));
}
try {
trackedRace.getRace().getCourse().update(update, params.getDomainFactory());
} catch (PatchFailedException e) {
logger.log(Level.WARNING, "Could not update course for race " + trackedRace.getRace().getName());
if (trackedRace != null) {
CourseBase base = new LastPublishedCourseDesignFinder(params.getRaceLog()).analyze();
List<Util.Pair<ControlPoint, PassingInstruction>> update = new ArrayList<>();
for (Waypoint waypoint : base.getWaypoints()) {
update.add(new Util.Pair<>(waypoint.getControlPoint(), waypoint.getPassingInstructions()));
}
try {
trackedRace.getRace().getCourse().update(update, params.getDomainFactory());
} catch (PatchFailedException e) {
logger.log(Level.WARNING, "Could not update course for race " + trackedRace.getRace().getName());
}
}
}
@@ -30,7 +30,7 @@ public class WeakRaceLogChangedVisitor extends AbstractRaceLogChangedVisitor {
while (true) {
try {
Reference<?> ref = queue.remove();
WeakRaceLogChangedVisitor visitor = referenceToVisitor.get(ref);
WeakRaceLogChangedVisitor visitor = referenceToVisitor.remove(ref);
visitor.removeListener();
} catch (InterruptedException e) {
logger.log(Level.SEVERE, "Error trying to clean weak reference", e);
@@ -19,7 +19,7 @@ import com.sap.sailing.domain.abstractlog.race.analyzing.impl.IsInFinishingPhase
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;
import com.sap.sailing.domain.abstractlog.race.impl.WeakRaceLogChangedVisitor;
import com.sap.sailing.domain.abstractlog.race.state.RaceStateEvent;
import com.sap.sailing.domain.abstractlog.race.state.RaceStateEventScheduler;
import com.sap.sailing.domain.abstractlog.race.state.ReadonlyRaceState;
@@ -79,12 +79,10 @@ public abstract class BaseRacingProcedure extends BaseRaceStateChangedListener i
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);
@@ -92,10 +90,7 @@ public abstract class BaseRacingProcedure extends BaseRaceStateChangedListener i
this.finishingTimeFinder = new FinishingTimeFinder(raceLog);
this.finishedTimeFinder = new FinishedTimeFinder(raceLog);
this.startTimeFinder = new StartTimeFinder(raceLogResolver, raceLog);
this.raceLogListener = new RaceLogChangedVisitor(this);
this.raceLog.addListener(raceLogListener);
this.raceLogListener = new WeakRaceLogChangedVisitor(this.raceLog, this);
this.cachedIsIndividualRecallDisplayed = false;
}
@@ -2,8 +2,23 @@ package com.sap.sailing.domain.base;
import java.io.Serializable;
public interface Leg extends Serializable {
/**
* When two legs are compared, their natural order is by the index of their {@link #getFrom() start waypoint} in the
* {@link Course} to which they belong. A leg closer to the beginning of the course ranks "less" than one that is closer
* to the end of the course.
*
* @author Axel Uhl (D043530)
*
*/
public interface Leg extends Serializable, Comparable<Leg> {
Waypoint getFrom();
Waypoint getTo();
/**
* The index of this leg's {@link #getFrom() start waypoint} in the sequence of the
* {@link Course}'s {@link Course#getWaypoints waypoints}. The first waypoint in
* the course has index 0.
*/
int getZeroBasedIndexOfStartWaypoint();
}
@@ -23,7 +23,6 @@ public class CourseDataImpl extends NamedImpl implements CourseBase {
@Override
public List<Leg> getLegs() {
// TODO Auto-generated method stub
return null;
}
@@ -72,7 +71,6 @@ public class CourseDataImpl extends NamedImpl implements CourseBase {
@Override
public Leg getFirstLeg() {
// TODO Auto-generated method stub
return null;
}
@@ -0,0 +1,204 @@
package com.sap.sailing.domain.ranking;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertSame;
import static org.mockito.Mockito.mock;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.function.Function;
import org.junit.Test;
import com.sap.sailing.domain.abstractlog.race.analyzing.impl.RaceLogResolver;
import com.sap.sailing.domain.base.Competitor;
import com.sap.sailing.domain.base.ControlPoint;
import com.sap.sailing.domain.base.Course;
import com.sap.sailing.domain.base.DomainFactory;
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.Sideline;
import com.sap.sailing.domain.base.Waypoint;
import com.sap.sailing.domain.base.impl.BoatClassImpl;
import com.sap.sailing.domain.base.impl.ControlPointWithTwoMarksImpl;
import com.sap.sailing.domain.base.impl.CourseImpl;
import com.sap.sailing.domain.base.impl.MarkImpl;
import com.sap.sailing.domain.base.impl.RaceDefinitionImpl;
import com.sap.sailing.domain.base.impl.RegattaImpl;
import com.sap.sailing.domain.base.impl.WaypointImpl;
import com.sap.sailing.domain.common.RankingMetrics;
import com.sap.sailing.domain.common.ScoringSchemeType;
import com.sap.sailing.domain.common.WindSourceType;
import com.sap.sailing.domain.common.impl.DegreeBearingImpl;
import com.sap.sailing.domain.common.impl.DegreePosition;
import com.sap.sailing.domain.common.impl.KnotSpeedWithBearingImpl;
import com.sap.sailing.domain.common.impl.WindImpl;
import com.sap.sailing.domain.common.impl.WindSourceImpl;
import com.sap.sailing.domain.common.tracking.impl.GPSFixImpl;
import com.sap.sailing.domain.common.tracking.impl.GPSFixMovingImpl;
import com.sap.sailing.domain.racelog.impl.EmptyRaceLogStore;
import com.sap.sailing.domain.racelog.tracking.EmptyGPSFixStore;
import com.sap.sailing.domain.ranking.RankingMetric.RankingInfo;
import com.sap.sailing.domain.regattalog.impl.EmptyRegattaLogStore;
import com.sap.sailing.domain.test.TrackBasedTest;
import com.sap.sailing.domain.tracking.DynamicTrackedRace;
import com.sap.sailing.domain.tracking.MarkPassing;
import com.sap.sailing.domain.tracking.TrackedRegatta;
import com.sap.sailing.domain.tracking.impl.DynamicTrackedRaceImpl;
import com.sap.sailing.domain.tracking.impl.DynamicTrackedRegattaImpl;
import com.sap.sailing.domain.tracking.impl.EmptyWindStore;
import com.sap.sailing.domain.tracking.impl.MarkPassingImpl;
import com.sap.sse.common.Duration;
import com.sap.sse.common.TimePoint;
import com.sap.sse.common.impl.MillisecondsTimePoint;
/**
* A test for the case described in bug 2976: when a competitor has skipped a mark passing but then got one for a
* later waypoint, that competitor may still be the one "farthest ahead." Still, we seem to have observed a case where
* under these circumstances the competitor was not considered "farthest ahead" and instead another with a contiguous
* mark passing list was preferred.<p>
*
* This test case establishes such a situation: two competitors, one with contiguous mark passings for the first two
* waypoints but not having sailed as far as the other in the second leg; the other competitor skipped the first mark
* passing, has one for the second waypoint and leads by windward distance in the second leg.<p>
*
* Since the problem occurred with the {@link OneDesignRankingMetric}, we'll use that one for the set-up here.
*
* @author Axel Uhl (D043530)
*
*/
public class TestFarthestAheadWithSkippedMarkPassing {
private RankingMetric rankingMetric;
private DynamicTrackedRace trackedRace;
private Competitor c1, c2;
private Waypoint start;
private Waypoint windward;
private Waypoint finish;
private void setUp(TimeOnTimeFactorMapping timeOnTimeFactors, Function<Competitor, Double> timeOnDistanceFactors) {
c1 = TrackBasedTest.createCompetitor("SlowBoat");
c2 = TrackBasedTest.createCompetitor("FastBoat");
trackedRace = createTrackedRace(Arrays.asList(c1, c2));
rankingMetric = trackedRace.getRankingMetric();
assertEquals(120, trackedRace.getCourseLength().getNauticalMiles(), 0.02);
assertSame(RankingMetrics.ONE_DESIGN, trackedRace.getTrackedRegatta().getRegatta().getRankingMetricType());
}
private DynamicTrackedRace createTrackedRace(Iterable<Competitor> competitors) {
final TimePoint timePointForFixes = MillisecondsTimePoint.now();
BoatClassImpl boatClass = new BoatClassImpl("Some Handicap Boat Class", /* typicallyStartsUpwind */ true);
Regatta regatta = new RegattaImpl(EmptyRaceLogStore.INSTANCE, EmptyRegattaLogStore.INSTANCE,
RegattaImpl.getDefaultName("Test Regatta", boatClass.getName()), boatClass, /*startDate*/ null, /*endDate*/ null, /* trackedRegattaRegistry */ null,
DomainFactory.INSTANCE.createScoringScheme(ScoringSchemeType.LOW_POINT), "123", /* courseArea */ null, OneDesignRankingMetric::new);
TrackedRegatta trackedRegatta = new DynamicTrackedRegattaImpl(regatta);
List<Waypoint> waypoints = new ArrayList<Waypoint>();
// create a two-lap upwind/downwind course:
MarkImpl left = new MarkImpl("Left lee gate buoy");
MarkImpl right = new MarkImpl("Right lee gate buoy");
ControlPoint leeGate = new ControlPointWithTwoMarksImpl(left, right, "Lee Gate");
Mark windwardMark = new MarkImpl("Windward mark");
start = new WaypointImpl(leeGate);
waypoints.add(start);
windward = new WaypointImpl(windwardMark);
waypoints.add(windward);
finish = new WaypointImpl(leeGate);
waypoints.add(finish);
Course course = new CourseImpl("Test Course", waypoints);
RaceDefinition race = new RaceDefinitionImpl("Test Race", course, boatClass, competitors);
DynamicTrackedRaceImpl trackedRace = new DynamicTrackedRaceImpl(trackedRegatta, race, Collections.<Sideline> emptyList(), EmptyWindStore.INSTANCE,
EmptyGPSFixStore.INSTANCE, /* delayToLiveInMillis */ 0,
/* millisecondsOverWhichToAverageWind */ 30000, /* millisecondsOverWhichToAverageSpeed */ 30000,
/* delay for wind estimation cache invalidation */ 0, /*useMarkPassingCalculator*/ false,
tr->new OneDesignRankingMetric(tr), mock(RaceLogResolver.class));
// in this simplified artificial course, the top mark is exactly north of the right leeward gate
DegreePosition topPosition = new DegreePosition(1, 0);
trackedRace.getOrCreateTrack(left).addGPSFix(new GPSFixImpl(new DegreePosition(0, -0.000001), timePointForFixes));
trackedRace.getOrCreateTrack(right).addGPSFix(new GPSFixImpl(new DegreePosition(0, 0.000001), timePointForFixes));
trackedRace.getOrCreateTrack(windwardMark).addGPSFix(new GPSFixImpl(topPosition, timePointForFixes));
trackedRace.recordWind(new WindImpl(topPosition, timePointForFixes, new KnotSpeedWithBearingImpl(
/* speedInKnots */14.7, new DegreeBearingImpl(180))), new WindSourceImpl(WindSourceType.WEB));
return trackedRace;
}
/**
* A competitor having only the start mark passing shall be ranked farthest ahead if the only other competitor
* has no start mark passing.
*/
@Test
public void testWithOneMarkPassingOnly() {
setUp(c -> c==c1 ? 2.0 : 1.0, c -> 0.0);
final TimePoint startOfRace = MillisecondsTimePoint.now();
final TimePoint middleOfFirstLeg = startOfRace.plus(Duration.ONE_HOUR.times(3));
trackedRace.updateMarkPassings(
c1,
Arrays.<MarkPassing> asList(new MarkPassingImpl(startOfRace, start, c1)));
trackedRace.getTrack(c1).add(
new GPSFixMovingImpl(new DegreePosition(0.0, 0), startOfRace, new KnotSpeedWithBearingImpl(12,
new DegreeBearingImpl(45))));
trackedRace.getTrack(c2).add(
new GPSFixMovingImpl(new DegreePosition(0.0, 0), startOfRace, new KnotSpeedWithBearingImpl(12,
new DegreeBearingImpl(315))));
trackedRace.getTrack(c1).add(
new GPSFixMovingImpl(new DegreePosition(0.5, 0), middleOfFirstLeg, new KnotSpeedWithBearingImpl(12,
new DegreeBearingImpl(45))));
trackedRace.getTrack(c2).add(
new GPSFixMovingImpl(new DegreePosition(0.5, 0), middleOfFirstLeg, new KnotSpeedWithBearingImpl(12,
new DegreeBearingImpl(315))));
// Both boats have climbed half of the first upwind beat; c1 is rated the faster boat (2.0), c2 has time-on-time factor 1.0.
// Therefore, c2 is expected to lead after applying the corrections.
final RankingInfo rankingInfo = rankingMetric.getRankingInfo(middleOfFirstLeg);
final Competitor farthestAhead = rankingInfo.getCompetitorFarthestAhead();
assertSame(c1, farthestAhead);
Comparator<Competitor> comparator = rankingMetric.getRaceRankingComparator(middleOfFirstLeg);
assertEquals(-1, comparator.compare(c1, c2)); // c1 is "less" than c2; better competitors rank less
}
/**
* C2 skipped the start mark passing but got a valid passing for the next waypoint. In the second leg, C2 leads
* by windward distance and should therefore be listed as the competitor farthest ahead by the ranking metric.
*/
@Test
public void testWithTwoMarkPassingsForC1AndSkippedStartForC2() {
setUp(c -> c==c1 ? 2.0 : 1.0, c -> 0.0);
final TimePoint startOfRace = MillisecondsTimePoint.now();
final TimePoint endOfFirstLeg = startOfRace.plus(Duration.ONE_HOUR.times(3));
final TimePoint middleOfSecondLeg = endOfFirstLeg.plus(Duration.ONE_MINUTE.times(10));
trackedRace.updateMarkPassings(
c1,
Arrays.<MarkPassing> asList(new MarkPassingImpl(startOfRace, start, c1), new MarkPassingImpl(endOfFirstLeg, windward, c1)));
trackedRace.updateMarkPassings(
c2,
Arrays.<MarkPassing> asList(/* skipping start waypoint */ new MarkPassingImpl(endOfFirstLeg, windward, c2)));
// they both start at the start line
trackedRace.getTrack(c1).add(
new GPSFixMovingImpl(new DegreePosition(0.0, 0), startOfRace, new KnotSpeedWithBearingImpl(12,
new DegreeBearingImpl(45))));
trackedRace.getTrack(c2).add(
new GPSFixMovingImpl(new DegreePosition(0.0, 0), startOfRace, new KnotSpeedWithBearingImpl(12,
new DegreeBearingImpl(315))));
// both round the windward mark at the same time
trackedRace.getTrack(c1).add(
new GPSFixMovingImpl(new DegreePosition(1.0, 0), endOfFirstLeg, new KnotSpeedWithBearingImpl(12,
new DegreeBearingImpl(45))));
trackedRace.getTrack(c2).add(
new GPSFixMovingImpl(new DegreePosition(1.0, 0), endOfFirstLeg, new KnotSpeedWithBearingImpl(12,
new DegreeBearingImpl(315))));
// c2 is further down the wind already at the middle of the second leg:
trackedRace.getTrack(c1).add(
new GPSFixMovingImpl(new DegreePosition(0.5, 0), middleOfSecondLeg, new KnotSpeedWithBearingImpl(12,
new DegreeBearingImpl(180))));
trackedRace.getTrack(c2).add(
new GPSFixMovingImpl(new DegreePosition(0.2, 0), middleOfSecondLeg, new KnotSpeedWithBearingImpl(12,
new DegreeBearingImpl(180))));
// Assert that c2 is the boat farthest ahead
final RankingInfo rankingInfo = rankingMetric.getRankingInfo(middleOfSecondLeg);
assertSame(c2, rankingInfo.getCompetitorFarthestAhead());
Comparator<Competitor> comparator = rankingMetric.getRaceRankingComparator(middleOfSecondLeg);
assertEquals(1, comparator.compare(c1, c2)); // c1 is "less" than c2; better competitors rank less
}
}
@@ -477,11 +477,6 @@ public class MockedTrackedRace implements DynamicTrackedRace {
return null;
}
@Override
public Iterable<TrackedRace> getTrackedRaces(BoatClass boatClass) {
return null;
}
@Override
public void addTrackedRace(TrackedRace trackedRace) {
}
@@ -536,6 +531,10 @@ public class MockedTrackedRace implements DynamicTrackedRace {
@Override
public void unlockTrackedRacesAfterWrite() {
}
@Override
public void removeRaceListener(RaceListener listener) {
}
};
}
@@ -28,4 +28,14 @@ public class LegImpl implements Leg {
public String toString() {
return getFrom() + " -> " + getTo();
}
@Override
public int getZeroBasedIndexOfStartWaypoint() {
return indexOfStartWaypoint;
}
@Override
public int compareTo(Leg o) {
return getZeroBasedIndexOfStartWaypoint() - o.getZeroBasedIndexOfStartWaypoint();
}
}
@@ -54,11 +54,11 @@ public interface Leaderboard extends LeaderboardBase {
*/
public interface Entry {
int getTrackedRank();
Double getNetPoints() throws NoWindException;
Double getNetPointsUncorrected() throws NoWindException;
Double getTotalPoints() throws NoWindException;
Double getNetPoints();
Double getNetPointsUncorrected();
Double getTotalPoints();
MaxPointsReason getMaxPointsReason();
boolean isDiscarded() throws NoWindException;
boolean isDiscarded();
/**
* Tells if the net points have been corrected by a {@link ScoreCorrection}
*/
@@ -219,7 +219,7 @@ public abstract class AbstractSimpleLeaderboardImpl implements Leaderboard, Race
return fleet;
}
@Override
public Double getNetPointsUncorrected() throws NoWindException {
public Double getNetPointsUncorrected() {
try {
return netPointsUncorrectedProvider.call();
} catch (Exception e) {
@@ -1068,7 +1068,10 @@ public abstract class AbstractSimpleLeaderboardImpl implements Leaderboard, Race
public Distance getTotalDistanceTraveled(Competitor competitor, TimePoint timePoint) {
Distance result = null;
for (TrackedRace trackedRace : getTrackedRaces()) {
if (Util.contains(trackedRace.getRace().getCompetitors(), competitor)) {
TimePoint startOfRace;
if (Util.contains(trackedRace.getRace().getCompetitors(), competitor) &&
(startOfRace=trackedRace.getStartOfRace()) != null &&
!startOfRace.after(timePoint)) {
Distance distanceSailedInRace = trackedRace.getDistanceTraveled(competitor, timePoint);
if (distanceSailedInRace != null) {
if (result == null) {
@@ -1137,10 +1140,10 @@ public abstract class AbstractSimpleLeaderboardImpl implements Leaderboard, Race
} else {
suppressedCompetitors.remove(competitor);
}
getScoreCorrection().notifyListenersAboutIsSuppressedChange(competitor, suppressed);
} finally {
LockUtil.unlockAfterWrite(suppressedCompetitorsLock);
}
getScoreCorrection().notifyListenersAboutIsSuppressedChange(competitor, suppressed);
}
@Override
@@ -1277,21 +1280,12 @@ public abstract class AbstractSimpleLeaderboardImpl implements Leaderboard, Race
final Set<RaceColumn> discardedRaceColumns = getResultDiscardingRule().getDiscardedRaceColumns(competitor, this, getRaceColumns(), timePoint);
for (final RaceColumn raceColumn : this.getRaceColumns()) {
RunnableFuture<LeaderboardEntryDTO> future = new FutureTask<LeaderboardEntryDTO>(() -> {
try {
Entry entry = AbstractSimpleLeaderboardImpl.this.getEntry(competitor, raceColumn, timePoint, discardedRaceColumns);
return getLeaderboardEntryDTO(entry, raceColumn, competitor, timePoint,
namesOfRaceColumnsForWhichToLoadLegDetails != null
&& namesOfRaceColumnsForWhichToLoadLegDetails.contains(raceColumn
.getName()), waitForLatestAnalyses, legRanksCache, baseDomainFactory,
fillNetPointsUncorrected, cache);
} catch (NoWindException e) {
logger.info("Exception trying to compute leaderboard entry for competitor "
+ competitor.getName() + " in race column " + raceColumn.getName() + ": "
+ e.getMessage());
logger.throwing(AbstractSimpleLeaderboardImpl.class.getName(),
"computeLeaderboardByName.future.call()", e);
throw new NoWindError(e);
}
Entry entry = AbstractSimpleLeaderboardImpl.this.getEntry(competitor, raceColumn, timePoint, discardedRaceColumns);
return getLeaderboardEntryDTO(entry, raceColumn, competitor, timePoint,
namesOfRaceColumnsForWhichToLoadLegDetails != null
&& namesOfRaceColumnsForWhichToLoadLegDetails.contains(raceColumn
.getName()), waitForLatestAnalyses, legRanksCache, baseDomainFactory,
fillNetPointsUncorrected, cache);
});
executor.execute(future);
futuresForColumnName.put(raceColumn.getName(), future);
@@ -1362,7 +1356,7 @@ public abstract class AbstractSimpleLeaderboardImpl implements Leaderboard, Race
private LeaderboardEntryDTO getLeaderboardEntryDTO(Entry entry, RaceColumn raceColumn, Competitor competitor,
TimePoint timePoint, boolean addLegDetails, boolean waitForLatestAnalyses,
Map<Leg, LinkedHashMap<Competitor, Integer>> legRanksCache, DomainFactory baseDomainFactory,
boolean fillNetPointsUncorrected, WindLegTypeAndLegBearingCache cache) throws NoWindException {
boolean fillNetPointsUncorrected, WindLegTypeAndLegBearingCache cache) {
LeaderboardEntryDTO entryDTO = new LeaderboardEntryDTO();
TrackedRace trackedRace = raceColumn.getTrackedRace(competitor);
entryDTO.race = trackedRace == null ? null : trackedRace.getRaceIdentifier();
@@ -1538,7 +1532,7 @@ public abstract class AbstractSimpleLeaderboardImpl implements Leaderboard, Race
*/
private RaceDetails getRaceDetails(TrackedRace trackedRace, Competitor competitor, TimePoint timePoint,
boolean waitForLatestAnalyses, Map<Leg, LinkedHashMap<Competitor, Integer>> legRanksCache,
RankingInfo rankingInfo, WindLegTypeAndLegBearingCache cache) throws NoWindException, InterruptedException, ExecutionException {
RankingInfo rankingInfo, WindLegTypeAndLegBearingCache cache) throws InterruptedException, ExecutionException {
final RaceDetails raceDetails;
if (trackedRace.getEndOfTracking() != null && trackedRace.getEndOfTracking().compareTo(timePoint) < 0) {
raceDetails = getRaceDetailsForEndOfTrackingFromCacheOrCalculateAndCache(trackedRace, competitor, legRanksCache, rankingInfo, cache);
@@ -1550,7 +1544,7 @@ public abstract class AbstractSimpleLeaderboardImpl implements Leaderboard, Race
private RaceDetails getRaceDetailsForEndOfTrackingFromCacheOrCalculateAndCache(final TrackedRace trackedRace,
final Competitor competitor, final Map<Leg, LinkedHashMap<Competitor, Integer>> legRanksCache,
RankingInfo rankingInfo, final WindLegTypeAndLegBearingCache cache) throws NoWindException, InterruptedException, ExecutionException {
RankingInfo rankingInfo, final WindLegTypeAndLegBearingCache cache) throws InterruptedException, ExecutionException {
final com.sap.sse.common.Util.Pair<TrackedRace, Competitor> key = new com.sap.sse.common.Util.Pair<TrackedRace, Competitor>(trackedRace, competitor);
RunnableFuture<RaceDetails> raceDetails;
synchronized (raceDetailsAtEndOfTrackingCache) {
@@ -1582,7 +1576,7 @@ public abstract class AbstractSimpleLeaderboardImpl implements Leaderboard, Race
private RaceDetails calculateRaceDetails(TrackedRace trackedRace, Competitor competitor, TimePoint timePoint,
boolean waitForLatestAnalyses, Map<Leg, LinkedHashMap<Competitor, Integer>> legRanksCache,
WindLegTypeAndLegBearingCache cache, final RankingInfo rankingInfo) throws NoWindException {
WindLegTypeAndLegBearingCache cache, final RankingInfo rankingInfo) {
final List<LegEntryDTO> legDetails = new ArrayList<LegEntryDTO>();
final Course course = trackedRace.getRace().getCourse();
course.lockForRead(); // hold back any course re-configurations while looping over the legs
@@ -1630,7 +1624,7 @@ public abstract class AbstractSimpleLeaderboardImpl implements Leaderboard, Race
private LegEntryDTO createLegEntry(TrackedLegOfCompetitor trackedLeg, TimePoint timePoint,
boolean waitForLatestAnalyses, Map<Leg, LinkedHashMap<Competitor, Integer>> legRanksCache,
RankingInfo rankingInfo, WindLegTypeAndLegBearingCache cache) throws NoWindException {
RankingInfo rankingInfo, WindLegTypeAndLegBearingCache cache) {
LegEntryDTO result;
final Duration time = trackedLeg.getTime(timePoint);
if (trackedLeg == null || time == null) {
@@ -195,7 +195,7 @@ public interface TrackedLegOfCompetitor extends Serializable {
* <code>timePoint</code>, returns the VMG value for this time point. If the competitor has already finished the
* leg, the VMG at the time when the competitor finished the leg is returned.
*/
Speed getVelocityMadeGood(TimePoint timePoint, WindPositionMode windPositionMode) throws NoWindException;
Speed getVelocityMadeGood(TimePoint timePoint, WindPositionMode windPositionMode);
/**
* Same as {@link #getVelocityMadeGood(TimePoint, WindPositionMode)}, only that a cache for wind data and leg type and bearing
@@ -212,7 +212,7 @@ public interface TrackedLegOfCompetitor extends Serializable {
/**
* Same as {@link #getEstimatedTimeToNextMark(TimePoint, WindPositionMode)}, only that a cache for leg type calculation is passed.
*/
Duration getEstimatedTimeToNextMark(TimePoint timePoint, WindPositionMode windPositionMode, WindLegTypeAndLegBearingCache cache) throws NoWindException;
Duration getEstimatedTimeToNextMark(TimePoint timePoint, WindPositionMode windPositionMode, WindLegTypeAndLegBearingCache cache);
/**
* Returns <code>null</code> in case this leg's competitor hasn't started the leg yet. If in the leg at
@@ -3,7 +3,6 @@ package com.sap.sailing.domain.tracking;
import java.io.Serializable;
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.RaceDefinition;
import com.sap.sailing.domain.base.Regatta;
@@ -55,8 +54,6 @@ public interface TrackedRegatta extends Serializable {
void unlockTrackedRacesAfterWrite();
Iterable<TrackedRace> getTrackedRaces(BoatClass boatClass);
/**
* Creates a {@link TrackedRace} based on the parameter specified and {@link #addTrackedRace(TrackedRace) adds} it
* to this tracked regatta. Afterwards, calling {@link #getTrackedRace(RaceDefinition) getTrackedRace(raceDefinition)}
@@ -93,6 +90,8 @@ public interface TrackedRegatta extends Serializable {
*/
void addRaceListener(RaceListener listener);
void removeRaceListener(RaceListener listener);
int getNetPoints(Competitor competitor, TimePoint timePoint) throws NoWindException;
void removeTrackedRace(RaceDefinition raceDefinition);
@@ -2,11 +2,14 @@ package com.sap.sailing.domain.tracking.impl;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.NavigableSet;
import java.util.SortedSet;
import java.util.logging.Logger;
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.tracking.MarkPassing;
import com.sap.sailing.domain.tracking.TrackedLegOfCompetitor;
import com.sap.sailing.domain.tracking.TrackedRace;
@@ -35,6 +38,7 @@ import com.sap.sse.common.TimePoint;
*
*/
public abstract class AbstractRaceRankComparator<C extends Comparable<C>> implements Comparator<Competitor> {
private static final Logger logger = Logger.getLogger(AbstractRaceRankComparator.class.getName());
private final TrackedRace trackedRace;
private final TimePoint timePoint;
private final DummyMarkPassingWithTimePointOnly markPassingWithTimePoint;
@@ -59,6 +63,7 @@ public abstract class AbstractRaceRankComparator<C extends Comparable<C>> implem
if (o1 == o2) {
result = 0;
} else {
final Course course = trackedRace.getRace().getCourse();
NavigableSet<MarkPassing> o1MarkPassings = trackedRace.getMarkPassings(o1);
NavigableSet<MarkPassing> o1MarkPassingsBeforeTimePoint;
MarkPassing o1LastMarkPassingBeforeTimePoint = null;
@@ -66,6 +71,7 @@ public abstract class AbstractRaceRankComparator<C extends Comparable<C>> implem
TrackedLegOfCompetitor o1Leg;
trackedRace.lockForRead(o1MarkPassings);
try {
// FIXME for the XMLExportTest.testExportingESSNice2014 the "inclusive" parameter doesn't seem to work properly; problem is caused by the MarkPassingByTimeComparator falling back to competitor ID if times are equal
o1MarkPassingsBeforeTimePoint = o1MarkPassings.headSet(
markPassingWithTimePoint, /* inclusive */true);
o1MarkPassingsBeforeTimePointSize = o1MarkPassingsBeforeTimePoint.size();
@@ -92,32 +98,43 @@ public abstract class AbstractRaceRankComparator<C extends Comparable<C>> implem
} finally {
trackedRace.unlockAfterRead(o2MarkPassings);
}
result = o2MarkPassingsBeforeTimePointSize - o1MarkPassingsBeforeTimePointSize; // inverted: more legs means
// smaller rank
final List<Leg> legs = course.getLegs();
result = o1LastMarkPassingBeforeTimePoint == null
? o2LastMarkPassingBeforeTimePoint == null ? 0 // both haven't started yet
: 1 // only o2 has started; o1 is worse ("greater") than o2
: o2LastMarkPassingBeforeTimePoint == null ? -1 // only o1 has started; o1 is better ("less") than o2
/* both have started; any difference */ : course.getIndexOfWaypoint(o2LastMarkPassingBeforeTimePoint.getWaypoint()) -
/* in last waypoint passed? */ course.getIndexOfWaypoint(o1LastMarkPassingBeforeTimePoint.getWaypoint());
if (result == 0 && o1MarkPassingsBeforeTimePointSize > 0) {
assert o2LastMarkPassingBeforeTimePoint != null;
// 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
assert o2Leg == null;
result = o1LastMarkPassingBeforeTimePoint.getTimePoint().compareTo(
o2LastMarkPassingBeforeTimePoint.getTimePoint());
} else {
if (o2Leg == null) {
result = 1; // o1Leg != null, so o1 has started leg already, o2 hasn't
assert o2Leg != null; // otherwise, o1Leg!=null && o2Leg==null, but then o1 would have a finish mark passing and o2 not
if (o1Leg.getLeg() != o2Leg.getLeg()) {
logger.finest("Warning: competitors "+o1+" and "+o2+" in different legs ("+
o1Leg.getLeg()+" and "+o2Leg.getLeg()+", respectively) although based on their last mark passings before "+
timePoint+" ("+o1LastMarkPassingBeforeTimePoint+" and "+o2LastMarkPassingBeforeTimePoint+", respectively) "+
"they should be in the same leg");
// strange: both have the same number of mark passings but are in different legs; something is
// broken, but we can only try our best:
logger.finest("Warning: competitors "+o1+" and "+o2+" in different legs ("+
o1Leg.getLeg()+" and "+o2Leg.getLeg()+", respectively) although based on their last mark passings before "+
timePoint+" ("+o1LastMarkPassingBeforeTimePoint+" and "+o2LastMarkPassingBeforeTimePoint+", respectively) "+
"they should be in the same leg");
result = legs.indexOf(o1Leg.getLeg()) - legs.indexOf(o2Leg.getLeg());
} 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 = getComparisonValueForSameLeg(o1);
final C wwdtgO2 = getComparisonValueForSameLeg(o2);
result = wwdtgO1==null?wwdtgO2==null?0:-1:wwdtgO2==null?1:(lessIsBetter?1:-1)*wwdtgO1.compareTo(wwdtgO2);
}
// competitors are in same leg; compare their windward distance to go
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);
}
}
}
@@ -6,35 +6,24 @@ import java.util.Comparator;
import com.sap.sailing.domain.tracking.MarkPassing;
/**
* Compares two {@link MarkPassing} objects, using their {@link MarkPassing#getTimePoint() time point} as the primary
* ordering criterion in ascending order. If two mark passings have equal time points, the competitor IDs' string
* representations are compared as the secondary ordering criterion to ensure that two competitors passing a mark at the
* same time are still identified as not being equal.
* Compares two {@link MarkPassing} objects, using their {@link MarkPassing#getTimePoint() time point} as the only
* ordering criterion in ascending order. If two mark passings have equal time points, they are considered equal,
* regardless the competitor. Don't use this comparator for collections in which mark passings for multiple competitors
* may be managed and shall be treated as different. Use {@link MarkPassingsByTimeAndCompetitorIdComparator} instead.
*
* @author Axel Uhl (D043530)
*
*/
public class MarkPassingByTimeComparator implements Comparator<MarkPassing>, Serializable {
private static final long serialVersionUID = 5758820139503482888L;
public static MarkPassingByTimeComparator INSTANCE = new MarkPassingByTimeComparator();
public static final MarkPassingByTimeComparator INSTANCE = new MarkPassingByTimeComparator();
@Override
public int compare(MarkPassing o1, MarkPassing o2) {
int result = o1 == null ? o2 == null ? 0 : -1 : o2 == null ? 1 : o1.getTimePoint() == null ? (o2.getTimePoint() == null ? 0 : -1) : o2.getTimePoint() == null ? 1 : o1.getTimePoint().compareTo(o2.getTimePoint());
if (result == 0 && o1 != null) {
assert o2 != null;
Object c1ID = o1.getCompetitor().getId();
Object c2ID = o2.getCompetitor().getId();
// shortcut comparison and don't use expensive toString() in case IDs are comparable by nature
if (c1ID instanceof Comparable<?> && c1ID.getClass() == c2ID.getClass()) {
@SuppressWarnings("unchecked")
final Comparable<Object> c1OID = (Comparable<Object>) c1ID;
result = c1OID.compareTo(o2.getCompetitor().getId());
} else {
result = o1.getCompetitor().getId().toString().compareTo(o2.getCompetitor().getId().toString());
}
}
return result;
return o1 == null ?
o2 == null ? 0 : -1
: o2 == null ? 1 : o1.getTimePoint() == null ?
(o2.getTimePoint() == null ? 0 : -1)
: o2.getTimePoint() == null ? 1 : o1.getTimePoint().compareTo(o2.getTimePoint());
}
}
@@ -0,0 +1,36 @@
package com.sap.sailing.domain.tracking.impl;
import com.sap.sailing.domain.tracking.MarkPassing;
/**
* Compares two {@link MarkPassing} objects, using their {@link MarkPassing#getTimePoint() time point} as the primary
* ordering criterion in ascending order. If two mark passings have equal time points, the competitor IDs' string
* representations are compared as the secondary ordering criterion to ensure that two competitors passing a mark at the
* same time are still identified as not being equal.
*
* @author Axel Uhl (D043530)
*
*/
public class MarkPassingsByTimeAndCompetitorIdComparator extends MarkPassingByTimeComparator {
private static final long serialVersionUID = 5977491869367296660L;
public static final MarkPassingsByTimeAndCompetitorIdComparator INSTANCE = new MarkPassingsByTimeAndCompetitorIdComparator();
@Override
public int compare(MarkPassing o1, MarkPassing o2) {
int result = super.compare(o1, o2);
if (result == 0 && o1 != null) {
assert o2 != null;
Object c1ID = o1.getCompetitor().getId();
Object c2ID = o2.getCompetitor().getId();
// shortcut comparison and don't use expensive toString() in case IDs are comparable by nature
if (c1ID instanceof Comparable<?> && c1ID.getClass() == c2ID.getClass()) {
@SuppressWarnings("unchecked")
final Comparable<Object> c1OID = (Comparable<Object>) c1ID;
result = c1OID.compareTo(o2.getCompetitor().getId());
} else {
result = o1.getCompetitor().getId().toString().compareTo(o2.getCompetitor().getId().toString());
}
}
return result;
}
}
@@ -284,11 +284,13 @@ public class TrackedLegOfCompetitorImpl implements TrackedLegOfCompetitor {
// as fallback in the absence of wind information, project to leg bearing
projectToBearing = cache.getLegBearing(getTrackedLeg(), at);
}
double cos = Math.cos(speed.getBearing().getRadians() - projectToBearing.getRadians());
if (cos < 0) {
projectToBearing = projectToBearing.reverse();
if (speed.getBearing() != null && projectToBearing != null) {
double cos = Math.cos(speed.getBearing().getRadians() - projectToBearing.getRadians());
if (cos < 0) {
projectToBearing = projectToBearing.reverse();
}
result = new KnotSpeedWithBearingImpl(Math.abs(speed.getKnots() * cos), projectToBearing);
}
result = new KnotSpeedWithBearingImpl(Math.abs(speed.getKnots() * cos), projectToBearing);
}
return result;
}
@@ -338,10 +340,12 @@ public class TrackedLegOfCompetitorImpl implements TrackedLegOfCompetitor {
}
final Position endPos = getTrackedRace().getTrack(getCompetitor()).getEstimatedPosition(to, /* extrapolate */false);
if (endPos != null) {
Distance d = getTrackedLeg().getAbsoluteWindwardDistance(
getTrackedRace().getTrack(getCompetitor()).getEstimatedPosition(start.getTimePoint(), false),
endPos, to, WindPositionMode.EXACT, cache);
result = d.inTime(to.asMillis() - start.getTimePoint().asMillis());
final Position startPos = getTrackedRace().getTrack(getCompetitor()).getEstimatedPosition(start.getTimePoint(), false);
if (startPos != null) {
Distance d = getTrackedLeg().getAbsoluteWindwardDistance(startPos, endPos, to,
WindPositionMode.EXACT, cache);
result = d.inTime(to.asMillis() - start.getTimePoint().asMillis());
}
}
}
return result;
@@ -613,7 +617,7 @@ public class TrackedLegOfCompetitorImpl implements TrackedLegOfCompetitor {
}
@Override
public Speed getVelocityMadeGood(TimePoint at, WindPositionMode windPositionMode) throws NoWindException {
public Speed getVelocityMadeGood(TimePoint at, WindPositionMode windPositionMode) {
return getVelocityMadeGood(at, windPositionMode, new LeaderboardDTOCalculationReuseCache(at));
}
@@ -452,7 +452,7 @@ public abstract class TrackedRaceImpl extends TrackedRaceWithWindEssentials impl
markPassingsForWaypoint = new ConcurrentHashMap<Waypoint, NavigableSet<MarkPassing>>();
for (Waypoint waypoint : race.getCourse().getWaypoints()) {
markPassingsForWaypoint.put(waypoint, new ConcurrentSkipListSet<MarkPassing>(
MarkPassingByTimeComparator.INSTANCE));
MarkPassingsByTimeAndCompetitorIdComparator.INSTANCE));
}
markPassingsTimes = new ArrayList<com.sap.sse.common.Util.Pair<Waypoint, com.sap.sse.common.Util.Pair<TimePoint, TimePoint>>>();
loadingFromWindStoreState = LoadingFromStoresState.NOT_STARTED;
@@ -697,7 +697,7 @@ public abstract class TrackedRaceImpl extends TrackedRaceWithWindEssentials impl
protected NavigableSet<MarkPassing> createMarkPassingsCollectionForWaypoint(Waypoint waypoint) {
final ConcurrentSkipListSet<MarkPassing> result = new ConcurrentSkipListSet<MarkPassing>(
MarkPassingByTimeComparator.INSTANCE);
MarkPassingsByTimeAndCompetitorIdComparator.INSTANCE);
LockUtil.lockForRead(getSerializationLock());
try {
markPassingsForWaypoint.put(waypoint, result);
@@ -5,17 +5,14 @@ import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.ObjectStreamException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
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.RaceDefinition;
import com.sap.sailing.domain.base.Regatta;
@@ -51,21 +48,19 @@ public class TrackedRegattaImpl implements TrackedRegatta {
*/
private final Map<RaceDefinition, TrackedRace> trackedRaces;
private final Map<BoatClass, Collection<TrackedRace>> trackedRacesByBoatClass;
private transient Set<RaceListener> raceListeners;
private transient ConcurrentHashMap<RaceListener, RaceListener> raceListeners;
public TrackedRegattaImpl(Regatta regatta) {
super();
trackedRacesLock = new NamedReentrantReadWriteLock("trackeRaces lock for tracked regatta "+regatta.getName(), /* fair */ false);
this.regatta = regatta;
this.trackedRaces = new HashMap<RaceDefinition, TrackedRace>();
this.trackedRacesByBoatClass = new HashMap<BoatClass, Collection<TrackedRace>>();
raceListeners = new HashSet<RaceListener>();
raceListeners = new ConcurrentHashMap<RaceListener, RaceListener>();
}
private void readObject(ObjectInputStream ois) throws ClassNotFoundException, IOException {
ois.defaultReadObject();
this.raceListeners = new HashSet<RaceListener>();
this.raceListeners = new ConcurrentHashMap<RaceListener, RaceListener>();
}
@Override
@@ -104,7 +99,6 @@ public class TrackedRegattaImpl implements TrackedRegatta {
private Object readResolve() throws ObjectStreamException {
TrackedRegattaImpl result = new TrackedRegattaImpl(this.regatta);
result.trackedRaces.putAll(this.trackedRaces);
result.trackedRacesByBoatClass.putAll(this.trackedRacesByBoatClass);
return result;
}
@@ -116,19 +110,11 @@ public class TrackedRegattaImpl implements TrackedRegatta {
logger.info("adding tracked race for "+trackedRace.getRace()+" to tracked regatta "+getRegatta().getName()+
" with regatta hash code "+getRegatta().hashCode());
oldTrackedRace = trackedRaces.put(trackedRace.getRace(), trackedRace);
if (oldTrackedRace != trackedRace) {
Collection<TrackedRace> coll = trackedRacesByBoatClass.get(trackedRace.getRace().getBoatClass());
if (coll == null) {
coll = new ArrayList<TrackedRace>();
trackedRacesByBoatClass.put(trackedRace.getRace().getBoatClass(), coll);
}
coll.add(trackedRace);
}
} finally {
LockUtil.unlockAfterWrite(trackedRacesLock);
}
if (oldTrackedRace != trackedRace) {
for (RaceListener listener : raceListeners) {
for (RaceListener listener : raceListeners.keySet()) {
listener.raceAdded(trackedRace);
}
}
@@ -149,14 +135,7 @@ public class TrackedRegattaImpl implements TrackedRegatta {
LockUtil.lockForWrite(trackedRacesLock);
try {
trackedRaces.remove(trackedRace.getRace());
Collection<TrackedRace> trbbc = trackedRacesByBoatClass.get(trackedRace.getRace().getBoatClass());
if (trbbc != null) {
trbbc.remove(trackedRace);
if (trbbc.isEmpty()) {
trackedRacesByBoatClass.remove(trackedRace.getRace().getBoatClass());
}
}
for (RaceListener listener : raceListeners) {
for (RaceListener listener : raceListeners.keySet()) {
listener.raceRemoved(trackedRace);
}
} finally {
@@ -177,23 +156,40 @@ public class TrackedRegattaImpl implements TrackedRegatta {
return trackedRaces.values();
}
@Override
public Iterable<TrackedRace> getTrackedRaces(BoatClass boatClass) {
return trackedRacesByBoatClass.get(boatClass);
}
@Override
public TrackedRace getTrackedRace(RaceDefinition race) {
boolean interrupted = false;
lockTrackedRacesForRead();
try {
TrackedRace result = trackedRaces.get(race);
while (!interrupted && result == null) {
if (!interrupted && result == null) {
final Object mutex = new Object();
final RaceListener listener = new RaceListener() {
@Override
public void raceRemoved(TrackedRace trackedRace) {}
@Override
public void raceAdded(TrackedRace trackedRace) {
synchronized (mutex) {
mutex.notifyAll();
}
}
};
addRaceListener(listener);
try {
trackedRaces.wait();
result = trackedRaces.get(race);
} catch (InterruptedException e) {
interrupted = true;
synchronized (mutex) {
result = trackedRaces.get(race);
while (!interrupted && result == null) {
try {
mutex.wait();
result = trackedRaces.get(race);
} catch (InterruptedException e) {
interrupted = true;
}
}
}
} finally {
removeRaceListener(listener);
}
}
return result;
@@ -217,7 +213,7 @@ public class TrackedRegattaImpl implements TrackedRegatta {
final List<TrackedRace> trackedRacesCopy = new ArrayList<>();
lockTrackedRacesForRead();
try {
raceListeners.add(listener);
raceListeners.put(listener, listener);
Util.addAll(getTrackedRaces(), trackedRacesCopy);
} finally {
unlockTrackedRacesAfterRead();
@@ -227,6 +223,16 @@ public class TrackedRegattaImpl implements TrackedRegatta {
}
}
@Override
public void removeRaceListener(RaceListener listener) {
lockTrackedRacesForRead();
try {
raceListeners.remove(listener);
} finally {
unlockTrackedRacesAfterRead();
}
}
@Override
public int getNetPoints(Competitor competitor, TimePoint timePoint) throws NoWindException {
int result = 0;
@@ -47,8 +47,8 @@
<plugin id="com.sap.sailing.gwt.ui" autoStart="true" startLevel="5" />
<plugin id="com.sap.sailing.kiworesultimport" autoStart="true" startLevel="3" />
<plugin id="com.sap.sailing.manage2sail.resultimport" autoStart="true" startLevel="3" />
<plugin id="com.sap.sailing.news" autoStart="true" startLevel="3" />
<plugin id="com.sap.sailing.monitoring" autoStart="true" startLevel="6" />
<plugin id="com.sap.sailing.news" autoStart="true" startLevel="3" />
<plugin id="com.sap.sailing.polars" autoStart="true" startLevel="4" />
<plugin id="com.sap.sailing.resultimport" autoStart="true" startLevel="3" />
<plugin id="com.sap.sailing.sailwave.resultimport" autoStart="true" startLevel="3" />
@@ -63,7 +63,7 @@
<plugin id="com.sap.sailing.xrr.resultimport" autoStart="true" startLevel="3" />
<plugin id="com.sap.sse.filestorage" autoStart="true" startLevel="3" />
<plugin id="com.sap.sse.mail" autoStart="true" startLevel="4" />
<plugin id="com.sap.sse.replication" autoStart="true" startLevel="4" />
<plugin id="com.sap.sse.replication" autoStart="true" startLevel="5" />
<plugin id="com.sap.sse.security.ui" autoStart="true" startLevel="5" />
<plugin id="com.sap.sse.security.userstore.mongodb" autoStart="true" startLevel="3" />
<plugin id="org.apache.felix.shell" autoStart="true" startLevel="0" />
@@ -11,7 +11,6 @@ import java.util.Set;
import com.sap.sailing.domain.abstractlog.race.RaceLog;
import com.sap.sailing.domain.abstractlog.race.analyzing.impl.RaceLogResolver;
import com.sap.sailing.domain.abstractlog.regatta.RegattaLog;
import com.sap.sailing.domain.base.BoatClass;
import com.sap.sailing.domain.base.Competitor;
import com.sap.sailing.domain.base.CourseBase;
import com.sap.sailing.domain.base.Leg;
@@ -274,11 +273,6 @@ public class MockedTrackedRace implements DynamicTrackedRace {
return null;
}
@Override
public Iterable<TrackedRace> getTrackedRaces(BoatClass boatClass) {
return null;
}
@Override
public void addTrackedRace(TrackedRace trackedRace) {
}
@@ -333,6 +327,10 @@ public class MockedTrackedRace implements DynamicTrackedRace {
@Override
public void unlockTrackedRacesAfterWrite() {
}
@Override
public void removeRaceListener(RaceListener listener) {
}
};
}
@@ -25,7 +25,7 @@ public interface BoatClassImageResources extends ClientBundle {
@Source("com/sap/sailing/gwt/ui/client/images/boatclass/470.png")
ImageResource _470Icon();
@Source("com/sap/sailing/gwt/ui/client/images/boatclass/49ER_FX.png")
@Source("com/sap/sailing/gwt/ui/client/images/boatclass/49ER_FX.jpg")
ImageResource _49erFXIcon();
@Source("com/sap/sailing/gwt/ui/client/images/boatclass/49ER.png")
@@ -3132,7 +3132,7 @@ public class SailingServiceImpl extends ProxiedRemoteServiceServlet implements S
StrippedLeaderboardDTO leaderboardDTO = createStrippedLeaderboardDTO(leaderboard, withGeoLocationData, withStatisticalData);
groupDTO.leaderboards.add(leaderboardDTO);
} catch (Exception e) {
logger.log(Level.SEVERE, "Catched exception while reading data for leaderboard " + leaderboard.getName(), e);
logger.log(Level.SEVERE, "Caught exception while reading data for leaderboard " + leaderboard.getName(), e);
}
}
Leaderboard overallLeaderboard = leaderboardGroup.getOverallLeaderboard();
Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.6 KiB

@@ -8,6 +8,7 @@ import java.net.UnknownHostException;
import java.util.Collection;
import java.util.UUID;
import org.junit.Before;
import org.junit.Test;
import com.mongodb.DB;
@@ -16,6 +17,7 @@ import com.mongodb.MongoException;
import com.mongodb.WriteConcern;
import com.sap.sailing.domain.base.Competitor;
import com.sap.sailing.domain.base.DomainFactory;
import com.sap.sailing.domain.base.impl.DomainFactoryImpl;
import com.sap.sailing.domain.base.impl.DynamicCompetitor;
import com.sap.sailing.domain.persistence.DomainObjectFactory;
import com.sap.sailing.domain.persistence.MongoObjectFactory;
@@ -25,11 +27,18 @@ import com.sap.sailing.domain.test.AbstractLeaderboardTest;
import com.sap.sse.common.Util;
public class StoreCompetitorTest extends AbstractMongoDBTest {
private DomainFactory domainFactory;
public StoreCompetitorTest() throws UnknownHostException, MongoException {
super();
}
@Before
public void setUp() {
// clear the domainFactory competitor store for a clean start:
domainFactory = new DomainFactoryImpl();
}
private void dropCompetitorCollection() {
DB db = getMongoService().getDB();
DBCollection competitorCollection = db.getCollection(CollectionNames.COMPETITORS.name());
@@ -45,7 +54,7 @@ public class StoreCompetitorTest extends AbstractMongoDBTest {
String competitorName2 = "Hasso Plattner";
MongoObjectFactory mongoObjectFactory = PersistenceFactory.INSTANCE.getMongoObjectFactory(getMongoService());
DomainObjectFactory domainObjectFactory = PersistenceFactory.INSTANCE.getDomainObjectFactory(getMongoService(), DomainFactory.INSTANCE);
DomainObjectFactory domainObjectFactory = PersistenceFactory.INSTANCE.getDomainObjectFactory(getMongoService(), domainFactory);
dropCompetitorCollection();
DynamicCompetitor c = AbstractLeaderboardTest.createCompetitor(competitorName1);
@@ -72,7 +81,7 @@ public class StoreCompetitorTest extends AbstractMongoDBTest {
@Test
public void testStoreAndUpdateCompetitorWithUUIDAsId() {
MongoObjectFactory mongoObjectFactory = PersistenceFactory.INSTANCE.getMongoObjectFactory(getMongoService());
DomainObjectFactory domainObjectFactory = PersistenceFactory.INSTANCE.getDomainObjectFactory(getMongoService(), DomainFactory.INSTANCE);
DomainObjectFactory domainObjectFactory = PersistenceFactory.INSTANCE.getDomainObjectFactory(getMongoService(), domainFactory);
dropCompetitorCollection();
DynamicCompetitor c = AbstractLeaderboardTest.createCompetitor("Hasso", UUID.randomUUID());
@@ -86,7 +95,7 @@ public class StoreCompetitorTest extends AbstractMongoDBTest {
@Test
public void testStoreAndRemoveCompetitor() {
MongoObjectFactory mongoObjectFactory = PersistenceFactory.INSTANCE.getMongoObjectFactory(getMongoService());
DomainObjectFactory domainObjectFactory = PersistenceFactory.INSTANCE.getDomainObjectFactory(getMongoService(), DomainFactory.INSTANCE);
DomainObjectFactory domainObjectFactory = PersistenceFactory.INSTANCE.getDomainObjectFactory(getMongoService(), domainFactory);
dropCompetitorCollection();
DynamicCompetitor c = AbstractLeaderboardTest.createCompetitor("Hasso");
@@ -100,7 +109,7 @@ public class StoreCompetitorTest extends AbstractMongoDBTest {
@Test
public void testStoreAndRemoveCompetitorWithUUIDAsId() {
MongoObjectFactory mongoObjectFactory = PersistenceFactory.INSTANCE.getMongoObjectFactory(getMongoService());
DomainObjectFactory domainObjectFactory = PersistenceFactory.INSTANCE.getDomainObjectFactory(getMongoService(), DomainFactory.INSTANCE);
DomainObjectFactory domainObjectFactory = PersistenceFactory.INSTANCE.getDomainObjectFactory(getMongoService(), domainFactory);
dropCompetitorCollection();
DynamicCompetitor c = AbstractLeaderboardTest.createCompetitor("Hasso", UUID.randomUUID());
@@ -17,6 +17,7 @@ public class RegattaJsonSerializer implements JsonSerializer<Regatta> {
public static final String FIELD_SERIES = "series";
public static final String FIELD_COMPETITORS = "competitors";
public static final String FIELD_TRACKED_RACES = "trackedRaces";
public static final String FIELD_COURSE_AREA_ID = "courseAreaId";
private final JsonSerializer<Series> seriesSerializer;
private final JsonSerializer<Competitor> competitorSerializer;
@@ -38,6 +39,7 @@ public class RegattaJsonSerializer implements JsonSerializer<Regatta> {
result.put(FIELD_END_DATE, regatta.getEndDate() != null ? regatta.getEndDate().asMillis() : null);
result.put(FIELD_SCORINGSYSTEM, regatta.getScoringScheme().getType().name());
result.put(FIELD_BOATCLASS, regatta.getBoatClass() != null ? regatta.getBoatClass().getName(): null);
result.put(FIELD_COURSE_AREA_ID, regatta.getDefaultCourseArea() != null ? regatta.getDefaultCourseArea().getId().toString(): null);
if(seriesSerializer != null) {
JSONArray seriesJson = new JSONArray();
@@ -287,14 +287,10 @@ public class RegattaAndRaceDataJsonGetServlet extends AbstractJsonHttpServlet {
jsonCompetitorInLeg.put("distanceTraveledOverGroundInMeters",
distanceTraveled.getMeters());
}
try {
Speed velocityMadeGood = trackedLegOfCompetitor.getVelocityMadeGood(timePoint, WindPositionMode.EXACT);
if (velocityMadeGood != null) {
jsonCompetitorInLeg.put("velocityMadeGoodInKnots", velocityMadeGood.getKnots());
jsonCompetitorInLeg.put("velocityMadeGoodInMetersPerSecond", velocityMadeGood.getMetersPerSecond());
}
} catch (NoWindException e) {
// well, we don't know the wind direction... then no VMG will be shown...
Speed velocityMadeGood = trackedLegOfCompetitor.getVelocityMadeGood(timePoint, WindPositionMode.EXACT);
if (velocityMadeGood != null) {
jsonCompetitorInLeg.put("velocityMadeGoodInKnots", velocityMadeGood.getKnots());
jsonCompetitorInLeg.put("velocityMadeGoodInMetersPerSecond", velocityMadeGood.getMetersPerSecond());
}
Speed averageVelocityMadeGood = trackedLegOfCompetitor
.getAverageVelocityMadeGood(timePoint);
@@ -0,0 +1,32 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<launchConfiguration type="org.eclipse.pde.ui.EquinoxLauncher">
<booleanAttribute key="append.args" value="true"/>
<booleanAttribute key="automaticAdd" value="false"/>
<booleanAttribute key="automaticValidate" value="false"/>
<stringAttribute key="bootstrap" value=""/>
<stringAttribute key="checked" value="[NONE]"/>
<booleanAttribute key="clearConfig" value="false"/>
<stringAttribute key="configLocation" value="${workspace_loc}/target"/>
<booleanAttribute key="default" value="true"/>
<booleanAttribute key="default_auto_start" value="true"/>
<intAttribute key="default_start_level" value="4"/>
<booleanAttribute key="includeOptional" value="true"/>
<listAttribute key="org.eclipse.debug.ui.favoriteGroups">
<listEntry value="org.eclipse.debug.ui.launchGroup.debug"/>
<listEntry value="org.eclipse.debug.ui.launchGroup.run"/>
</listAttribute>
<booleanAttribute key="org.eclipse.jdt.launching.ATTR_USE_START_ON_FIRST_THREAD" 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.PROGRAM_ARGUMENTS" value="-os ${target.os} -ws ${target.ws} -arch ${target.arch} -nl ${target.nl} -consoleLog -console -clean"/>
<stringAttribute key="org.eclipse.jdt.launching.SOURCE_PATH_PROVIDER" value="org.eclipse.pde.ui.workbenchClasspathProvider"/>
<stringAttribute key="org.eclipse.jdt.launching.VM_ARGUMENTS" value="-Djetty.port=8889 -Dreplication.exchangeName=sapsailinganalytics-replica -Declipse.ignoreApp=true -Dosgi.noShutdown=true&#13;&#10;-Dexpedition.udp.port=2011 -Xmx6000m -XX:+UseG1GC -Djetty.home=${project_loc:com.sap.sailing.server}/../target/configuration/jetty -Djava.util.logging.config.file=${project_loc:com.sap.sailing.server}/../target/configuration/logging_debug.properties -XX:+UseMembar -Dmongo.dbName=replica -Dreplicate.on.start=com.sap.sailing.server.impl.RacingEventServiceImpl,com.sap.sse.security.impl.SecurityServiceImpl,com.sap.sse.filestorage.impl.FileStorageManagementServiceImpl,com.sap.sse.mail.impl.MailServiceImpl -Dreplicate.master.queue.host=127.0.0.1 -Dreplicate.master.queue.port=5672 -Dreplicate.master.servlet.port=8888 -Dreplicate.master.servlet.host=127.0.0.1"/>
<stringAttribute key="org.eclipse.jdt.launching.WORKING_DIRECTORY" value="${workspace_loc}"/>
<stringAttribute key="pde.version" value="3.3"/>
<booleanAttribute key="show_selected_only" value="false"/>
<stringAttribute key="target_bundles" value="com.fasterxml.jackson.core.jackson-annotations@default:default,com.fasterxml.jackson.core.jackson-core@default:default,com.fasterxml.jackson.core.jackson-databind@default:default,com.fasterxml.jackson.jaxrs.jackson-jaxrs-base@default:default,com.fasterxml.jackson.jaxrs.jackson-jaxrs-json-provider@default:default,com.rabbitmq.client@default:default,com.sun.jersey.contribs.jersey-multipart@default:default,com.sun.jersey@default:default,com.sun.mail.javax.mail@default:default,jackson-core-lgpl@default:default,jackson-jaxrs@default:default,jackson-mapper-lgpl@default:default,javax.servlet@default:default,javax.validation@default:default,javax.ws.rs@default:default,jcl.over.slf4j@default:default,org.apache.commons.beanutils@default:default,org.apache.commons.codec@default:default,org.apache.commons.collections@default:default,org.apache.commons.fileupload@default:default,org.apache.commons.io@default:default,org.apache.commons.lang@default:default,org.apache.commons.logging@default:default,org.apache.commons.math@default:default,org.apache.felix.gogo.command@default:default,org.apache.felix.gogo.runtime@default:default,org.apache.felix.gogo.shell@default:default,org.apache.geronimo.specs.geronimo-annotation_1.0_spec@default:default,org.apache.geronimo.specs.geronimo-j2ee-management_1.1_spec@default:default,org.apache.geronimo.specs.geronimo-jms_1.1_spec@default:default,org.apache.httpcomponents.httpclient@default:default,org.apache.httpcomponents.httpcore@default:default,org.apache.servicemix.bundles.aws-java-sdk@default:default,org.apache.servicemix.bundles.ehcache@default:default,org.apache.servicemix.bundles.scribe@default:default,org.apache.servicemix.bundles.zxing@default:default,org.apache.shiro.core@default:default,org.apache.shiro.ehcache@default:default,org.apache.shiro.web@default:default,org.eclipse.equinox.common@2:true,org.eclipse.equinox.console@default:default,org.eclipse.jetty.continuation@default:default,org.eclipse.jetty.deploy@default:default,org.eclipse.jetty.http@default:default,org.eclipse.jetty.io@default:default,org.eclipse.jetty.jmx@default:default,org.eclipse.jetty.osgi.boot@3:default,org.eclipse.jetty.security@default:default,org.eclipse.jetty.server@default:default,org.eclipse.jetty.servlet@default:default,org.eclipse.jetty.util@default:default,org.eclipse.jetty.webapp@default:default,org.eclipse.jetty.websocket.api@default:default,org.eclipse.jetty.websocket.client@default:default,org.eclipse.jetty.websocket.common@default:default,org.eclipse.jetty.websocket.server@default:default,org.eclipse.jetty.websocket.servlet@default:default,org.eclipse.jetty.xml@default:default,org.eclipse.osgi.services@default:default,org.eclipse.osgi@-1:true,org.jdom@default:default,org.jvnet.mimepull@default:default,org.mongodb.mongo-java-driver@default:default,org.objectweb.asm@default:default,rome@default:default,routeconverter@default:default,slf4j.api@default:default,slf4j.jdk14@default:false"/>
<booleanAttribute key="tracing" value="false"/>
<booleanAttribute key="useCustomFeatures" value="false"/>
<booleanAttribute key="useDefaultConfigArea" value="false"/>
<stringAttribute key="workspace_bundles" value="com.google.gwt.osgi@default:default,com.googlecode.java-diff-utils@default:default,com.googlecode.mgwt@default:default,com.sap.sailing.barbados.resultimport@default:default,com.sap.sailing.dashboards.gwt@5:true,com.sap.sailing.datamining.shared@default:default,com.sap.sailing.datamining@default:default,com.sap.sailing.declination@default:default,com.sap.sailing.domain.common@default:default,com.sap.sailing.domain.deckmanadapter@4:true,com.sap.sailing.domain.igtimiadapter.persistence@default:default,com.sap.sailing.domain.igtimiadapter@default:default,com.sap.sailing.domain.persistence@default:default,com.sap.sailing.domain.racelogtrackingadapter@3:default,com.sap.sailing.domain.shared.android@default:default,com.sap.sailing.domain.swisstimingadapter.persistence@default:default,com.sap.sailing.domain.swisstimingadapter@4:true,com.sap.sailing.domain.swisstimingreplayadapter@4:true,com.sap.sailing.domain.tractracadapter.persistence@default:default,com.sap.sailing.domain.tractracadapter@4:true,com.sap.sailing.domain@default:default,com.sap.sailing.ess40.resultimport@default:default,com.sap.sailing.expeditionconnector@default:default,com.sap.sailing.freg.resultimport@default:default,com.sap.sailing.geocoding@default:default,com.sap.sailing.gwt.ui@5:true,com.sap.sailing.kiworesultimport@default:default,com.sap.sailing.manage2sail.resultimport@default:default,com.sap.sailing.manage2sail@default:default,com.sap.sailing.news@default:default,com.sap.sailing.nmeaconnector@default:default,com.sap.sailing.polars@4:true,com.sap.sailing.resultimport@default:default,com.sap.sailing.sailwave.resultimport@default:default,com.sap.sailing.server.gateway.ess40@4:true,com.sap.sailing.server.gateway.serialization.shared.android@default:default,com.sap.sailing.server.gateway.serialization@default:default,com.sap.sailing.server.gateway@5:true,com.sap.sailing.server.trackfiles@default:default,com.sap.sailing.server@default:default,com.sap.sailing.simulator@default:default,com.sap.sailing.udpconnector@default:default,com.sap.sailing.velum.resultimport@default:default,com.sap.sailing.www.events@4:true,com.sap.sailing.www@4:true,com.sap.sailing.xrr.resultimport@default:default,com.sap.sailing.xrr.schema@default:default,com.sap.sailing.xrr.structureimport@default:default,com.sap.sse.common@default:default,com.sap.sse.datamining.shared@default:default,com.sap.sse.datamining@default:default,com.sap.sse.filestorage@default:default,com.sap.sse.gwt.adminconsole@default:default,com.sap.sse.gwt.theme@default:default,com.sap.sse.gwt@default:default,com.sap.sse.mail@4:true,com.sap.sse.mongodb@default:default,com.sap.sse.operationaltransformation@default:default,com.sap.sse.replication@4:true,com.sap.sse.security.common@default:default,com.sap.sse.security.ui@6:true,com.sap.sse.security.userstore.mongodb@4:true,com.sap.sse.security@5:true,com.sap.sse.shared.android@default:default,com.sap.sse@default:default,com.tractrac.clientmodule@default:default,net.sf.marineapi@default:default,org.json.simple@default:default,org.moxieapps.gwt.highcharts@default:default"/>
<stringAttribute key="yk-options" value="&#13;&#10;additional-options2=onexit\=snapshot&#13;&#10;"/>
</launchConfiguration>
@@ -30,14 +30,24 @@ public interface ReplicationService {
*/
ReplicationMasterDescriptor getReplicatingFromMaster();
/**
* Same as {@link #startToReplicateFrom(ReplicationMasterDescriptor, Iterable)}, where the list of replicables
* is determined by asking this service's {@link ReplicablesProvider} which replicables are currently available.
* Note that this is not a good idea during the OSGi start-up phase, particularly if there is a bundle that
* starts after this bundle because then that {@link Replicable} will not yet be registered and won't become part
* of replication.
*/
void startToReplicateFrom(ReplicationMasterDescriptor master) throws IOException, ClassNotFoundException, InterruptedException;
/**
* Performs a servlet request to the remote master server's {@link ReplicationServlet}, first registering this
* replica, ensuring the message queue for replicating operations is created, then subscribing to the master's
* replication message queue and asking the servlet for the stream containing the initial load which will then be
* used to {@link Replicable#initiallyFillFrom(java.io.ObjectInputStream) replace} the current {@link Replicable}'s
* used to {@link Replicable#initiallyFillFrom(java.io.ObjectInputStream) replace} the {@link Replicable replicables}'
* state.
*/
void startToReplicateFrom(ReplicationMasterDescriptor master) throws IOException, ClassNotFoundException, InterruptedException;
void startToReplicateFrom(ReplicationMasterDescriptor master, Iterable<Replicable<?, ?>> replicables) throws IOException,
ClassNotFoundException, InterruptedException;
/**
* Registers a replica with this master instance. The <code>replica</code> will be considered in the result of
@@ -1,12 +1,15 @@
package com.sap.sse.replication.impl;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.logging.Logger;
import org.osgi.framework.BundleActivator;
import org.osgi.framework.BundleContext;
import com.sap.sse.replication.Replicable;
import com.sap.sse.replication.ReplicablesProvider;
import com.sap.sse.replication.ReplicationService;
@@ -129,12 +132,16 @@ public class Activator implements BundleActivator {
new Thread("ServiceTracker waiting for Replicables "+Arrays.toString(replicableIdsAsStrings)) {
@Override
public void run() {
logger.info("Waiting for Replicables " + replicableIdsAsStrings + " before firing up replication automatically...");
logger.info("Waiting for Replicables " + Arrays.toString(replicableIdsAsStrings) +
" before firing up replication automatically...");
final List<Replicable<?, ?>> replicables = new ArrayList<>();
for (String replicableIdAsString : replicableIdsAsStrings) {
replicablesProvider.getReplicable(replicableIdAsString, /* wait */true);
Replicable<?, ?> replicable = replicablesProvider.getReplicable(replicableIdAsString, /* wait */true);
logger.info("Obtained Replicable " + replicableIdAsString);
replicables.add(replicable);
}
logger.info("Configuration requested automatic replication. Starting it up...");
logger.info("Configuration requested automatic replication for replicables "+
Arrays.toString(replicableIdsAsStrings)+". Starting it up...");
String replicateFromExchangeName = System.getProperty(PROPERTY_NAME_REPLICATE_MASTER_EXCHANGE_NAME);
if (replicateFromExchangeName == null) {
replicateFromExchangeName = masterExchangeName;
@@ -147,8 +154,8 @@ public class Activator implements BundleActivator {
System.getProperty(PROPERTY_NAME_REPLICATE_MASTER_SERVLET_HOST),
Integer.valueOf(System.getProperty(PROPERTY_NAME_REPLICATE_MASTER_SERVLET_PORT).trim()));
try {
// TODO pass on the replicables to wait for
serverReplicationMasterService.startToReplicateFrom(master);
// TODO pass on the replicables to wait for; failure to do so can cause the symptoms of bug 3015
serverReplicationMasterService.startToReplicateFrom(master, replicables);
logger.info("Automatic replication has been started.");
} catch (ClassNotFoundException | IOException | InterruptedException e) {
e.printStackTrace();
@@ -476,7 +476,14 @@ public class ReplicationServiceImpl implements ReplicationService {
*/
@Override
public void startToReplicateFrom(ReplicationMasterDescriptor master) throws IOException, ClassNotFoundException, InterruptedException {
logger.info("Starting to replicate from "+master);
final Iterable<Replicable<?, ?>> replicables = getReplicables();
startToReplicateFrom(master, replicables);
}
@Override
public void startToReplicateFrom(ReplicationMasterDescriptor master, Iterable<Replicable<?, ?>> replicables)
throws IOException, ClassNotFoundException, InterruptedException {
logger.info("Starting to replicate from " + master);
try {
registerReplicaWithMaster(master);
} catch (Exception ex) {
@@ -497,14 +504,13 @@ public class ReplicationServiceImpl implements ReplicationService {
throw ex;
}
logger.info("Connection to exchange successful.");
final Iterable<Replicable<?, ?>> replicables = replicablesProvider.getReplicables();
URL initialLoadURL = master.getInitialLoadURL(replicables);
logger.info("Initial load URL is "+initialLoadURL);
// start receiving messages already now, but start in suspended mode
replicator = new ReplicationReceiver(master, replicablesProvider, /* startSuspended */true, consumer);
// clear Replicable state here, before starting to receive and de-serialized operations which builds up
// new state, e.g., in competitor store
for (Replicable<?, ?> r : getReplicables()) {
for (Replicable<?, ?> r : replicables) {
r.clearReplicaState();
r.startedReplicatingFrom(master);
}
@@ -517,7 +523,7 @@ public class ReplicationServiceImpl implements ReplicationService {
RabbitInputStreamProvider rabbitInputStreamProvider = new RabbitInputStreamProvider(master.createChannel(), queueName);
try {
final GZIPInputStream gzipInputStream = new GZIPInputStream(rabbitInputStreamProvider.getInputStream());
for (Replicable<?, ?> replicable : getReplicables()) {
for (Replicable<?, ?> replicable : replicables) { // absolutely make sure to use the same sequence of replicables as for URL (bug 3015)
logger.info("Starting to receive initial load for "+replicable.getId());
try {
replicable.initiallyFillFrom(gzipInputStream);
@@ -527,9 +533,9 @@ public class ReplicationServiceImpl implements ReplicationService {
}
logger.info("Done receiving initial load for "+replicable.getId());
}
} finally {
logger.info("Resuming replicator to apply queues");
replicator.setSuspended(false); // apply queued operations
} finally {
// delete initial load queue
DeleteOk deleteOk = consumer.getChannel().queueDelete(queueName);
logger.info("Deleted queue " + queueName + " used for initial load: " + deleteOk.toString());
+6 -2
View File
@@ -246,12 +246,16 @@ if [[ $OPERATION == "auto-install" ]]; then
activate_user_data
# then download and install environment and append to env.sh
install_environment
# finally, append user data to env.sh as it shall take precedence over the installed environment's defaults
append_user_data_to_envsh
# finally, append user data to env.sh as it shall take precedence over the installed environment's defaults
append_user_data_to_envsh
# make sure to reload data
source `pwd`/env.sh
# Append Apache macro invocation for /internal-server-status based on mod_status and INSTANCE_DNS to /etc/httpd/conf.d/001-events.conf
APACHE_CONFIG_DIR=/etc/httpd/conf.d
echo "Appending macro usage for /internal-server-status URL for mod_status based Apache monitoring to $APACHE_CONFIG_DIR/001-events.conf"
echo "Use Status $INSTANCE_DNS internal-server-status" >>$APACHE_CONFIG_DIR/001-events.conf
if [[ $INSTALL_FROM_RELEASE == "" ]] && [[ $BUILD_BEFORE_START != "True" ]]; then
echo "I could not find any option telling me to download a release or to build! Possible cause: Your environment contains empty values for these variables!"