Merge branch 'master' into windestimation

Change-Id: I1356ad8c307e20dfa114aa2438f6d1d3c5898793
This commit is contained in:
Axel Uhl committed 2019-05-15 11:50:29 +02:00
commit b6dd97ef8b
179 files changed
+4656 -2688

No files matched your search

@@ -16,7 +16,9 @@ import com.sap.sailing.domain.base.RaceColumnListener;
import com.sap.sailing.domain.base.impl.RaceColumnListenerWithDefaultAction;
import com.sap.sailing.domain.common.LeaderboardNameConstants;
import com.sap.sailing.domain.common.MaxPointsReason;
import com.sap.sailing.domain.common.RankingMetrics;
import com.sap.sailing.domain.leaderboard.Leaderboard;
import com.sap.sailing.domain.leaderboard.RegattaLeaderboard;
import com.sap.sailing.domain.leaderboard.ScoringScheme;
import com.sap.sailing.domain.racelog.RaceLogIdentifier;
import com.sap.sailing.server.interfaces.RacingEventService;
@@ -65,8 +67,8 @@ public class RaceLogScoringReplicator implements RaceColumnListenerWithDefaultAc
/**
* Called when a {@link RaceLogFinishPositioningConfirmedEvent} was received by the {@link RaceLog}. Retrieves the
* last {@link RaceLogFinishPositioningConfirmedEvent} from the racelog and applies the ranks and disqualifications
* entered by the race committee to the score correstions as follows:
* last {@link RaceLogFinishPositioningConfirmedEvent} from the {@link RaceLog} and applies the ranks and
* disqualifications entered by the race committee to the score corrections as follows:
* <ul>
* <li>When no {@link CompetitorResult} object is received for a competitor, no change is applied to that
* competitor's score corrections.</li>
@@ -75,11 +77,13 @@ public class RaceLogScoringReplicator implements RaceColumnListenerWithDefaultAc
* {@link MaxPointsReason}, any existing score correction (points) is removed for that competitor, otherwise, the
* score correction (points) from the CompetitorResult object is applied if provided (in this case a rank provided
* in the {@link CompetitorResult} object is ignored); if no {@link MaxPointsReason} is provided and only a rank but
* no score is provided in the {@link CompetitorResult}, the scoring scheme will compute the score from the rank,
* considering any {@link MaxPointsReason} provided in the result, and that score will be applied as a score
* correction. If a {@link MaxPointsReason} but no explicit score is provided, the rank is ignored because
* the scoring scheme is expected to compute the score from the {@link MaxPointsReason}; therefore, the score
* correction (points) is cleared in this case so that the scoring scheme will be used for score calculation.</li>
* no score is provided in the {@link CompetitorResult}, the scoring scheme will
* {@link ScoringScheme#getScoreForRank(Leaderboard, RaceColumn, Competitor, int, java.util.concurrent.Callable, com.sap.sailing.domain.leaderboard.NumberOfCompetitorsInLeaderboardFetcher, TimePoint)
* compute} the score from the rank, considering any {@link MaxPointsReason} provided in the result, and that score
* will be applied as a score correction. If a {@link MaxPointsReason} but no explicit score is provided, the rank
* is ignored because the scoring scheme is expected to compute the score from the {@link MaxPointsReason};
* therefore, the score correction (points) is cleared in this case so that the scoring scheme will be used for
* score calculation.</li>
* <li>When a {@link CompetitorResult} object is received for a competitor, if it contains {@code null} for the
* {@link MaxPointsReason}, any existing {@link MaxPointsReason} is removed for that competitor; otherwise, the
* {@link MaxPointsReason} from the {@link CompetitorResult} object is applied, and if no explicit score is provided
@@ -174,8 +178,17 @@ public class RaceLogScoringReplicator implements RaceColumnListenerWithDefaultAc
// let scoring scheme calculate the penalty score dynamically
scoreByRaceCommittee = null;
} else {
scoreByRaceCommittee = leaderboard.getScoringScheme().getScoreForRank(leaderboard, raceColumn, competitor,
oneBasedRankByRaceCommittee, ()->numberOfCompetitorsInRace, leaderboard.getNumberOfCompetitorsInLeaderboardFetcher(), timePoint);
// Check whether it's a non-one-design regatta. In that case, "rank by race committee" just means finish line
// crossing order, but that's not relevant for the actual *ranking* in a handicapped regatta. Corrected/calculated
// times are. Therefore, for handicap regattas, don't ask the scoring scheme to map the finishing order
// to a score.
if (leaderboard instanceof RegattaLeaderboard &&
((RegattaLeaderboard) leaderboard).getRegatta().getRankingMetricType() != RankingMetrics.ONE_DESIGN) {
scoreByRaceCommittee = null;
} else {
scoreByRaceCommittee = leaderboard.getScoringScheme().getScoreForRank(leaderboard, raceColumn, competitor,
oneBasedRankByRaceCommittee, ()->numberOfCompetitorsInRace, leaderboard.getNumberOfCompetitorsInLeaderboardFetcher(), timePoint);
}
}
} else {
scoreByRaceCommittee = optionalExplicitScore;
@@ -2,8 +2,9 @@ package com.sap.sailing.server.security;
import java.io.Serializable;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Optional;
import java.util.function.Supplier;
import java.util.concurrent.Callable;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.subject.Subject;
@@ -51,16 +52,21 @@ public class PermissionAwareRaceTrackingHandler extends DefaultRaceTrackingHandl
defaultTenant = securityService.getDefaultTenantForCurrentUser();
}
private <T> T decorate(RegattaAndRaceIdentifier regattaAndRaceIdentifier, Supplier<T> innerAction) {
/**
* Sets the ownership for a {@link SecuredDomainType#TRACKED_RACE} object identified by
* {@code regattaAndRaceIdentifier} if no ownership exists for it yet; then, the permission to
* create the object is checked. If granted, the {@code raceCreationAction} is executed and its
* result is returned. Otherwise, the action is not executed, and if the ownership was set here,
* it is removed again.
*/
private <T> T setOwnershipForRace(RegattaAndRaceIdentifier regattaAndRaceIdentifier, Callable<T> raceCreationAction) {
SubjectThreadState subjectThreadState = new SubjectThreadState(subject);
subjectThreadState.bind();
try {
return securityService.doWithTemporaryDefaultTenant(defaultTenant, () -> {
return securityService.setOwnershipCheckPermissionForObjectCreationAndRevertOnError(
SecuredDomainType.TRACKED_RACE, regattaAndRaceIdentifier.getTypeRelativeObjectIdentifier(),
regattaAndRaceIdentifier.toString(), () -> {
return innerAction.get();
});
regattaAndRaceIdentifier.toString(), raceCreationAction);
});
} finally {
subjectThreadState.restore();
@@ -73,7 +79,7 @@ public class PermissionAwareRaceTrackingHandler extends DefaultRaceTrackingHandl
long millisecondsOverWhichToAverageWind, long millisecondsOverWhichToAverageSpeed,
DynamicRaceDefinitionSet raceDefinitionSetToUpdate, boolean useMarkPassingCalculator,
RaceLogResolver raceLogResolver, Optional<ThreadLocalTransporter> threadLocalTransporter) {
return decorate(new RegattaNameAndRaceName(trackedRegatta.getRegatta().getName(), raceDefinition.getName()),
return setOwnershipForRace(new RegattaNameAndRaceName(trackedRegatta.getRegatta().getName(), raceDefinition.getName()),
() -> super.createTrackedRace(trackedRegatta, raceDefinition, sidelines, windStore, delayToLiveInMillis,
millisecondsOverWhichToAverageWind, millisecondsOverWhichToAverageSpeed,
raceDefinitionSetToUpdate, useMarkPassingCalculator, raceLogResolver, threadLocalTransporter));
@@ -82,7 +88,22 @@ public class PermissionAwareRaceTrackingHandler extends DefaultRaceTrackingHandl
@Override
public RaceDefinition createRaceDefinition(Regatta regatta, String name, Course course, BoatClass boatClass,
Map<Competitor, Boat> competitorsAndTheirBoats, Serializable id) {
return decorate(new RegattaNameAndRaceName(regatta.getName(), name),
// TODO bug 5015: this is just a very basic hack that is not checking for competitor creation permission but for now only establishes an ownership when none exists
SubjectThreadState subjectThreadState = new SubjectThreadState(subject);
subjectThreadState.bind();
try {
for (final Entry<Competitor, Boat> e : competitorsAndTheirBoats.entrySet()) {
if (securityService.getOwnership(e.getKey().getIdentifier()) == null) {
securityService.setOwnership(e.getKey().getIdentifier(), securityService.getCurrentUser(), defaultTenant);
}
if (securityService.getOwnership(e.getValue().getIdentifier()) == null) {
securityService.setOwnership(e.getValue().getIdentifier(), securityService.getCurrentUser(), defaultTenant);
}
}
} finally {
subjectThreadState.restore();
}
return setOwnershipForRace(new RegattaNameAndRaceName(regatta.getName(), name),
() -> super.createRaceDefinition(regatta, name, course, boatClass, competitorsAndTheirBoats, id));
}
}