Merge branch 'bug4343'

# Conflicts:
#	java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/event/regatta/analyticstab/RegattaCompetitorAnalyticsTabView.java
#	java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/event/regatta/leaderboardtab/RegattaLeaderboardTabView.java
#	java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/fakeseries/analyticstab/EventSeriesCompetitorAnalyticsTabView.java
#	java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/fakeseries/leaderboardstab/EventSeriesLeaderboardsTabView.java
#	java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/fakeseries/overallleaderboardtab/EventSeriesOverallLeaderboardTabView.java
#	java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/leaderboard/LeaderboardEntryPoint.java
#	java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/leaderboardedit/LeaderboardEditPage.java
This commit is contained in:
Steffen Schaefer committed 2018-06-26 14:12:48 +02:00
commit 1bae7e936a
52 files changed
+888 -282

No files matched your search

@@ -1,12 +1,9 @@
package com.sap.sailing.dashboards.gwt.client;
import com.google.gwt.core.client.GWT;
import com.google.gwt.user.client.rpc.ServiceDefTarget;
import com.sap.sailing.dashboards.gwt.shared.dispatch.DashboardDispatchSystem;
import com.sap.sailing.dashboards.gwt.shared.dispatch.impl.DashboardDispatchSystemImpl;
import com.sap.sailing.gwt.ui.client.SailingService;
import com.sap.sailing.gwt.ui.client.SailingServiceAsync;
import com.sap.sse.gwt.client.EntryPointHelper;
import com.sap.sailing.gwt.ui.client.SailingServiceHelper;
import com.sap.sse.gwt.client.player.Timer;
import com.sap.sse.gwt.client.player.Timer.PlayModes;
@@ -24,8 +21,7 @@ public class DashboardClientFactoryImpl implements DashboardClientFactory{
public DashboardClientFactoryImpl() {
dispatch = new DashboardDispatchSystemImpl();
sailingService = GWT.create(SailingService.class);
EntryPointHelper.registerASyncService((ServiceDefTarget) sailingService, RemoteServiceMappingConstants.WEB_CONTEXT_PATH, RemoteServiceMappingConstants.sailingServiceRemotePath);
sailingService = SailingServiceHelper.createSailingServiceInstance(false);
dashboardFiveSecondsTimer = new Timer(PlayModes.Live);
dashboardFiveSecondsTimer.setRefreshInterval(DASHBOARD_RERFRESH_INTERVAL);
@@ -17,6 +17,7 @@ Export-Package: com.sap.sailing.domain.common,
com.sap.sailing.domain.common.quadtree,
com.sap.sailing.domain.common.quadtree.impl;x-friends:="com.sap.sailing.domain.test",
com.sap.sailing.domain.common.racelog,
com.sap.sailing.domain.common.sharding,
com.sap.sailing.domain.common.racelog.tracking,
com.sap.sailing.domain.common.racelog.utils,
com.sap.sailing.domain.common.scalablevalue.impl,
@@ -0,0 +1,61 @@
package com.sap.sailing.domain.common.sharding;
/**
* Enum that defines all sharding types known by the system.
*
* For a sharding to work, we need both client and backend properly identifying a shard.
*
* While the client has to properly deliver sharding information on each request, the server side
* infrastructure must be able to identify the information and properly route the requests.
*
* The current implementation uses a SUFFIX appended the GWT RPC URLs (allowing path based routing), so that each call to the server
* propagates the sharding information through the url.
*
* A load balancer can be used to properly route each request to the corresponding server node. The first
* sharding implemented is the sharding by leaderboard name.
*
* The suffix appended to the request URL consists of two parts: a prefix that is used to identify the type of shard
* and a payload that will be used to identify the shard.
*
*
*/
public enum ShardingType {
LEADERBOARDNAME("/leaderboard/");
private String prefix;
private ShardingType(String prefix) {
this.prefix = prefix;
}
public String encodeIfNeeded(String shardingInfo) {
if (shardingInfo.startsWith(prefix)) {
return shardingInfo;
}
return new StringBuilder().append(prefix)
.append(normalize(shardingInfo))
.toString();
}
private String normalize(String replace) {
char[] chars = replace.toCharArray();
StringBuilder answer = new StringBuilder();
for(int i = 0;i<chars.length;i++) {
char c = chars[i];
if (c > 47 && c < 58) { // digits
answer.append(c);
} else if (c > 64 && c < 91) { // uppercase letters
answer.append(c);
} else if (c > 69 && c < 123) { // lowercase letters
answer.append(c);
} else {
answer.append("_");
}
}
return answer.toString();
}
public String getPrefix() {
return prefix;
}
}
@@ -31,6 +31,7 @@ Export-Package: com.sap.sailing.domain.base,
com.sap.sailing.domain.trackimport,
com.sap.sailing.domain.tracking,
com.sap.sailing.domain.tracking.impl,
com.sap.sailing.domain.sharding,
com.sap.sailing.domain.windfinder,
com.sap.sailing.util,
com.sap.sailing.util.impl;x-friends:="com.sap.sailing.server.replication,com.sap.sailing.domain.test"
@@ -12,7 +12,9 @@ import java.util.logging.Logger;
import com.sap.sailing.domain.base.DomainFactory;
import com.sap.sailing.domain.common.NoWindException;
import com.sap.sailing.domain.common.dto.LeaderboardDTO;
import com.sap.sailing.domain.common.sharding.ShardingType;
import com.sap.sailing.domain.leaderboard.Leaderboard;
import com.sap.sailing.domain.sharding.ShardingContext;
import com.sap.sailing.domain.tracking.TrackedRegattaRegistry;
import com.sap.sse.common.TimePoint;
import com.sap.sse.common.impl.MillisecondsTimePoint;
@@ -274,6 +276,7 @@ public class LiveLeaderboardUpdater implements Runnable {
public void run() {
assert running;
try {
ShardingContext.setShardingConstraint(ShardingType.LEADERBOARDNAME, leaderboard.getName());
logger.info("Starting " + LiveLeaderboardUpdater.class.getSimpleName() + " thread for leaderboard "
+ leaderboard.getName());
// interrupt the current thread if not producing a single result within the overall timeout
@@ -326,6 +329,8 @@ public class LiveLeaderboardUpdater implements Runnable {
notifyAll();
}
logger.log(Level.SEVERE, "exception updating live leaderboard "+leaderboard.getName(), e);
} finally {
ShardingContext.clearShardingConstraint(ShardingType.LEADERBOARDNAME);
}
}
@@ -55,6 +55,7 @@ import com.sap.sailing.domain.common.dto.LegEntryDTO;
import com.sap.sailing.domain.common.dto.MetaLeaderboardRaceColumnDTO;
import com.sap.sailing.domain.common.dto.RaceColumnDTO;
import com.sap.sailing.domain.common.dto.RaceDTO;
import com.sap.sailing.domain.common.sharding.ShardingType;
import com.sap.sailing.domain.common.tracking.BravoExtendedFix;
import com.sap.sailing.domain.common.tracking.BravoFix;
import com.sap.sailing.domain.common.tracking.GPSFixMoving;
@@ -68,6 +69,7 @@ import com.sap.sailing.domain.racelog.RaceLogIdentifier;
import com.sap.sailing.domain.ranking.RankingMetric.CompetitorRankingInfo;
import com.sap.sailing.domain.ranking.RankingMetric.RankingInfo;
import com.sap.sailing.domain.regattalike.LeaderboardThatHasRegattaLike;
import com.sap.sailing.domain.sharding.ShardingContext;
import com.sap.sailing.domain.tracking.BravoFixTrack;
import com.sap.sailing.domain.tracking.GPSFixTrack;
import com.sap.sailing.domain.tracking.Maneuver;
@@ -355,6 +357,7 @@ public abstract class AbstractLeaderboardWithCache implements Leaderboard {
final boolean waitForLatestAnalyses, TrackedRegattaRegistry trackedRegattaRegistry, final DomainFactory baseDomainFactory,
final boolean fillTotalPointsUncorrected)
throws NoWindException {
ShardingContext.checkConstraint(ShardingType.LEADERBOARDNAME, getName());
long startOfRequestHandling = System.currentTimeMillis();
final LeaderboardDTOCalculationReuseCache cache = new LeaderboardDTOCalculationReuseCache(timePoint);
final BoatClass boatClass = getBoatClass();
@@ -52,16 +52,17 @@ import com.sap.sse.concurrent.NamedReentrantReadWriteLock;
/**
* Base implementation for various types of leaderboards. The {@link RaceColumnListener} implementation forwards events
* received to all {@link RaceColumnListener} subscribed with this leaderboard. To which objects this leaderboard subscribes
* as {@link RaceColumnListener} is left to the concrete subclasses to implement, but the race columns seem like useful
* candidates.
* received to all {@link RaceColumnListener} subscribed with this leaderboard. To which objects this leaderboard
* subscribes as {@link RaceColumnListener} is left to the concrete subclasses to implement, but the race columns seem
* like useful candidates.
*
* @author Axel Uhl (d043530)
*
*/
public abstract class AbstractSimpleLeaderboardImpl extends AbstractLeaderboardWithCache implements Leaderboard, RaceColumnListener {
public abstract class AbstractSimpleLeaderboardImpl extends AbstractLeaderboardWithCache
implements Leaderboard, RaceColumnListener {
private static final long serialVersionUID = 330156778603279333L;
static final Double DOUBLE_0 = new Double(0);
private final SettableScoreCorrection scoreCorrection;
@@ -75,15 +76,15 @@ public abstract class AbstractSimpleLeaderboardImpl extends AbstractLeaderboardW
private final Map<Competitor, String> displayNames;
/**
* Backs the {@link #getCarriedPoints(Competitor)} API with data. Can be used to prime this leaderboard
* with aggregated results of races not tracked / displayed by this leaderboard in detail. The points
* provided by this map are considered by {@link #getNetPoints(Competitor, TimePoint)}.
* Backs the {@link #getCarriedPoints(Competitor)} API with data. Can be used to prime this leaderboard with
* aggregated results of races not tracked / displayed by this leaderboard in detail. The points provided by this
* map are considered by {@link #getNetPoints(Competitor, TimePoint)}.
*/
private final Map<Competitor, Double> carriedPoints;
/**
* A set that manages the difference between {@link #getCompetitors()} and {@link #getAllCompetitors()}. Access
* is controlled by the {@link #suppressedCompetitorsLock} lock.
* A set that manages the difference between {@link #getCompetitors()} and {@link #getAllCompetitors()}. Access is
* controlled by the {@link #suppressedCompetitorsLock} lock.
*/
private final Set<Competitor> suppressedCompetitors;
private final NamedReentrantReadWriteLock suppressedCompetitorsLock;
@@ -107,8 +108,8 @@ public abstract class AbstractSimpleLeaderboardImpl extends AbstractLeaderboardW
private final Fleet fleet;
private EntryImpl(Callable<Integer> trackedRankProvider, Double totalPoints,
Callable<Double> totalPointsUncorrectedProvider, boolean isTotalPointsCorrected,
Double netPoints, MaxPointsReason maxPointsReason, boolean discarded, Fleet fleet) {
Callable<Double> totalPointsUncorrectedProvider, boolean isTotalPointsCorrected, Double netPoints,
MaxPointsReason maxPointsReason, boolean discarded, Fleet fleet) {
super();
this.trackedRankProvider = trackedRankProvider;
this.totalPoints = totalPoints;
@@ -119,6 +120,7 @@ public abstract class AbstractSimpleLeaderboardImpl extends AbstractLeaderboardW
this.discarded = discarded;
this.fleet = fleet;
}
@Override
public int getTrackedRank() {
try {
@@ -127,30 +129,37 @@ public abstract class AbstractSimpleLeaderboardImpl extends AbstractLeaderboardW
throw new RuntimeException(e);
}
}
@Override
public Double getTotalPoints() {
return totalPoints;
}
@Override
public boolean isTotalPointsCorrected() {
return isTotalPointsCorrected;
}
@Override
public Double getNetPoints() {
return netPoints;
}
@Override
public MaxPointsReason getMaxPointsReason() {
return maxPointsReason;
}
@Override
public boolean isDiscarded() {
return discarded;
}
@Override
public Fleet getFleet() {
return fleet;
}
@Override
public Double getTotalPointsUncorrected() {
try {
@@ -160,7 +169,7 @@ public abstract class AbstractSimpleLeaderboardImpl extends AbstractLeaderboardW
}
}
}
/**
* Computing the competitors can be a bit expensive, particularly if the fleet is large and there may be suppressed
* competitors, and the leaderboard may be a meta-leaderboard that refers to other leaderboards which each have
@@ -171,10 +180,10 @@ public abstract class AbstractSimpleLeaderboardImpl extends AbstractLeaderboardW
*
* As it turns out, one of the most frequent uses of the {@link AbstractSimpleLeaderboardImpl#getCompetitors}
* competitors list is to determine their number which in turn is only required for high-point scoring systems and
* for computing the default score for penalties. Again, the most frequently used low-point family of scoring schemes
* does not require this number. Yet, the scoring scheme requires an argument for polymorphic use by those that
* need it. Instead of computing it for each call, this interface lets us defer the actual calculation until the
* point when it's really needed. Once asked, this object will cache the result. Therefore, a new one should be
* for computing the default score for penalties. Again, the most frequently used low-point family of scoring
* schemes does not require this number. Yet, the scoring scheme requires an argument for polymorphic use by those
* that need it. Instead of computing it for each call, this interface lets us defer the actual calculation until
* the point when it's really needed. Once asked, this object will cache the result. Therefore, a new one should be
* constructed each time the number shall be computed.
*
* @author Axel Uhl (D043530)
@@ -183,7 +192,7 @@ public abstract class AbstractSimpleLeaderboardImpl extends AbstractLeaderboardW
public class NumberOfCompetitorsFetcherImpl implements NumberOfCompetitorsInLeaderboardFetcher {
private int numberOfCompetitors = -1;
private int numberOfCompetitorsWithoutMaxPointReason = -1;
@Override
public int getNumberOfCompetitorsInLeaderboard() {
if (numberOfCompetitors == -1) {
@@ -191,7 +200,7 @@ public abstract class AbstractSimpleLeaderboardImpl extends AbstractLeaderboardW
}
return numberOfCompetitors;
}
@Override
public int getNumberOfCompetitorsWithoutMaxPointReason(RaceColumn column, TimePoint timePoint) {
if (numberOfCompetitorsWithoutMaxPointReason == -1) {
@@ -215,17 +224,17 @@ public abstract class AbstractSimpleLeaderboardImpl extends AbstractLeaderboardW
this.suppressedCompetitors = new HashSet<Competitor>();
this.suppressedCompetitorsLock = new NamedReentrantReadWriteLock("suppressedCompetitorsLock", /* fair */ false);
}
protected RaceColumnListeners getRaceColumnListeners() {
return raceColumnListeners;
}
@Override
public void trackedRaceUnlinked(RaceColumn raceColumn, Fleet fleet, TrackedRace trackedRace) {
getRaceColumnListeners().notifyListenersAboutTrackedRaceUnlinked(raceColumn, fleet, trackedRace);
super.trackedRaceUnlinked(raceColumn, fleet, trackedRace);
}
@Override
public void trackedRaceLinked(RaceColumn raceColumn, Fleet fleet, TrackedRace trackedRace) {
getRaceColumnListeners().notifyListenersAboutTrackedRaceLinked(raceColumn, fleet, trackedRace);
@@ -235,10 +244,11 @@ public abstract class AbstractSimpleLeaderboardImpl extends AbstractLeaderboardW
public void isMedalRaceChanged(RaceColumn raceColumn, boolean newIsMedalRace) {
getRaceColumnListeners().notifyListenersAboutIsMedalRaceChanged(raceColumn, newIsMedalRace);
}
@Override
public void isFleetsCanRunInParallelChanged(RaceColumn raceColumn, boolean newIsFleetsCanRunInParallel) {
getRaceColumnListeners().notifyListenersAboutIsFleetsCanRunInParallelChanged(raceColumn, newIsFleetsCanRunInParallel);
getRaceColumnListeners().notifyListenersAboutIsFleetsCanRunInParallelChanged(raceColumn,
newIsFleetsCanRunInParallel);
}
@Override
@@ -247,13 +257,16 @@ public abstract class AbstractSimpleLeaderboardImpl extends AbstractLeaderboardW
}
@Override
public void isFirstColumnIsNonDiscardableCarryForwardChanged(RaceColumn raceColumn, boolean firstColumnIsNonDiscardableCarryForward) {
getRaceColumnListeners().notifyListenersAboutIsFirstColumnIsNonDiscardableCarryForwardChanged(raceColumn, firstColumnIsNonDiscardableCarryForward);
public void isFirstColumnIsNonDiscardableCarryForwardChanged(RaceColumn raceColumn,
boolean firstColumnIsNonDiscardableCarryForward) {
getRaceColumnListeners().notifyListenersAboutIsFirstColumnIsNonDiscardableCarryForwardChanged(raceColumn,
firstColumnIsNonDiscardableCarryForward);
}
@Override
public void hasSplitFleetContiguousScoringChanged(RaceColumn raceColumn, boolean hasSplitFleetContiguousScoring) {
getRaceColumnListeners().notifyListenersAboutHasSplitFleetContiguousScoringChanged(raceColumn, hasSplitFleetContiguousScoring);
getRaceColumnListeners().notifyListenersAboutHasSplitFleetContiguousScoringChanged(raceColumn,
hasSplitFleetContiguousScoring);
}
@Override
@@ -283,11 +296,13 @@ public abstract class AbstractSimpleLeaderboardImpl extends AbstractLeaderboardW
@Override
public void competitorDisplayNameChanged(Competitor competitor, String oldDisplayName, String displayName) {
getRaceColumnListeners().notifyListenersAboutCompetitorDisplayNameChanged(competitor, oldDisplayName, displayName);
getRaceColumnListeners().notifyListenersAboutCompetitorDisplayNameChanged(competitor, oldDisplayName,
displayName);
}
@Override
public void resultDiscardingRuleChanged(ResultDiscardingRule oldDiscardingRule, ResultDiscardingRule newDiscardingRule) {
public void resultDiscardingRuleChanged(ResultDiscardingRule oldDiscardingRule,
ResultDiscardingRule newDiscardingRule) {
getRaceColumnListeners().notifyListenersAboutResultDiscardingRuleChanged(oldDiscardingRule, newDiscardingRule);
}
@@ -304,7 +319,7 @@ public abstract class AbstractSimpleLeaderboardImpl extends AbstractLeaderboardW
protected SettableScoreCorrection createScoreCorrection() {
return new ScoreCorrectionImpl(this);
}
@Override
public SettableScoreCorrection getScoreCorrection() {
return scoreCorrection;
@@ -372,7 +387,8 @@ public abstract class AbstractSimpleLeaderboardImpl extends AbstractLeaderboardW
String oldDisplayName = displayNames.get(competitor);
displayNames.put(competitor, displayName);
if (!Util.equalsWithNull(oldDisplayName, displayName)) {
getRaceColumnListeners().notifyListenersAboutCompetitorDisplayNameChanged(competitor, oldDisplayName, displayName);
getRaceColumnListeners().notifyListenersAboutCompetitorDisplayNameChanged(competitor, oldDisplayName,
displayName);
}
}
@@ -385,9 +401,9 @@ public abstract class AbstractSimpleLeaderboardImpl extends AbstractLeaderboardW
@Override
public Double getTotalPoints(final Competitor competitor, final RaceColumn raceColumn, final TimePoint timePoint) {
return getScoreCorrection().getCorrectedScore(
()->getTrackedRank(competitor, raceColumn, timePoint), competitor,
raceColumn, this, timePoint, new NumberOfCompetitorsFetcherImpl(), getScoringScheme()).getCorrectedScore();
return getScoreCorrection().getCorrectedScore(() -> getTrackedRank(competitor, raceColumn, timePoint),
competitor, raceColumn, this, timePoint, new NumberOfCompetitorsFetcherImpl(), getScoringScheme())
.getCorrectedScore();
}
@Override
@@ -399,19 +415,19 @@ public abstract class AbstractSimpleLeaderboardImpl extends AbstractLeaderboardW
public boolean isDiscarded(Competitor competitor, RaceColumn raceColumn, TimePoint timePoint) {
return isDiscarded(competitor, raceColumn, getRaceColumns(), timePoint);
}
private boolean isDiscarded(Competitor competitor, RaceColumn raceColumn,
Iterable<RaceColumn> raceColumnsToConsider, TimePoint timePoint) {
final Set<RaceColumn> discardedRaceColumns = getResultDiscardingRule()
.getDiscardedRaceColumns(competitor, this, raceColumnsToConsider, timePoint);
final Set<RaceColumn> discardedRaceColumns = getResultDiscardingRule().getDiscardedRaceColumns(competitor, this,
raceColumnsToConsider, timePoint);
return isDiscarded(competitor, raceColumn, timePoint, discardedRaceColumns);
}
/**
* Same as {@link #isDiscarded(Competitor, RaceColumn, TimePoint)}, only that the set of discarded race columns can
* be specified which is useful when net points are to be computed for more than one column for the same
* competitor because then the calculation of discards (which requires looking at all columns) only needs to be done
* once and not again for each column (which would lead to quadratic effort).
* be specified which is useful when net points are to be computed for more than one column for the same competitor
* because then the calculation of discards (which requires looking at all columns) only needs to be done once and
* not again for each column (which would lead to quadratic effort).
*
* @param discardedRaceColumns
* expected to be the result of what we would get if we called {@link #getResultDiscardingRule()}.
@@ -420,8 +436,7 @@ public abstract class AbstractSimpleLeaderboardImpl extends AbstractLeaderboardW
*/
private boolean isDiscarded(Competitor competitor, RaceColumn raceColumn, TimePoint timePoint,
final Set<RaceColumn> discardedRaceColumns) {
return !raceColumn.isMedalRace()
&& getMaxPointsReason(competitor, raceColumn, timePoint).isDiscardable()
return !raceColumn.isMedalRace() && getMaxPointsReason(competitor, raceColumn, timePoint).isDiscardable()
&& discardedRaceColumns.contains(raceColumn);
}
@@ -431,16 +446,16 @@ public abstract class AbstractSimpleLeaderboardImpl extends AbstractLeaderboardW
}
@Override
public Double getNetPoints(Competitor competitor, RaceColumn raceColumn,
Iterable<RaceColumn> raceColumnsToConsider, TimePoint timePoint) {
final Set<RaceColumn> discardedRaceColumns = getResultDiscardingRule()
.getDiscardedRaceColumns(competitor, this, raceColumnsToConsider, timePoint);
public Double getNetPoints(Competitor competitor, RaceColumn raceColumn, Iterable<RaceColumn> raceColumnsToConsider,
TimePoint timePoint) {
final Set<RaceColumn> discardedRaceColumns = getResultDiscardingRule().getDiscardedRaceColumns(competitor, this,
raceColumnsToConsider, timePoint);
return getNetPoints(competitor, raceColumn, timePoint, discardedRaceColumns);
}
/**
* Same as {@link #getNetPoints(Competitor, RaceColumn, Iterable, TimePoint)}, only that the set of discarded race columns can
* be specified which is useful when net points are to be computed for more than one column for the same
* Same as {@link #getNetPoints(Competitor, RaceColumn, Iterable, TimePoint)}, only that the set of discarded race
* columns can be specified which is useful when net points are to be computed for more than one column for the same
* competitor because then the calculation of discards (which requires looking at all columns) only needs to be done
* once and not again for each column (which would lead to quadratic effort).
*
@@ -450,7 +465,8 @@ public abstract class AbstractSimpleLeaderboardImpl extends AbstractLeaderboardW
* getDiscardedRaceColumns(competitor, this, raceColumnsToConsider, timePoint)}.
*/
@Override
public Double getNetPoints(Competitor competitor, RaceColumn raceColumn, TimePoint timePoint, Set<RaceColumn> discardedRaceColumns) {
public Double getNetPoints(Competitor competitor, RaceColumn raceColumn, TimePoint timePoint,
Set<RaceColumn> discardedRaceColumns) {
Double result;
if (isDiscarded(competitor, raceColumn, timePoint, discardedRaceColumns)) {
result = 0.0;
@@ -473,11 +489,12 @@ public abstract class AbstractSimpleLeaderboardImpl extends AbstractLeaderboardW
@Override
public Double getNetPoints(Competitor competitor, final Iterable<RaceColumn> raceColumnsToConsider,
TimePoint timePoint) {
// when a column with isStartsWithZeroScore() is found, only reset score if the competitor scored in any race from there on
// when a column with isStartsWithZeroScore() is found, only reset score if the competitor scored in any race
// from there on
boolean needToResetScoreUponNextNonEmptyEntry = false;
double result = getCarriedPoints(competitor);
final Set<RaceColumn> discardedRaceColumns = getResultDiscardingRule()
.getDiscardedRaceColumns(competitor, this, raceColumnsToConsider, timePoint);
final Set<RaceColumn> discardedRaceColumns = getResultDiscardingRule().getDiscardedRaceColumns(competitor, this,
raceColumnsToConsider, timePoint);
for (RaceColumn raceColumn : raceColumnsToConsider) {
if (raceColumn.isStartsWithZeroScore()) {
needToResetScoreUponNextNonEmptyEntry = true;
@@ -497,16 +514,19 @@ public abstract class AbstractSimpleLeaderboardImpl extends AbstractLeaderboardW
}
/**
* All competitors with non-<code>null</code> total points are added to the result which is then sorted by total points in ascending
* order. The fleet, if ordered, is the primary ordering criterion, followed by the total points.
* All competitors with non-<code>null</code> total points are added to the result which is then sorted by total
* points in ascending order. The fleet, if ordered, is the primary ordering criterion, followed by the total
* points.
*/
@Override
public List<Competitor> getCompetitorsFromBestToWorst(final RaceColumn raceColumn, TimePoint timePoint) throws NoWindException {
public List<Competitor> getCompetitorsFromBestToWorst(final RaceColumn raceColumn, TimePoint timePoint)
throws NoWindException {
final Map<Competitor, com.sap.sse.common.Util.Pair<Double, Fleet>> totalPointsAndFleet = new HashMap<Competitor, com.sap.sse.common.Util.Pair<Double, Fleet>>();
for (Competitor competitor : getCompetitors()) {
Double totalPoints = getTotalPoints(competitor, raceColumn, timePoint);
if (totalPoints != null) {
totalPointsAndFleet.put(competitor, new com.sap.sse.common.Util.Pair<Double, Fleet>(totalPoints, raceColumn.getFleetOfCompetitor(competitor)));
totalPointsAndFleet.put(competitor, new com.sap.sse.common.Util.Pair<Double, Fleet>(totalPoints,
raceColumn.getFleetOfCompetitor(competitor)));
}
}
List<Competitor> result = new ArrayList<Competitor>(totalPointsAndFleet.keySet());
@@ -518,7 +538,8 @@ public abstract class AbstractSimpleLeaderboardImpl extends AbstractLeaderboardW
comparisonResult = 0;
} else {
if (raceColumn.hasSplitFleets() && !raceColumn.hasSplitFleetContiguousScoring()) {
// only check fleets if there are more than one and the column is not to be contiguously scored even in case
// only check fleets if there are more than one and the column is not to be contiguously scored
// even in case
// of split fleets
final Fleet o1Fleet = totalPointsAndFleet.get(o1).getB();
final Fleet o2Fleet = totalPointsAndFleet.get(o2).getB();
@@ -537,13 +558,14 @@ public abstract class AbstractSimpleLeaderboardImpl extends AbstractLeaderboardW
}
}
} else {
// either there are no split fleets or the split isn't relevant for scoring as for ordered fleets
// either there are no split fleets or the split isn't relevant for scoring as for ordered
// fleets
// the scoring runs contiguously from top to bottom
comparisonResult = 0;
}
if (comparisonResult == 0) {
comparisonResult = getScoringScheme().getScoreComparator(/* nullScoresAreBetter */ false).compare(
totalPointsAndFleet.get(o1).getA(), totalPointsAndFleet.get(o2).getA());
comparisonResult = getScoringScheme().getScoreComparator(/* nullScoresAreBetter */ false)
.compare(totalPointsAndFleet.get(o1).getA(), totalPointsAndFleet.get(o2).getA());
}
}
return comparisonResult;
@@ -559,11 +581,12 @@ public abstract class AbstractSimpleLeaderboardImpl extends AbstractLeaderboardW
public List<Competitor> getCompetitorsFromBestToWorst(TimePoint timePoint) {
return getCompetitorsFromBestToWorst(getRaceColumns(), timePoint);
}
/**
* suppressed competitors are removed from the result
*/
private List<Competitor> getCompetitorsFromBestToWorst(Iterable<RaceColumn> raceColumnsToConsider, TimePoint timePoint) {
private List<Competitor> getCompetitorsFromBestToWorst(Iterable<RaceColumn> raceColumnsToConsider,
TimePoint timePoint) {
List<Competitor> result = new ArrayList<Competitor>();
for (Competitor competitor : getCompetitors()) {
result.add(competitor);
@@ -571,9 +594,11 @@ public abstract class AbstractSimpleLeaderboardImpl extends AbstractLeaderboardW
Collections.sort(result, getTotalRankComparator(raceColumnsToConsider, timePoint));
return result;
}
protected Comparator<? super Competitor> getTotalRankComparator(Iterable<RaceColumn> raceColumnsToConsider, TimePoint timePoint) {
return new LeaderboardTotalRankComparator(this, timePoint, getScoringScheme(), /* nullScoresAreBetter */ false, raceColumnsToConsider);
protected Comparator<? super Competitor> getTotalRankComparator(Iterable<RaceColumn> raceColumnsToConsider,
TimePoint timePoint) {
return new LeaderboardTotalRankComparator(this, timePoint, getScoringScheme(), /* nullScoresAreBetter */ false,
raceColumnsToConsider);
}
@Override
@@ -599,15 +624,16 @@ public abstract class AbstractSimpleLeaderboardImpl extends AbstractLeaderboardW
}
@Override
public boolean countRaceForComparisonWithDiscardingThresholds(Competitor competitor, RaceColumn raceColumn, TimePoint timePoint) {
public boolean countRaceForComparisonWithDiscardingThresholds(Competitor competitor, RaceColumn raceColumn,
TimePoint timePoint) {
TrackedRace trackedRaceForCompetitorInColumn;
return getScoringScheme().isValidInNetScore(this, raceColumn, competitor, timePoint) &&
(getScoreCorrection().isScoreCorrected(competitor, raceColumn, timePoint) ||
((trackedRaceForCompetitorInColumn=raceColumn.getTrackedRace(competitor)) != null &&
trackedRaceForCompetitorInColumn.hasStarted(timePoint) &&
trackedRaceForCompetitorInColumn.getRank(competitor, timePoint) != 0));
return getScoringScheme().isValidInNetScore(this, raceColumn, competitor, timePoint)
&& (getScoreCorrection().isScoreCorrected(competitor, raceColumn, timePoint)
|| ((trackedRaceForCompetitorInColumn = raceColumn.getTrackedRace(competitor)) != null
&& trackedRaceForCompetitorInColumn.hasStarted(timePoint)
&& trackedRaceForCompetitorInColumn.getRank(competitor, timePoint) != 0));
}
@Override
public void addRaceColumnListener(RaceColumnListener listener) {
getRaceColumnListeners().addRaceColumnListener(listener);
@@ -619,27 +645,31 @@ public abstract class AbstractSimpleLeaderboardImpl extends AbstractLeaderboardW
}
@Override
public Entry getEntry(final Competitor competitor, final RaceColumn race, final TimePoint timePoint) throws NoWindException {
final Set<RaceColumn> discardedRaceColumns = getResultDiscardingRule().getDiscardedRaceColumns(competitor, this, getRaceColumns(), timePoint);
public Entry getEntry(final Competitor competitor, final RaceColumn race, final TimePoint timePoint)
throws NoWindException {
final Set<RaceColumn> discardedRaceColumns = getResultDiscardingRule().getDiscardedRaceColumns(competitor, this,
getRaceColumns(), timePoint);
return getEntry(competitor, race, timePoint, discardedRaceColumns);
}
@Override
public Entry getEntry(final Competitor competitor, final RaceColumn race, final TimePoint timePoint,
Set<RaceColumn> discardedRaceColumns) throws NoWindException {
Callable<Integer> trackedRankProvider = ()->getTrackedRank(competitor, race, timePoint);
Callable<Integer> trackedRankProvider = () -> getTrackedRank(competitor, race, timePoint);
final Result correctedResults = getScoreCorrection().getCorrectedScore(trackedRankProvider, competitor, race,
this, timePoint, new NumberOfCompetitorsFetcherImpl(), getScoringScheme());
boolean discarded = isDiscarded(competitor, race, timePoint, discardedRaceColumns);
final Double correctedScore = correctedResults.getCorrectedScore();
return new EntryImpl(trackedRankProvider, correctedScore, ()->correctedResults.getUncorrectedScore(),
correctedResults.isCorrected(), discarded ? DOUBLE_0 : correctedScore == null ? null
: Double.valueOf(correctedScore * race.getFactor()), correctedResults.getMaxPointsReason(), discarded,
race.getFleetOfCompetitor(competitor));
return new EntryImpl(trackedRankProvider, correctedScore, () -> correctedResults.getUncorrectedScore(),
correctedResults.isCorrected(),
discarded ? DOUBLE_0
: correctedScore == null ? null : Double.valueOf(correctedScore * race.getFactor()),
correctedResults.getMaxPointsReason(), discarded, race.getFleetOfCompetitor(competitor));
}
@Override
public Map<RaceColumn, List<Competitor>> getRankedCompetitorsFromBestToWorstAfterEachRaceColumn(TimePoint timePoint) throws NoWindException {
public Map<RaceColumn, List<Competitor>> getRankedCompetitorsFromBestToWorstAfterEachRaceColumn(TimePoint timePoint)
throws NoWindException {
Map<RaceColumn, List<Competitor>> result = new LinkedHashMap<>();
List<RaceColumn> raceColumnsToConsider = new ArrayList<>();
for (RaceColumn raceColumn : getRaceColumns()) {
@@ -663,7 +693,8 @@ public abstract class AbstractSimpleLeaderboardImpl extends AbstractLeaderboardW
public Map<Competitor, Double> call() {
Map<Competitor, Double> netPointsSumPerCompetitorInColumn = new HashMap<>();
for (Competitor competitor : getCompetitors()) {
netPointsSumPerCompetitorInColumn.put(competitor, getNetPoints(competitor, finalRaceColumnsToConsider, timePoint));
netPointsSumPerCompetitorInColumn.put(competitor,
getNetPoints(competitor, finalRaceColumnsToConsider, timePoint));
}
synchronized (result) {
return netPointsSumPerCompetitorInColumn;
@@ -686,27 +717,29 @@ public abstract class AbstractSimpleLeaderboardImpl extends AbstractLeaderboardW
}
@Override
public Map<com.sap.sse.common.Util.Pair<Competitor, RaceColumn>, Entry> getContent(final TimePoint timePoint) throws NoWindException {
public Map<com.sap.sse.common.Util.Pair<Competitor, RaceColumn>, Entry> getContent(final TimePoint timePoint)
throws NoWindException {
Map<com.sap.sse.common.Util.Pair<Competitor, RaceColumn>, Entry> result = new HashMap<com.sap.sse.common.Util.Pair<Competitor, RaceColumn>, Entry>();
Map<Competitor, Set<RaceColumn>> discardedRaces = new HashMap<Competitor, Set<RaceColumn>>();
for (final RaceColumn raceColumn : getRaceColumns()) {
for (final Competitor competitor : getCompetitors()) {
Callable<Integer> trackedRankProvider = ()->getTrackedRank(competitor, raceColumn, timePoint);
final Result correctedResults = getScoreCorrection().getCorrectedScore(trackedRankProvider, competitor, raceColumn,
this, timePoint, new NumberOfCompetitorsFetcherImpl(), getScoringScheme());
Callable<Integer> trackedRankProvider = () -> getTrackedRank(competitor, raceColumn, timePoint);
final Result correctedResults = getScoreCorrection().getCorrectedScore(trackedRankProvider, competitor,
raceColumn, this, timePoint, new NumberOfCompetitorsFetcherImpl(), getScoringScheme());
Set<RaceColumn> discardedRacesForCompetitor = discardedRaces.get(competitor);
if (discardedRacesForCompetitor == null) {
discardedRacesForCompetitor = getResultDiscardingRule().getDiscardedRaceColumns(competitor, this, getRaceColumns(), timePoint);
discardedRacesForCompetitor = getResultDiscardingRule().getDiscardedRaceColumns(competitor, this,
getRaceColumns(), timePoint);
discardedRaces.put(competitor, discardedRacesForCompetitor);
}
boolean discarded = discardedRacesForCompetitor.contains(raceColumn);
final Double correctedScore = correctedResults.getCorrectedScore();
Entry entry = new EntryImpl(trackedRankProvider, correctedScore,
()->correctedResults.getUncorrectedScore(),
correctedResults.isCorrected(),
discarded ? DOUBLE_0 : (correctedScore==null?null:
Double.valueOf((correctedScore * raceColumn.getFactor()))), correctedResults.getMaxPointsReason(),
discarded, raceColumn.getFleetOfCompetitor(competitor));
() -> correctedResults.getUncorrectedScore(), correctedResults.isCorrected(),
discarded ? DOUBLE_0
: (correctedScore == null ? null
: Double.valueOf((correctedScore * raceColumn.getFactor()))),
correctedResults.getMaxPointsReason(), discarded, raceColumn.getFleetOfCompetitor(competitor));
result.put(new com.sap.sse.common.Util.Pair<Competitor, RaceColumn>(competitor, raceColumn), entry);
}
}
@@ -714,7 +747,8 @@ public abstract class AbstractSimpleLeaderboardImpl extends AbstractLeaderboardW
}
/**
* A leaderboard will only accept the addition of a race column if the column's name is unique across the leaderboard.
* A leaderboard will only accept the addition of a race column if the column's name is unique across the
* leaderboard.
*/
@Override
public boolean canAddRaceColumnToContainer(RaceColumn newRaceColumn) {
@@ -731,17 +765,18 @@ public abstract class AbstractSimpleLeaderboardImpl extends AbstractLeaderboardW
/**
* Finds out the time point when any of the {@link Leaderboard#getTrackedRaces() tracked races currently attached to
* the <code>leaderboard</code>} and the {@link Leaderboard#getScoreCorrection() score corrections} have last been
* modified. If no tracked race is attached and no time-stamped score corrections have been applied to the leaderboard,
* <code>null</code> is returned. The time point computed this way is a good choice for normalizing queries for later time
* points in an attempt to achieve more cache hits.<p>
* modified. If no tracked race is attached and no time-stamped score corrections have been applied to the
* leaderboard, <code>null</code> is returned. The time point computed this way is a good choice for normalizing
* queries for later time points in an attempt to achieve more cache hits.
* <p>
*
* Note, however, that the result does not tell about structural changes to the leaderboard and therefore cannot be used
* to determine the need for cache invalidation. For example, if a column is added to a leaderboard after the time point
* returned by this method but that column's attached tracked race has finished before the time point returned by this method,
* the result of this method won't change. Still, the contents of the leaderboard will change by a change in column structure.
* A different means to determine the possibility of changes that happened to this leaderboard must be used for cache
* management. Such a facility has to listen for score correction changes, tracked races being attached or detached and
* the column structure changing.
* Note, however, that the result does not tell about structural changes to the leaderboard and therefore cannot be
* used to determine the need for cache invalidation. For example, if a column is added to a leaderboard after the
* time point returned by this method but that column's attached tracked race has finished before the time point
* returned by this method, the result of this method won't change. Still, the contents of the leaderboard will
* change by a change in column structure. A different means to determine the possibility of changes that happened
* to this leaderboard must be used for cache management. Such a facility has to listen for score correction
* changes, tracked races being attached or detached and the column structure changing.
*
* @see TrackedRace#getTimePointOfNewestEvent()
* @see SettableScoreCorrection#getTimePointOfLastCorrectionsValidity()
@@ -750,19 +785,22 @@ public abstract class AbstractSimpleLeaderboardImpl extends AbstractLeaderboardW
public TimePoint getTimePointOfLatestModification() {
TimePoint result = null;
for (TrackedRace trackedRace : getTrackedRaces()) {
if (result == null || (trackedRace.getTimePointOfNewestEvent() != null && trackedRace.getTimePointOfNewestEvent().after(result))) {
if (result == null || (trackedRace.getTimePointOfNewestEvent() != null
&& trackedRace.getTimePointOfNewestEvent().after(result))) {
result = trackedRace.getTimePointOfNewestEvent();
}
}
TimePoint timePointOfLastScoreCorrection = getScoreCorrection().getTimePointOfLastCorrectionsValidity();
if (timePointOfLastScoreCorrection != null && (result == null || timePointOfLastScoreCorrection.after(result))) {
if (timePointOfLastScoreCorrection != null
&& (result == null || timePointOfLastScoreCorrection.after(result))) {
result = timePointOfLastScoreCorrection;
}
return result;
}
@Override
public com.sap.sse.common.Util.Pair<GPSFixMoving, Speed> getMaximumSpeedOverGround(Competitor competitor, TimePoint timePoint) {
public com.sap.sse.common.Util.Pair<GPSFixMoving, Speed> getMaximumSpeedOverGround(Competitor competitor,
TimePoint timePoint) {
com.sap.sse.common.Util.Pair<GPSFixMoving, Speed> result = null;
// TODO should we ensure that competitor participated in all race columns?
for (TrackedRace trackedRace : getTrackedRaces()) {
@@ -771,16 +809,17 @@ public abstract class AbstractSimpleLeaderboardImpl extends AbstractLeaderboardW
if (!markPassings.isEmpty()) {
TimePoint from = markPassings.first().getTimePoint();
TimePoint to;
if (timePoint.after(markPassings.last().getTimePoint()) &&
markPassings.last().getWaypoint() == trackedRace.getRace().getCourse().getLastWaypoint()) {
if (timePoint.after(markPassings.last().getTimePoint()) && markPassings.last()
.getWaypoint() == trackedRace.getRace().getCourse().getLastWaypoint()) {
// stop counting when competitor finished the race
to = markPassings.last().getTimePoint();
} else {
to = timePoint;
}
com.sap.sse.common.Util.Pair<GPSFixMoving, Speed> maxSpeed = trackedRace.getTrack(competitor).getMaximumSpeedOverGround(from, to);
if (result == null || result.getB() == null ||
(maxSpeed != null && maxSpeed.getB() != null && maxSpeed.getB().compareTo(result.getB()) > 0)) {
com.sap.sse.common.Util.Pair<GPSFixMoving, Speed> maxSpeed = trackedRace.getTrack(competitor)
.getMaximumSpeedOverGround(from, to);
if (result == null || result.getB() == null || (maxSpeed != null && maxSpeed.getB() != null
&& maxSpeed.getB().compareTo(result.getB()) > 0)) {
result = maxSpeed;
}
}
@@ -799,7 +838,7 @@ public abstract class AbstractSimpleLeaderboardImpl extends AbstractLeaderboardW
}
return result;
}
@Override
public Iterable<Competitor> getCompetitors() {
final Iterable<Competitor> result;
@@ -815,10 +854,11 @@ public abstract class AbstractSimpleLeaderboardImpl extends AbstractLeaderboardW
}
return result;
}
@Override
public Iterable<Competitor> getCompetitors(RaceColumn raceColumn, Fleet fleet) {
return getCompetitorIterableSkippingSuppressed(getAllCompetitors(raceColumn, fleet), getSuppressedCompetitors());
return getCompetitorIterableSkippingSuppressed(getAllCompetitors(raceColumn, fleet),
getSuppressedCompetitors());
}
/**
@@ -838,7 +878,7 @@ public abstract class AbstractSimpleLeaderboardImpl extends AbstractLeaderboardW
LockUtil.unlockAfterRead(suppressedCompetitorsLock);
}
}
@Override
public boolean isSuppressed(Competitor competitor) {
LockUtil.lockForRead(suppressedCompetitorsLock);
@@ -848,12 +888,12 @@ public abstract class AbstractSimpleLeaderboardImpl extends AbstractLeaderboardW
LockUtil.unlockAfterRead(suppressedCompetitorsLock);
}
}
@Override
public void setSuppressed(Competitor competitor, boolean suppressed) {
if (competitor == null) {
throw new IllegalArgumentException("Cannot change suppression for a null competitor");
}
if (competitor == null) {
throw new IllegalArgumentException("Cannot change suppression for a null competitor");
}
LockUtil.lockForWrite(suppressedCompetitorsLock);
try {
if (suppressed) {
@@ -874,7 +914,7 @@ public abstract class AbstractSimpleLeaderboardImpl extends AbstractLeaderboardW
TimePoint timePoint = delayToLiveInMillis == null ? now : now.minus(delayToLiveInMillis);
return timePoint;
}
@Override
public void raceLogEventAdded(RaceColumn raceColumn, RaceLogIdentifier raceLogIdentifier, RaceLogEvent event) {
getRaceColumnListeners().notifyListenersAboutRaceLogEventAdded(raceColumn, raceLogIdentifier, event);
@@ -887,14 +927,16 @@ public abstract class AbstractSimpleLeaderboardImpl extends AbstractLeaderboardW
}
public String toString() {
return getName() + " " + (getDefaultCourseArea() != null ? getDefaultCourseArea().getName() : "<No course area defined>") + " " + (getScoringScheme() != null ? getScoringScheme().getType().name() : "<No scoring scheme set>");
return getName() + " "
+ (getDefaultCourseArea() != null ? getDefaultCourseArea().getName() : "<No course area defined>") + " "
+ (getScoringScheme() != null ? getScoringScheme().getType().name() : "<No scoring scheme set>");
}
@Override
public NumberOfCompetitorsInLeaderboardFetcher getNumberOfCompetitorsInLeaderboardFetcher() {
return new NumberOfCompetitorsFetcherImpl();
}
@Override
public Pair<RaceColumn, Fleet> getRaceColumnAndFleet(TrackedRace trackedRace) {
for (final RaceColumn raceColumn : getRaceColumns()) {
@@ -914,8 +956,8 @@ public abstract class AbstractSimpleLeaderboardImpl extends AbstractLeaderboardW
Map<Competitor, Boat> competitorsAndTheirBoats = raceColumn.getAllCompetitorsAndTheirBoats();
allBoats.addAll(competitorsAndTheirBoats.values());
}
return Util.getDominantObject(StreamSupport.stream(allBoats.spliterator(), /* parallel */ false).
map(b->b.getBoatClass()).collect(Collectors.toList()));
return Util.getDominantObject(StreamSupport.stream(allBoats.spliterator(), /* parallel */ false)
.map(b -> b.getBoatClass()).collect(Collectors.toList()));
}
}
@@ -0,0 +1,121 @@
package com.sap.sailing.domain.sharding;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.logging.Level;
import java.util.logging.Logger;
import com.sap.sailing.domain.common.sharding.ShardingType;
import com.sap.sailing.domain.leaderboard.caching.LiveLeaderboardUpdater;
/**
* The sharding context is used to store and verify contraints for a thread.
*
* This is currently used to verify if a given thread, that is explicitly expected to only
* trigger the calculation of a given leaderboard, does trigger the calculation of further/ other
* leaderboards.
*
* It is also used to log warnings if a leaderboard is calculated without predefining the thread constraint.
*
* The enum {@link ShardingType} lists the known sharding types. Each sharding type defines a prefix that will
* be used to identify the sharding type from the request, as implemented in {@link #identifyAndSetShardingConstraint(String)}.
*
* By calling {@link #setShardingConstraint(ShardingType, String)} it is possible to directly set a thread constraint.
* This is useful in background computing code, as in {@link LiveLeaderboardUpdater}
*
*/
public class ShardingContext {
private static final Logger logger = Logger.getLogger(ShardingContext.class.getName());
private static final ConcurrentMap<ShardingType, ThreadLocal<String>> shardingMap = new ConcurrentHashMap<>();
/**
* Sets the sharding context. The type of sharding will be identified by the prefix.
*
* @param shardingInfo
*/
public static ShardingType identifyAndSetShardingConstraint(String shardingInfo) {
if (shardingInfo == null || shardingInfo.isEmpty()) {
logger.warning("Empty sharding constraint");
return null;
}
ThreadLocal<String> identifiedShardingHolder = null;
for (ShardingType shardingType : ShardingType.values()) {
if (shardingInfo.startsWith(shardingType.getPrefix())) {
identifiedShardingHolder = shardingMap.computeIfAbsent(shardingType, t -> new ThreadLocal<>());
checkAndSetShardingInfo(shardingType, shardingInfo, identifiedShardingHolder);
return shardingType;
}
}
if (identifiedShardingHolder == null) {
logger.warning("Could not identify sharding type for: " + shardingInfo);
}
return null;
}
/**
* Provide sharding constraint for given sharding type.
*
* @param shardingType
* @param shardingInfo
*/
public static void setShardingConstraint(ShardingType shardingType, String shardingInfo) {
final String encodedShardingInfo = shardingType.encodeIfNeeded(shardingInfo);
ThreadLocal<String> shardingHolder = shardingMap.computeIfAbsent(shardingType, t -> new ThreadLocal<>());
checkAndSetShardingInfo(shardingType, encodedShardingInfo, shardingHolder);
}
/**
* Check if provided sharding information name equals shard constraint.
*
* If the information is null or empty, we log a warning.
* If shard does not have a constraint, we log a warning. If
* the information provided does not match information previously stored in shard,
* we make a severe log entry.
*
* @param shardingInfo
*/
public static void checkConstraint(final ShardingType type, final String shardingInfo) {
if (shardingInfo == null || shardingInfo.isEmpty()) {
logger.severe("Empty sharding constraint");
return;
}
final ThreadLocal<String> shardingHolder = shardingMap.get(type);
if (shardingHolder == null) {
logger.log(Level.SEVERE, "No current sharding context set for " + type.name(), new RuntimeException());
return;
}
String currentShardingInfo = shardingHolder.get();
if (currentShardingInfo == null || currentShardingInfo.isEmpty()) {
logger.warning("No current sharding constraint for " + type.name());
return;
}
final String encodedShardingInfo = type.encodeIfNeeded(shardingInfo);
if (!encodedShardingInfo.equals(currentShardingInfo)) {
logger.log(Level.SEVERE, "Current sharding constraint vialation for " + type.name() + ". Got "
+ shardingInfo + ", shard requires " + currentShardingInfo, new RuntimeException());
return;
}
}
public static void clearShardingConstraint(ShardingType type) {
ThreadLocal<String> shardingHolder = shardingMap.remove(type);
if (shardingHolder != null) {
shardingHolder.remove();
}
}
private static void checkAndSetShardingInfo(ShardingType shardingType, String encodedShardingInfo,
ThreadLocal<String> shardingHolder) {
if (encodedShardingInfo == null || encodedShardingInfo.isEmpty()) {
logger.log(Level.SEVERE, "Cannot set empty sharding information for " + shardingType.name(),
new RuntimeException());
}
String currentShardingInfo = shardingHolder.get();
if (currentShardingInfo == null) {
shardingHolder.set(encodedShardingInfo);
} else if (!encodedShardingInfo.equals(currentShardingInfo)) {
logger.log(Level.SEVERE, "Switching shard constraint for " + shardingType.name()+". Got <<" + encodedShardingInfo +">>, expeted <<"+ currentShardingInfo+">>", new RuntimeException());
}
}
}
@@ -77,6 +77,7 @@ TrackLifecycle: true
Export-Package: com.google.gwt.user.client.rpc.core.com.sap.sailing.domain.common.confidence.impl,
com.google.gwt.user.client.rpc.core.com.sap.sailing.domain.common.impl,
com.google.gwt.user.client.rpc.core.com.sap.sailing.domain.common.tracking.impl,
com.sap.sailing.gwt.common.communication.routing,
com.sap.sailing.gwt.home.communication,
com.sap.sailing.gwt.home.server,
com.sap.sailing.gwt.server,
@@ -70,6 +70,7 @@
<servlet-mapping>
<servlet-name>SailingService</servlet-name>
<url-pattern>/service/sailing</url-pattern>
<url-pattern>/service/sailing/*</url-pattern>
</servlet-mapping>
<servlet>
@@ -90,6 +91,7 @@
<servlet-mapping>
<servlet-name>sailingDispatch</servlet-name>
<url-pattern>/service/dispatch</url-pattern>
<url-pattern>/service/dispatch/*</url-pattern>
</servlet-mapping>
<servlet>
@@ -1,16 +1,20 @@
package com.sap.sailing.gwt.autoplay.client.app;
import java.util.HashMap;
import java.util.Map;
import com.google.gwt.core.client.GWT;
import com.google.gwt.place.shared.Place;
import com.google.gwt.place.shared.PlaceController;
import com.google.gwt.user.client.rpc.ServiceDefTarget;
import com.google.web.bindery.event.shared.EventBus;
import com.sap.sailing.gwt.autoplay.client.places.autoplaystart.AutoPlayStartPlace;
import com.sap.sailing.gwt.common.communication.routing.ProvidesLeaderboardRouting;
import com.sap.sailing.gwt.ui.client.MediaService;
import com.sap.sailing.gwt.ui.client.MediaServiceAsync;
import com.sap.sailing.gwt.ui.client.RemoteServiceMappingConstants;
import com.sap.sailing.gwt.ui.client.SailingService;
import com.sap.sailing.gwt.ui.client.SailingServiceAsync;
import com.sap.sailing.gwt.ui.client.SailingServiceHelper;
import com.sap.sse.gwt.client.EntryPointHelper;
import com.sap.sse.security.ui.client.SecureClientFactoryImpl;
@@ -20,11 +24,13 @@ public abstract class AutoPlayClientFactoryBase
private final MediaServiceAsync mediaService;
private final AutoPlayPlaceNavigator navigator;
private final Map<String, SailingServiceAsync> services = new HashMap<>();
public AutoPlayClientFactoryBase(ApplicationTopLevelView root, EventBus eventBus, PlaceController placeController,
AutoPlayPlaceNavigator navigator) {
super(root, eventBus, placeController);
this.navigator = navigator;
sailingService = GWT.create(SailingService.class);
sailingService = SailingServiceHelper.createSailingServiceInstance();
mediaService = GWT.create(MediaService.class);
EntryPointHelper.registerASyncService((ServiceDefTarget) sailingService,
RemoteServiceMappingConstants.sailingServiceRemotePath);
@@ -39,8 +45,25 @@ public abstract class AutoPlayClientFactoryBase
@Override
public SailingServiceAsync getSailingService() {
if (isConfigured()) {
return getSailingService(() -> getAutoPlayCtxSignalError().getContextDefinition().getLeaderboardName());
}
return sailingService;
}
@Override
public SailingServiceAsync getSailingService(ProvidesLeaderboardRouting routingProvider) {
if (routingProvider == null) {
return sailingService;
} else {
SailingServiceAsync sailingServiceAsync = services.get(routingProvider.routingSuffixPath());
if (sailingServiceAsync == null) {
sailingServiceAsync = SailingServiceHelper.createSailingServiceInstance(routingProvider);
services.put(routingProvider.routingSuffixPath(), sailingServiceAsync);
}
return sailingServiceAsync;
}
}
@Override
public MediaServiceAsync getMediaService() {
@@ -93,11 +93,11 @@ public class IdleSixtyInchLeaderboardNode extends FiresPlaceNode {
private void startWithLeaderbaord(final MultiRaceLeaderboardSettings leaderboardSettings,
CompetitorSelectionProvider provider, String leaderboardName) {
MultiRaceLeaderboardPanel leaderboardPanel = new MultiRaceLeaderboardPanel(null, null, cf.getSailingService(),
new AsyncActionsExecutor(), leaderboardSettings, false, provider, timer, null, leaderboardName,
cf.getErrorReporter(), StringMessages.INSTANCE, false, null, false, null, false, true, false, false,
false, new SixtyInchLeaderboardStyle(true), FlagImageResolverImpl.get(),
Arrays.asList(DetailType.values()));
MultiRaceLeaderboardPanel leaderboardPanel = new MultiRaceLeaderboardPanel(null, null,
cf.getSailingService(() -> leaderboardName), new AsyncActionsExecutor(), leaderboardSettings, false,
provider, timer, null, leaderboardName, cf.getErrorReporter(), StringMessages.INSTANCE, false, null,
false, null, false, true, false, false, false, new SixtyInchLeaderboardStyle(true),
FlagImageResolverImpl.get(), Arrays.asList(DetailType.values()));
IdleSixtyInchLeaderboardPlace place = new IdleSixtyInchLeaderboardPlace(leaderboardPanel, provider,
durationConsumer);
@@ -6,6 +6,8 @@
<inherits name="com.sap.sse.gwt.CommonSharedResources" />
<source path='client'/>
<source path='communication'/>
<source path='theme'/>
</module>
@@ -0,0 +1,16 @@
package com.sap.sailing.gwt.common.communication.routing;
import com.sap.sailing.domain.common.sharding.ShardingType;
import com.sap.sse.gwt.client.ServiceRoutingProvider;
/**
* Interface used to provide leaderboard specific routing, see {@link ServiceRoutingProvider}
*/
public interface ProvidesLeaderboardRouting extends ServiceRoutingProvider {
String getLeaderboardName();
default String routingSuffixPath() {
return ShardingType.LEADERBOARDNAME.encodeIfNeeded(getLeaderboardName());
}
}
@@ -3,6 +3,7 @@ package com.sap.sailing.gwt.home.communication.event;
import java.util.UUID;
import com.google.gwt.core.shared.GwtIncompatible;
import com.sap.sailing.gwt.common.communication.routing.ProvidesLeaderboardRouting;
import com.sap.sailing.gwt.home.communication.SailingAction;
import com.sap.sailing.gwt.home.communication.SailingDispatchContext;
import com.sap.sailing.gwt.home.server.EventActionUtil;
@@ -26,7 +27,7 @@ import com.sap.sse.gwt.dispatch.shared.exceptions.DispatchException;
* </p>
*/
public class GetCompetitionFormatRacesAction implements
SailingAction<ResultWithTTL<ListResult<RaceCompetitionFormatSeriesDTO>>>, IsClientCacheable {
SailingAction<ResultWithTTL<ListResult<RaceCompetitionFormatSeriesDTO>>>, IsClientCacheable, ProvidesLeaderboardRouting {
private UUID eventId;
private String regattaId;
@@ -58,4 +59,9 @@ public class GetCompetitionFormatRacesAction implements
public void cacheInstanceKey(StringBuilder key) {
key.append(eventId).append("_").append(regattaId);
}
@Override
public String getLeaderboardName() {
return regattaId;
}
}
@@ -3,6 +3,7 @@ package com.sap.sailing.gwt.home.communication.event;
import java.util.UUID;
import com.google.gwt.core.shared.GwtIncompatible;
import com.sap.sailing.gwt.common.communication.routing.ProvidesLeaderboardRouting;
import com.sap.sailing.gwt.home.communication.SailingAction;
import com.sap.sailing.gwt.home.communication.SailingDispatchContext;
import com.sap.sailing.gwt.home.server.EventActionUtil;
@@ -25,7 +26,7 @@ import com.sap.sse.gwt.dispatch.shared.commands.ResultWithTTL;
* </p>
*/
public class GetFinishedRacesAction implements SailingAction<ResultWithTTL<ListResult<RaceListRaceDTO>>>,
IsClientCacheable {
IsClientCacheable, ProvidesLeaderboardRouting {
private UUID eventId;
private String regattaId;
@@ -59,4 +60,9 @@ public class GetFinishedRacesAction implements SailingAction<ResultWithTTL<ListR
public void cacheInstanceKey(StringBuilder key) {
key.append(eventId).append("_").append(regattaId);
}
@Override
public String getLeaderboardName() {
return regattaId;
}
}
@@ -4,6 +4,7 @@ import java.util.UUID;
import com.google.gwt.core.shared.GwtIncompatible;
import com.sap.sailing.domain.base.Event;
import com.sap.sailing.gwt.common.communication.routing.ProvidesLeaderboardRouting;
import com.sap.sailing.gwt.home.communication.SailingAction;
import com.sap.sailing.gwt.home.communication.SailingDispatchContext;
import com.sap.sailing.gwt.home.server.EventActionUtil;
@@ -30,7 +31,7 @@ import com.sap.sse.gwt.dispatch.shared.commands.SortedSetResult;
* </p>
*/
public class GetLiveRacesForRegattaAction implements SailingAction<ResultWithTTL<SortedSetResult<LiveRaceDTO>>>,
IsClientCacheable {
IsClientCacheable, ProvidesLeaderboardRouting {
private UUID eventId;
private String regattaName;
@@ -66,4 +67,10 @@ public class GetLiveRacesForRegattaAction implements SailingAction<ResultWithTTL
public void cacheInstanceKey(StringBuilder key) {
key.append(eventId).append("_").append(regattaName);
}
@Override
public String getLeaderboardName() {
return regattaName;
}
}
@@ -3,6 +3,7 @@ package com.sap.sailing.gwt.home.communication.event;
import java.util.UUID;
import com.google.gwt.core.shared.GwtIncompatible;
import com.sap.sailing.gwt.common.communication.routing.ProvidesLeaderboardRouting;
import com.sap.sailing.gwt.home.communication.SailingAction;
import com.sap.sailing.gwt.home.communication.SailingDispatchContext;
import com.sap.sailing.gwt.home.communication.event.statistics.EventStatisticsDTO;
@@ -22,7 +23,7 @@ import com.sap.sse.gwt.dispatch.shared.exceptions.DispatchException;
* The {@link ResultWithTTL result's} time to live is <i>5 minutes</i>.
* </p>
*/
public class GetRegattaStatisticsAction implements SailingAction<ResultWithTTL<EventStatisticsDTO>>, IsClientCacheable {
public class GetRegattaStatisticsAction implements SailingAction<ResultWithTTL<EventStatisticsDTO>>, IsClientCacheable, ProvidesLeaderboardRouting {
private UUID eventId;
private String regattaId;
@@ -53,4 +54,9 @@ public class GetRegattaStatisticsAction implements SailingAction<ResultWithTTL<E
public void cacheInstanceKey(StringBuilder key) {
key.append(eventId).append("_").append(regattaId);
}
@Override
public String getLeaderboardName() {
return regattaId;
}
}
@@ -3,6 +3,7 @@ package com.sap.sailing.gwt.home.communication.event;
import java.util.UUID;
import com.google.gwt.core.shared.GwtIncompatible;
import com.sap.sailing.gwt.common.communication.routing.ProvidesLeaderboardRouting;
import com.sap.sailing.gwt.home.communication.SailingAction;
import com.sap.sailing.gwt.home.communication.SailingDispatchContext;
import com.sap.sailing.gwt.home.communication.regatta.RegattaWithProgressDTO;
@@ -24,7 +25,7 @@ import com.sap.sse.gwt.dispatch.shared.commands.ResultWithTTL;
* state} using a duration of <i>5 minutes</i> for currently running events.
* </p>
*/
public class GetRegattaWithProgressAction implements SailingAction<ResultWithTTL<RegattaWithProgressDTO>>, IsClientCacheable {
public class GetRegattaWithProgressAction implements SailingAction<ResultWithTTL<RegattaWithProgressDTO>>, IsClientCacheable, ProvidesLeaderboardRouting {
private UUID eventId;
private String regattaId;
@@ -55,4 +56,9 @@ public class GetRegattaWithProgressAction implements SailingAction<ResultWithTTL
public void cacheInstanceKey(StringBuilder key) {
key.append(eventId).append("_").append(regattaId);
}
@Override
public String getLeaderboardName() {
return regattaId;
}
}
@@ -4,6 +4,7 @@ import java.util.UUID;
import com.google.gwt.core.shared.GwtIncompatible;
import com.sap.sailing.domain.base.Event;
import com.sap.sailing.gwt.common.communication.routing.ProvidesLeaderboardRouting;
import com.sap.sailing.gwt.home.communication.SailingAction;
import com.sap.sailing.gwt.home.communication.SailingDispatchContext;
import com.sap.sailing.gwt.home.server.EventActionUtil;
@@ -21,7 +22,7 @@ import com.sap.sse.gwt.dispatch.shared.commands.ResultWithTTL;
* otherwise.
* </p>
*/
public class GetMiniLeaderbordAction implements SailingAction<ResultWithTTL<GetMiniLeaderboardDTO>>, IsClientCacheable {
public class GetMiniLeaderbordAction implements SailingAction<ResultWithTTL<GetMiniLeaderboardDTO>>, IsClientCacheable, ProvidesLeaderboardRouting {
private UUID eventId;
private String leaderboardName;
private int limit = 0;
@@ -74,4 +75,9 @@ public class GetMiniLeaderbordAction implements SailingAction<ResultWithTTL<GetM
key.append("_");
key.append(limit);
}
@Override
public String getLeaderboardName() {
return leaderboardName;
}
}
@@ -13,6 +13,7 @@ import com.sap.sailing.domain.common.RegattaNameAndRaceName;
import com.sap.sailing.domain.common.TargetTimeInfo;
import com.sap.sailing.domain.polars.NotEnoughDataHasBeenAddedException;
import com.sap.sailing.domain.tracking.DynamicTrackedRace;
import com.sap.sailing.gwt.common.communication.routing.ProvidesLeaderboardRouting;
import com.sap.sailing.gwt.home.communication.SailingAction;
import com.sap.sailing.gwt.home.communication.SailingDispatchContext;
import com.sap.sse.common.Distance;
@@ -32,7 +33,7 @@ import com.sap.sse.gwt.dispatch.shared.commands.ResultWithTTL;
* otherwise.
* </p>
*/
public class GetSixtyInchStatisticAction implements SailingAction<GetSixtyInchStatisticDTO> {
public class GetSixtyInchStatisticAction implements SailingAction<GetSixtyInchStatisticDTO>, ProvidesLeaderboardRouting {
private static final Logger LOGGER = Logger.getLogger(GetSixtyInchStatisticAction.class.getName());
// transfer as string, to avoid transfering incompatible types
private String racename;
@@ -95,4 +96,9 @@ public class GetSixtyInchStatisticAction implements SailingAction<GetSixtyInchSt
}
return duration;
}
@Override
public String getLeaderboardName() {
return regattaname;
}
}
@@ -5,12 +5,13 @@ import com.google.gwt.place.shared.Place;
import com.google.gwt.place.shared.PlaceController;
import com.google.gwt.user.client.rpc.ServiceDefTarget;
import com.google.web.bindery.event.shared.EventBus;
import com.sap.sailing.gwt.common.communication.routing.ProvidesLeaderboardRouting;
import com.sap.sailing.gwt.home.shared.places.start.StartPlace;
import com.sap.sailing.gwt.ui.client.MediaService;
import com.sap.sailing.gwt.ui.client.MediaServiceAsync;
import com.sap.sailing.gwt.ui.client.RemoteServiceMappingConstants;
import com.sap.sailing.gwt.ui.client.SailingService;
import com.sap.sailing.gwt.ui.client.SailingServiceAsync;
import com.sap.sailing.gwt.ui.client.SailingServiceHelper;
import com.sap.sse.gwt.client.EntryPointHelper;
import com.sap.sse.security.ui.client.SecureClientFactoryImpl;
@@ -24,9 +25,8 @@ public abstract class AbstractApplicationClientFactory<ATLV extends ApplicationT
PlaceController placeController, final DesktopPlacesNavigator navigator) {
super(root, eventBus, placeController);
this.navigator = navigator;
sailingService = GWT.create(SailingService.class);
sailingService = SailingServiceHelper.createSailingServiceInstance();
mediaService = GWT.create(MediaService.class);
EntryPointHelper.registerASyncService((ServiceDefTarget) sailingService, RemoteServiceMappingConstants.sailingServiceRemotePath);
EntryPointHelper.registerASyncService((ServiceDefTarget) mediaService, RemoteServiceMappingConstants.mediaServiceRemotePath);
}
@@ -40,6 +40,15 @@ public abstract class AbstractApplicationClientFactory<ATLV extends ApplicationT
return sailingService;
}
@Override
public SailingServiceAsync getSailingService(ProvidesLeaderboardRouting routingProvider) {
if (routingProvider == null) {
return sailingService;
} else {
return SailingServiceHelper.createSailingServiceInstance(routingProvider);
}
}
@Override
public MediaServiceAsync getMediaService() {
return mediaService;
@@ -37,7 +37,6 @@ import com.sap.sailing.gwt.settings.client.raceboard.RaceBoardPerspectiveOwnSett
import com.sap.sailing.gwt.settings.client.raceboard.RaceboardContextDefinition;
import com.sap.sailing.gwt.settings.client.regattaoverview.RegattaOverviewContextDefinition;
import com.sap.sailing.gwt.settings.client.regattaoverview.RegattaRaceStatesSettings;
import com.sap.sailing.gwt.ui.client.SailingServiceAsync;
import com.sap.sailing.gwt.ui.client.refresh.ErrorAndBusyClientFactory;
import com.sap.sailing.gwt.ui.client.shared.racemap.RaceMapLifecycle;
import com.sap.sailing.gwt.ui.client.shared.racemap.RaceMapSettings;
@@ -83,10 +82,6 @@ public abstract class AbstractEventActivity<PLACE extends AbstractEventPlace> ex
this.timerForClientServerOffset = new Timer(PlayModes.Replay);
this.clientFactory = clientFactory;
}
public SailingServiceAsync getSailingService() {
return clientFactory.getSailingService();
}
public SailingDispatchSystem getDispatch() {
return clientFactory.getDispatch();
@@ -21,7 +21,6 @@ import com.sap.sailing.gwt.home.shared.places.event.EventDefaultPlace;
import com.sap.sailing.gwt.home.shared.places.events.EventsPlace;
import com.sap.sailing.gwt.home.shared.places.fakeseries.SeriesDefaultPlace;
import com.sap.sailing.gwt.home.shared.places.start.StartPlace;
import com.sap.sailing.gwt.ui.client.SailingServiceAsync;
import com.sap.sailing.gwt.ui.client.refresh.ErrorAndBusyClientFactory;
import com.sap.sse.gwt.client.player.Timer;
@@ -37,7 +36,6 @@ public interface EventView<PLACE extends AbstractEventPlace, PRES extends EventV
boolean needsSelectionInHeader();
void forPlaceSelection(PlaceCallback callback);
Timer getTimerForClientServerOffset();
SailingServiceAsync getSailingService();
AbstractEventRegattaPlace getPlaceForRegatta(String regattaId);
AbstractEventRegattaPlace getPlaceForRegattaRaces(String regattaId);
@@ -4,7 +4,10 @@ import java.util.ArrayList;
import java.util.List;
import com.google.gwt.event.shared.EventBus;
import com.google.gwt.user.client.rpc.AsyncCallback;
import com.google.gwt.user.client.ui.AcceptsOneWidget;
import com.sap.sailing.domain.common.DetailType;
import com.sap.sailing.domain.common.RegattaAndRaceIdentifier;
import com.sap.sailing.domain.common.dto.EventType;
import com.sap.sailing.gwt.home.communication.event.EventReferenceWithStateDTO;
import com.sap.sailing.gwt.home.communication.event.EventState;
@@ -50,7 +53,7 @@ public class EventRegattaActivity extends AbstractEventActivity<AbstractEventReg
currentView = new TabletAndDesktopRegattaEventView(flagImageResolver);
if (this.ctx.getRegattaAnalyticsManager() == null) {
ctx.withRegattaAnalyticsManager(new RegattaAnalyticsDataManager(
clientFactory.getSailingService(),
clientFactory,
asyncActionsExecutor,
new Timer(PlayModes.Live, PlayStates.Paused, delayBetweenAutoAdvancesInMilliseconds),
clientFactory.getErrorReporter(), flagImageResolver));
@@ -158,4 +161,10 @@ public class EventRegattaActivity extends AbstractEventActivity<AbstractEventReg
public UserService getUserService() {
return clientFactory.getUserService();
}
@Override
public void getAvailableDetailTypesForLeaderboard(String leaderboardName, RegattaAndRaceIdentifier raceOrNull,
AsyncCallback<Iterable<DetailType>> asyncCallback) {
clientFactory.getSailingService(()-> leaderboardName).getAvailableDetailTypesForLeaderboard(leaderboardName, raceOrNull, asyncCallback);
}
}
@@ -1,5 +1,8 @@
package com.sap.sailing.gwt.home.desktop.places.event.regatta;
import com.google.gwt.user.client.rpc.AsyncCallback;
import com.sap.sailing.domain.common.DetailType;
import com.sap.sailing.domain.common.RegattaAndRaceIdentifier;
import com.sap.sailing.gwt.home.desktop.places.event.EventView;
import com.sap.sailing.gwt.home.desktop.places.event.regatta.overviewtab.RegattaOverviewPlace;
import com.sap.sailing.gwt.home.shared.app.PlaceNavigation;
@@ -15,5 +18,8 @@ public interface EventRegattaView extends EventView<AbstractEventRegattaPlace, E
Timer getAutoRefreshTimer();
UserService getUserService();
void getAvailableDetailTypesForLeaderboard(String leaderboardName, RegattaAndRaceIdentifier raceOrNull,
AsyncCallback<Iterable<DetailType>> asyncCallback);
}
}
@@ -6,6 +6,7 @@ import com.sap.sailing.gwt.settings.client.leaderboard.MultiRaceLeaderboardSetti
import com.sap.sailing.gwt.ui.client.CompetitorSelectionModel;
import com.sap.sailing.gwt.ui.client.DebugIdHelper;
import com.sap.sailing.gwt.ui.client.FlagImageResolver;
import com.sap.sailing.gwt.ui.client.SailingClientFactory;
import com.sap.sailing.gwt.ui.client.SailingServiceAsync;
import com.sap.sailing.gwt.ui.client.StringMessages;
import com.sap.sailing.gwt.ui.client.shared.charts.MultiCompetitorLeaderboardChart;
@@ -31,16 +32,16 @@ public class RegattaAnalyticsDataManager {
private final CompetitorSelectionModel competitorSelectionProvider;
private final AsyncActionsExecutor asyncActionsExecutor;
private final ErrorReporter errorReporter;
private final SailingServiceAsync sailingService;
private final SailingClientFactory sailingCF;
private final Timer timer;
private final FlagImageResolver flagImageResolver;
public RegattaAnalyticsDataManager(final SailingServiceAsync sailingService,
public RegattaAnalyticsDataManager(final SailingClientFactory sailingCF,
AsyncActionsExecutor asyncActionsExecutor, Timer timer, ErrorReporter errorReporter,
FlagImageResolver flagImageResolver) {
this.flagImageResolver = flagImageResolver;
this.competitorSelectionProvider = new CompetitorSelectionModel(/* hasMultiSelection */true);
this.sailingService = sailingService;
this.sailingCF = sailingCF;
this.asyncActionsExecutor = asyncActionsExecutor;
this.timer = timer;
this.errorReporter = errorReporter;
@@ -53,6 +54,7 @@ public class RegattaAnalyticsDataManager {
final String leaderboardGroupName, String leaderboardName, boolean showRaceDetails,
boolean autoExpandLastRaceColumn, Iterable<DetailType> availableDetailTypes) {
if (leaderboardPanel == null) {
SailingServiceAsync sailingService = sailingCF.getSailingService(()-> leaderboardName);
leaderboardPanel = new MultiRaceLeaderboardPanel(parent, context, sailingService,
asyncActionsExecutor,
leaderboardSettings,
@@ -68,6 +70,7 @@ public class RegattaAnalyticsDataManager {
public MultiCompetitorLeaderboardChart createMultiCompetitorChart(String leaderboardName, DetailType chartDetailType) {
if(multiCompetitorChart == null) {
SailingServiceAsync sailingService = sailingCF.getSailingService(()-> leaderboardName);
multiCompetitorChart = new MultiCompetitorLeaderboardChart(null, null, sailingService, asyncActionsExecutor,
leaderboardName, chartDetailType,
competitorSelectionProvider, timer, StringMessages.INSTANCE, false, errorReporter);
@@ -99,7 +99,7 @@ public class RegattaCompetitorAnalyticsTabView extends SharedLeaderboardRegattaT
}
};
if (regattaAnalyticsManager.getLeaderboardPanel() == null) {
currentPresenter.getSailingService().getAvailableDetailTypesForLeaderboard(leaderboardName,
currentPresenter.getAvailableDetailTypesForLeaderboard(leaderboardName,
null, new AsyncCallback<Iterable<DetailType>>() {
@Override
@@ -147,7 +147,7 @@ public class RegattaLeaderboardTabView extends SharedLeaderboardRegattaTabView<R
private void loadAvailableDetailTypes(final String leaderboardName, final AcceptsOneWidget contentArea,
final Consumer<Iterable<DetailType>> callback) {
currentPresenter.getSailingService().getAvailableDetailTypesForLeaderboard(leaderboardName,
currentPresenter.getAvailableDetailTypesForLeaderboard(leaderboardName,
null, new AsyncCallback<Iterable<DetailType>>() {
@Override
@@ -4,7 +4,9 @@ import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import com.google.gwt.user.client.rpc.AsyncCallback;
import com.sap.sailing.domain.common.DetailType;
import com.sap.sailing.domain.common.RegattaAndRaceIdentifier;
import com.sap.sailing.domain.common.dto.CompetitorDTO;
import com.sap.sailing.gwt.settings.client.leaderboard.MultiCompetitorLeaderboardChartSettings;
import com.sap.sailing.gwt.settings.client.leaderboard.MultiRaceLeaderboardSettings;
@@ -12,6 +14,7 @@ import com.sap.sailing.gwt.ui.client.CompetitorSelectionChangeListener;
import com.sap.sailing.gwt.ui.client.CompetitorSelectionModel;
import com.sap.sailing.gwt.ui.client.DebugIdHelper;
import com.sap.sailing.gwt.ui.client.FlagImageResolver;
import com.sap.sailing.gwt.ui.client.SailingClientFactory;
import com.sap.sailing.gwt.ui.client.SailingServiceAsync;
import com.sap.sailing.gwt.ui.client.StringMessages;
import com.sap.sailing.gwt.ui.client.shared.charts.MultiCompetitorLeaderboardChart;
@@ -42,33 +45,32 @@ public class EventSeriesAnalyticsDataManager {
private final CompetitorSelectionModel competitorSelectionProvider;
private final AsyncActionsExecutor asyncActionsExecutor;
private final ErrorReporter errorReporter;
private final SailingServiceAsync sailingService;
private final SailingClientFactory sailingCF;
private final Timer timer;
private final int MAX_COMPETITORS_IN_CHART = 30;
private final FlagImageResolver flagImageResolver;
public EventSeriesAnalyticsDataManager(final SailingServiceAsync sailingService,
public EventSeriesAnalyticsDataManager(final SailingClientFactory sailingCF,
AsyncActionsExecutor asyncActionsExecutor, Timer timer, ErrorReporter errorReporter,
FlagImageResolver flagImageResolver) {
this.flagImageResolver = flagImageResolver;
this.competitorSelectionProvider = new CompetitorSelectionModel(/* hasMultiSelection */true);
this.sailingService = sailingService;
this.sailingCF = sailingCF;
this.asyncActionsExecutor = asyncActionsExecutor;
this.timer = timer;
this.errorReporter = errorReporter;
this.overallLeaderboardPanel = null;
this.multiCompetitorChart = null;
}
public SailingServiceAsync getSailingService() {
return sailingService;
}
public MultiRaceLeaderboardPanel createMultiRaceOverallLeaderboardPanel(Component<?> parent, ComponentContext<?> context,
final MultiRaceLeaderboardSettings leaderboardSettings,
final String leaderboardGroupName, String leaderboardName, boolean showRaceDetails,
boolean autoExpandLastRaceColumn, Iterable<DetailType> availableDetailTypes) {
if(overallLeaderboardPanel == null) {
SailingServiceAsync sailingService = sailingCF.getSailingService(()-> leaderboardName);
overallLeaderboardPanel = new MultiRaceLeaderboardPanel(parent, context, sailingService, asyncActionsExecutor,
leaderboardSettings, true,
competitorSelectionProvider, timer, leaderboardGroupName, leaderboardName, errorReporter,
@@ -84,7 +86,10 @@ public class EventSeriesAnalyticsDataManager {
public MultiCompetitorLeaderboardChart createMultiCompetitorChart(Component<?> parent,
ComponentContext<?> context, String leaderboardName,
DetailType chartDetailType) {
if(multiCompetitorChart == null) {
SailingServiceAsync sailingService = sailingCF.getSailingService(()-> leaderboardName);
multiCompetitorChart = new MultiCompetitorLeaderboardChart(parent, context, sailingService,
asyncActionsExecutor,
leaderboardName, chartDetailType,
@@ -99,6 +104,7 @@ public class EventSeriesAnalyticsDataManager {
String preselectedLeaderboardName, String leaderboardGroupName,
String metaLeaderboardName, boolean showRaceDetails, boolean autoExpandLastRaceColumn, Iterable<DetailType> availableDetailTypes) {
if(multiLeaderboardPanel == null) {
SailingServiceAsync sailingService = sailingCF.getSailingService(()-> metaLeaderboardName);
multiLeaderboardPanel = new MultiLeaderboardProxyPanel(parent, context, sailingService, metaLeaderboardName,
asyncActionsExecutor, timer, true /* isEmbedded */,
preselectedLeaderboardName, errorReporter, StringMessages.INSTANCE,
@@ -179,4 +185,10 @@ public class EventSeriesAnalyticsDataManager {
public Timer getTimer() {
return timer;
}
public void getAvailableDetailTypesForLeaderboard(String leaderboardName, RegattaAndRaceIdentifier raceOrNull,
AsyncCallback<Iterable<DetailType>> asyncCallback) {
SailingServiceAsync sailingService = sailingCF.getSailingService(()-> leaderboardName);
sailingService.getAvailableDetailTypesForLeaderboard(leaderboardName, raceOrNull, asyncCallback);
}
}
@@ -59,7 +59,7 @@ public class SeriesActivity extends AbstractActivity implements SeriesView.Prese
if (this.ctx.getAnalyticsManager() == null) {
ctx.withAnalyticsManager(new EventSeriesAnalyticsDataManager( //
clientFactory.getSailingService(), //
clientFactory, //
asyncActionsExecutor, //
new Timer(PlayModes.Live, PlayStates.Paused, delayBetweenAutoAdvancesInMilliseconds), //
clientFactory.getErrorReporter(), flagImageResolver));
@@ -78,7 +78,7 @@ public class EventSeriesCompetitorAnalyticsTabView extends SharedLeaderboardEven
}
};
if (eventSeriesAnalyticsManager.getLeaderboardPanel() == null) {
eventSeriesAnalyticsManager.getSailingService().getAvailableDetailTypesForLeaderboard(leaderboardName,
eventSeriesAnalyticsManager.getAvailableDetailTypesForLeaderboard(leaderboardName,
null, new AsyncCallback<Iterable<DetailType>>() {
@Override
@@ -77,7 +77,7 @@ public class EventSeriesLeaderboardsTabView extends Composite implements SeriesT
final EventSeriesAnalyticsDataManager regattaAnalyticsManager = currentPresenter.getCtx()
.getAnalyticsManager();
regattaAnalyticsManager.getSailingService().getAvailableDetailTypesForLeaderboard(leaderboardName,
regattaAnalyticsManager.getAvailableDetailTypesForLeaderboard(leaderboardName,
null, new AsyncCallback<Iterable<DetailType>>() {
@Override
@@ -64,7 +64,7 @@ public class EventSeriesOverallLeaderboardTabView extends SharedLeaderboardEvent
contentArea.setWidget(currentPresenter.getErrorAndBusyClientFactory().createBusyView());
String leaderboardName = currentPresenter.getSeriesDTO().getLeaderboardId();
if (leaderboardName != null && !leaderboardName.isEmpty()) {
currentPresenter.getCtx().getAnalyticsManager().getSailingService().getAvailableDetailTypesForLeaderboard(leaderboardName, null, new AsyncCallback<Iterable<DetailType>>() {
currentPresenter.getCtx().getAnalyticsManager().getAvailableDetailTypesForLeaderboard(leaderboardName, null, new AsyncCallback<Iterable<DetailType>>() {
@Override
public void onSuccess(Iterable<DetailType> result) {
@@ -1,8 +1,17 @@
package com.sap.sailing.gwt.home.server.servlets;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import org.osgi.framework.BundleContext;
import org.osgi.util.tracker.ServiceTracker;
import com.sap.sailing.domain.common.sharding.ShardingType;
import com.sap.sailing.domain.sharding.ShardingContext;
import com.sap.sailing.domain.windfinder.WindFinderTrackerFactory;
import com.sap.sailing.gwt.home.communication.SailingDispatchContext;
import com.sap.sailing.gwt.home.server.SailingDispatchContextImpl;
@@ -47,4 +56,19 @@ public class SailingDispatchServlet extends AbstractDispatchServlet<SailingDispa
userStoreTracker.getService(), trackedRaceStatisticsCacheTracker.getService(),
request.getClientLocaleName(), getThreadLocalRequest());
}
@Override
public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException {
ShardingType identifiedShardingType = null;
try {
if (req instanceof HttpServletRequest) {
identifiedShardingType = ShardingContext.identifyAndSetShardingConstraint( ((HttpServletRequest) req).getPathInfo());
}
super.service(req, res);
} finally {
if (identifiedShardingType != null) {
ShardingContext.clearShardingConstraint(identifiedShardingType);
}
}
}
}
@@ -64,6 +64,7 @@ public class RegattaOverviewEntryPoint extends AbstractSailingEntryPoint {
return;
}
createAndAddDetailPanel();
createAndAddRegattaPanel(regattaOverviewContextDefinition);
toggleDetailPanel(false);
@@ -88,7 +89,7 @@ public class RegattaOverviewEntryPoint extends AbstractSailingEntryPoint {
}
private void createAndAddRegattaPanel(RegattaOverviewContextDefinition regattaOverviewContextDefinition) {
regattaPanel = new RegattaOverviewPanel(sailingService, getUserService(), this, getStringMessages(),
regattaPanel = new RegattaOverviewPanel(getSailingService(), getUserService(), this, getStringMessages(),
regattaOverviewContextDefinition);
regattaPanel.addHandler(new EventDTOLoadedEvent.Handler() {
@@ -83,14 +83,14 @@ public class AdminConsoleEntryPoint extends AbstractSailingEntryPoint implements
private Widget createAdminConsolePanel() {
AdminConsolePanel panel = new AdminConsolePanel(getUserService(), SailingPermissionsForRoleProvider.INSTANCE,
sailingService, getStringMessages().releaseNotes(), "/release_notes_admin.html", /* error reporter */ this, SecurityStylesheetResources.INSTANCE.css(), getStringMessages());
getSailingService(), getStringMessages().releaseNotes(), "/release_notes_admin.html", /* error reporter */ this, SecurityStylesheetResources.INSTANCE.css(), getStringMessages());
panel.addStyleName("adminConsolePanel");
regattasDisplayers = new HashSet<>();
leaderboardsDisplayers = new HashSet<>();
leaderboardGroupsDisplayers = new HashSet<>();
final EventManagementPanel eventManagementPanel = new EventManagementPanel(sailingService, this, this, getStringMessages(), panel);
final EventManagementPanel eventManagementPanel = new EventManagementPanel(getSailingService(), this, this, getStringMessages(), panel);
eventManagementPanel.ensureDebugId("EventManagement");
panel.addToVerticalTabPanel(new DefaultRefreshableAdminConsolePanel<EventManagementPanel>(eventManagementPanel) {
@Override
@@ -104,7 +104,7 @@ public class AdminConsoleEntryPoint extends AbstractSailingEntryPoint implements
/* REGATTAS */
RegattaManagementPanel regattaManagementPanel = new RegattaManagementPanel(
sailingService, this, getStringMessages(), this, eventManagementPanel);
getSailingService(), this, getStringMessages(), this, eventManagementPanel);
regattaManagementPanel.ensureDebugId("RegattaStructureManagement");
panel.addToVerticalTabPanel(new DefaultRefreshableAdminConsolePanel<RegattaManagementPanel>(regattaManagementPanel) {
@Override
@@ -117,7 +117,7 @@ public class AdminConsoleEntryPoint extends AbstractSailingEntryPoint implements
/* LEADERBOARDS */
final HorizontalTabLayoutPanel leaderboardTabPanel = panel.addVerticalTab(getStringMessages().leaderboards(), "LeaderboardPanel");
final LeaderboardConfigPanel leaderboardConfigPanel = new LeaderboardConfigPanel(sailingService, this, this,
final LeaderboardConfigPanel leaderboardConfigPanel = new LeaderboardConfigPanel(getSailingService(), this, this,
getStringMessages(), /* showRaceDetails */true, this);
leaderboardConfigPanel.ensureDebugId("LeaderboardConfiguration");
panel.addToTabPanel(leaderboardTabPanel, new DefaultRefreshableAdminConsolePanel<LeaderboardConfigPanel>(leaderboardConfigPanel) {
@@ -129,7 +129,7 @@ public class AdminConsoleEntryPoint extends AbstractSailingEntryPoint implements
regattasDisplayers.add(leaderboardConfigPanel);
leaderboardsDisplayers.add(leaderboardConfigPanel);
final LeaderboardGroupConfigPanel leaderboardGroupConfigPanel = new LeaderboardGroupConfigPanel(sailingService,
final LeaderboardGroupConfigPanel leaderboardGroupConfigPanel = new LeaderboardGroupConfigPanel(getSailingService(),
this, this, this, this, getStringMessages());
leaderboardGroupConfigPanel.ensureDebugId("LeaderboardGroupConfiguration");
panel.addToTabPanel(leaderboardTabPanel, new DefaultRefreshableAdminConsolePanel<LeaderboardGroupConfigPanel>(leaderboardGroupConfigPanel) {
@@ -154,7 +154,7 @@ public class AdminConsoleEntryPoint extends AbstractSailingEntryPoint implements
final HorizontalTabLayoutPanel racesTabPanel = panel.addVerticalTab(getStringMessages().trackedRaces(), "RacesPanel");
racesTabPanel.ensureDebugId("RacesPanel");
final TrackedRacesManagementPanel trackedRacesManagementPanel = new TrackedRacesManagementPanel(sailingService, this,
final TrackedRacesManagementPanel trackedRacesManagementPanel = new TrackedRacesManagementPanel(getSailingService(), this,
this, getStringMessages());
trackedRacesManagementPanel.ensureDebugId("TrackedRacesManagement");
panel.addToTabPanel(racesTabPanel, new DefaultRefreshableAdminConsolePanel<TrackedRacesManagementPanel>(trackedRacesManagementPanel) {
@@ -165,7 +165,7 @@ public class AdminConsoleEntryPoint extends AbstractSailingEntryPoint implements
}, getStringMessages().trackedRaces(), Permission.SHOW_TRACKED_RACES);
regattasDisplayers.add(trackedRacesManagementPanel);
final CompetitorPanel competitorPanel = new CompetitorPanel(sailingService, getStringMessages(), this);
final CompetitorPanel competitorPanel = new CompetitorPanel(getSailingService(), getStringMessages(), this);
competitorPanel.ensureDebugId("CompetitorPanel");
panel.addToTabPanel(racesTabPanel, new DefaultRefreshableAdminConsolePanel<CompetitorPanel>(competitorPanel) {
@Override
@@ -174,7 +174,7 @@ public class AdminConsoleEntryPoint extends AbstractSailingEntryPoint implements
}
}, getStringMessages().competitors(), Permission.MANAGE_ALL_COMPETITORS);
final BoatPanel boatPanel = new BoatPanel(sailingService, getStringMessages(), this);
final BoatPanel boatPanel = new BoatPanel(getSailingService(), getStringMessages(), this);
boatPanel.ensureDebugId("BoatPanel");
panel.addToTabPanel(racesTabPanel, new DefaultRefreshableAdminConsolePanel<BoatPanel>(boatPanel) {
@Override
@@ -183,18 +183,18 @@ public class AdminConsoleEntryPoint extends AbstractSailingEntryPoint implements
}
}, getStringMessages().boats(), Permission.MANAGE_ALL_BOATS);
RaceCourseManagementPanel raceCourseManagementPanel = new RaceCourseManagementPanel(sailingService, this, this, getStringMessages());
RaceCourseManagementPanel raceCourseManagementPanel = new RaceCourseManagementPanel(getSailingService(), this, this, getStringMessages());
panel.addToTabPanel(racesTabPanel, new DefaultRefreshableAdminConsolePanel<RaceCourseManagementPanel>(raceCourseManagementPanel), getStringMessages().courseLayout(), Permission.MANAGE_COURSE_LAYOUT);
regattasDisplayers.add(raceCourseManagementPanel);
final AsyncActionsExecutor asyncActionsExecutor = new AsyncActionsExecutor();
WindPanel windPanel = new WindPanel(sailingService, asyncActionsExecutor, this, this, getStringMessages());
WindPanel windPanel = new WindPanel(getSailingService(), asyncActionsExecutor, this, this, getStringMessages());
panel.addToTabPanel(racesTabPanel, new DefaultRefreshableAdminConsolePanel<WindPanel>(windPanel), getStringMessages().wind(),
Permission.MANAGE_WIND);
regattasDisplayers.add(windPanel);
final MediaPanel mediaPanel = new MediaPanel(regattasDisplayers, sailingService, this, mediaService, this, getStringMessages());
final MediaPanel mediaPanel = new MediaPanel(regattasDisplayers, getSailingService(), this, mediaService, this, getStringMessages());
panel.addToTabPanel(racesTabPanel, new DefaultRefreshableAdminConsolePanel<MediaPanel>(mediaPanel) {
@Override
public void refreshAfterBecomingVisible() {
@@ -205,7 +205,7 @@ public class AdminConsoleEntryPoint extends AbstractSailingEntryPoint implements
/* RACE COMMITTEE APP */
final HorizontalTabLayoutPanel raceCommitteeTabPanel = panel.addVerticalTab(getStringMessages().raceCommitteeApp(), "RaceCommiteeAppPanel");
final DeviceConfigurationUserPanel deviceConfigurationUserPanel = new DeviceConfigurationUserPanel(sailingService,
final DeviceConfigurationUserPanel deviceConfigurationUserPanel = new DeviceConfigurationUserPanel(getSailingService(),
getUserService(), getStringMessages(), this);
panel.addToTabPanel(raceCommitteeTabPanel, new DefaultRefreshableAdminConsolePanel<DeviceConfigurationUserPanel>(deviceConfigurationUserPanel),
getStringMessages().deviceConfiguration(), Permission.MANAGE_DEVICE_CONFIGURATION);
@@ -213,7 +213,7 @@ public class AdminConsoleEntryPoint extends AbstractSailingEntryPoint implements
/* CONNECTORS */
final HorizontalTabLayoutPanel connectorsTabPanel = panel.addVerticalTab(getStringMessages().connectors(), "TrackingProviderPanel");
TracTracEventManagementPanel tractracEventManagementPanel = new TracTracEventManagementPanel(sailingService,
TracTracEventManagementPanel tractracEventManagementPanel = new TracTracEventManagementPanel(getSailingService(),
this, this, getStringMessages());
tractracEventManagementPanel.ensureDebugId("TracTracEventManagement");
panel.addToTabPanel(connectorsTabPanel, new DefaultRefreshableAdminConsolePanel<TracTracEventManagementPanel>(tractracEventManagementPanel),
@@ -221,19 +221,19 @@ public class AdminConsoleEntryPoint extends AbstractSailingEntryPoint implements
regattasDisplayers.add(tractracEventManagementPanel);
SwissTimingReplayConnectorPanel swissTimingReplayConnectorPanel = new SwissTimingReplayConnectorPanel(
sailingService, this, this, getStringMessages());
getSailingService(), this, this, getStringMessages());
panel.addToTabPanel(connectorsTabPanel, new DefaultRefreshableAdminConsolePanel<SwissTimingReplayConnectorPanel>(swissTimingReplayConnectorPanel),
getStringMessages().swissTimingArchiveConnector(), Permission.MANAGE_TRACKED_RACES);
regattasDisplayers.add(swissTimingReplayConnectorPanel);
SwissTimingEventManagementPanel swisstimingEventManagementPanel = new SwissTimingEventManagementPanel(
sailingService, this, this, getStringMessages());
getSailingService(), this, this, getStringMessages());
panel.addToTabPanel(connectorsTabPanel, new DefaultRefreshableAdminConsolePanel<SwissTimingEventManagementPanel>(swisstimingEventManagementPanel),
getStringMessages().swissTimingEvents(), Permission.MANAGE_TRACKED_RACES);
regattasDisplayers.add(swisstimingEventManagementPanel);
final SmartphoneTrackingEventManagementPanel raceLogTrackingEventManagementPanel = new SmartphoneTrackingEventManagementPanel(
sailingService, this, this, this, getStringMessages());
getSailingService(), this, this, this, getStringMessages());
raceLogTrackingEventManagementPanel.ensureDebugId("SmartphoneTrackingPanel");
panel.addToTabPanel(connectorsTabPanel, new DefaultRefreshableAdminConsolePanel<SmartphoneTrackingEventManagementPanel>(raceLogTrackingEventManagementPanel) {
@Override
@@ -244,12 +244,12 @@ public class AdminConsoleEntryPoint extends AbstractSailingEntryPoint implements
regattasDisplayers.add(raceLogTrackingEventManagementPanel);
leaderboardsDisplayers.add(raceLogTrackingEventManagementPanel);
IgtimiAccountsPanel igtimiAccountsPanel = new IgtimiAccountsPanel(sailingService, this, getStringMessages());
IgtimiAccountsPanel igtimiAccountsPanel = new IgtimiAccountsPanel(getSailingService(), this, getStringMessages());
igtimiAccountsPanel.ensureDebugId("IgtimiAccounts");
panel.addToTabPanel(connectorsTabPanel, new DefaultRefreshableAdminConsolePanel<IgtimiAccountsPanel>(igtimiAccountsPanel),
getStringMessages().igtimiAccounts(), Permission.MANAGE_IGTIMI_ACCOUNTS);
ExpeditionDeviceConfigurationsPanel expeditionDeviceConfigurationsPanel = new ExpeditionDeviceConfigurationsPanel(sailingService, this, getStringMessages());
ExpeditionDeviceConfigurationsPanel expeditionDeviceConfigurationsPanel = new ExpeditionDeviceConfigurationsPanel(getSailingService(), this, getStringMessages());
expeditionDeviceConfigurationsPanel.ensureDebugId("ExpeditionDeviceConfigurations");
panel.addToTabPanel(connectorsTabPanel, new DefaultRefreshableAdminConsolePanel<ExpeditionDeviceConfigurationsPanel>(expeditionDeviceConfigurationsPanel) {
@Override
@@ -258,11 +258,11 @@ public class AdminConsoleEntryPoint extends AbstractSailingEntryPoint implements
}
}, getStringMessages().expeditionDeviceConfigurations(), Permission.MANAGE_EXPEDITION_DEVICE_CONFIGURATIONS);
ResultImportUrlsManagementPanel resultImportUrlsManagementPanel = new ResultImportUrlsManagementPanel(sailingService, this, getStringMessages());
ResultImportUrlsManagementPanel resultImportUrlsManagementPanel = new ResultImportUrlsManagementPanel(getSailingService(), this, getStringMessages());
panel.addToTabPanel(connectorsTabPanel, new DefaultRefreshableAdminConsolePanel<ResultImportUrlsManagementPanel>(resultImportUrlsManagementPanel),
getStringMessages().resultImportUrls(), Permission.MANAGE_RESULT_IMPORT_URLS);
StructureImportManagementPanel structureImportUrlsManagementPanel = new StructureImportManagementPanel(sailingService, this, getStringMessages(), this, eventManagementPanel);
StructureImportManagementPanel structureImportUrlsManagementPanel = new StructureImportManagementPanel(getSailingService(), this, getStringMessages(), this, eventManagementPanel);
panel.addToTabPanel(connectorsTabPanel, new DefaultRefreshableAdminConsolePanel<StructureImportManagementPanel>(structureImportUrlsManagementPanel),
getStringMessages().manage2Sail() + " " + getStringMessages().regattaStructureImport(), Permission.MANAGE_STRUCTURE_IMPORT_URLS);
@@ -270,7 +270,7 @@ public class AdminConsoleEntryPoint extends AbstractSailingEntryPoint implements
final HorizontalTabLayoutPanel advancedTabPanel = panel.addVerticalTab(getStringMessages().advanced(), "AdvancedPanel");
advancedTabPanel.ensureDebugId("AdvancedTab");
final ReplicationPanel replicationPanel = new ReplicationPanel(sailingService, this, getStringMessages());
final ReplicationPanel replicationPanel = new ReplicationPanel(getSailingService(), this, getStringMessages());
panel.addToTabPanel(advancedTabPanel, new DefaultRefreshableAdminConsolePanel<ReplicationPanel>(replicationPanel) {
@Override
public void refreshAfterBecomingVisible() {
@@ -278,17 +278,17 @@ public class AdminConsoleEntryPoint extends AbstractSailingEntryPoint implements
}
}, getStringMessages().replication(), Permission.MANAGE_REPLICATION);
final MasterDataImportPanel masterDataImportPanel = new MasterDataImportPanel(getStringMessages(), sailingService,
final MasterDataImportPanel masterDataImportPanel = new MasterDataImportPanel(getStringMessages(), getSailingService(),
this, eventManagementPanel, this, this, mediaPanel);
masterDataImportPanel.ensureDebugId("MasterDataImport");
panel.addToTabPanel(advancedTabPanel, new DefaultRefreshableAdminConsolePanel<MasterDataImportPanel>(masterDataImportPanel),
getStringMessages().masterDataImportPanel(), Permission.MANAGE_MASTERDATA_IMPORT);
RemoteServerInstancesManagementPanel remoteServerInstancesManagementPanel = new RemoteServerInstancesManagementPanel(sailingService, this, getStringMessages());
RemoteServerInstancesManagementPanel remoteServerInstancesManagementPanel = new RemoteServerInstancesManagementPanel(getSailingService(), this, getStringMessages());
panel.addToTabPanel(advancedTabPanel, new DefaultRefreshableAdminConsolePanel<RemoteServerInstancesManagementPanel>(remoteServerInstancesManagementPanel),
getStringMessages().remoteServerInstances(), Permission.MANAGE_SAILING_SERVER_INSTANCES);
LocalServerManagementPanel localServerInstancesManagementPanel = new LocalServerManagementPanel(sailingService, this, getStringMessages());
LocalServerManagementPanel localServerInstancesManagementPanel = new LocalServerManagementPanel(getSailingService(), this, getStringMessages());
panel.addToTabPanel(advancedTabPanel, new DefaultRefreshableAdminConsolePanel<LocalServerManagementPanel>(localServerInstancesManagementPanel),
getStringMessages().localServer(), Permission.MANAGE_LOCAL_SERVER_INSTANCE);
@@ -297,7 +297,7 @@ public class AdminConsoleEntryPoint extends AbstractSailingEntryPoint implements
panel.addToTabPanel(advancedTabPanel, new DefaultRefreshableAdminConsolePanel<UserManagementPanel>(userManagementPanel),
getStringMessages().userManagement(), Permission.MANAGE_USERS);
final FileStoragePanel fileStoragePanel = new FileStoragePanel(sailingService, this);
final FileStoragePanel fileStoragePanel = new FileStoragePanel(getSailingService(), this);
panel.addToTabPanel(advancedTabPanel, new DefaultRefreshableAdminConsolePanel<FileStoragePanel>(fileStoragePanel),
getStringMessages().fileStorage(), Permission.MANAGE_FILE_STORAGE);
@@ -311,7 +311,7 @@ public class AdminConsoleEntryPoint extends AbstractSailingEntryPoint implements
@Override
public void fillLeaderboards() {
sailingService.getLeaderboards(new MarkedAsyncCallback<List<StrippedLeaderboardDTO>>(
getSailingService().getLeaderboards(new MarkedAsyncCallback<List<StrippedLeaderboardDTO>>(
new AsyncCallback<List<StrippedLeaderboardDTO>>() {
@Override
public void onSuccess(List<StrippedLeaderboardDTO> leaderboards) {
@@ -338,7 +338,7 @@ public class AdminConsoleEntryPoint extends AbstractSailingEntryPoint implements
@Override
public void fillLeaderboardGroups() {
sailingService.getLeaderboardGroups(false /*withGeoLocationData*/,
getSailingService().getLeaderboardGroups(false /*withGeoLocationData*/,
new MarkedAsyncCallback<List<LeaderboardGroupDTO>>(
new AsyncCallback<List<LeaderboardGroupDTO>>() {
@Override
@@ -366,7 +366,7 @@ public class AdminConsoleEntryPoint extends AbstractSailingEntryPoint implements
@Override
public void fillRegattas() {
sailingService.getRegattas(new MarkedAsyncCallback<List<RegattaDTO>>(
getSailingService().getRegattas(new MarkedAsyncCallback<List<RegattaDTO>>(
new AsyncCallback<List<RegattaDTO>>() {
@Override
public void onSuccess(List<RegattaDTO> result) {
@@ -1,17 +1,32 @@
package com.sap.sailing.gwt.ui.client;
import com.google.gwt.core.client.GWT;
import com.google.gwt.user.client.rpc.ServiceDefTarget;
import com.sap.sse.gwt.client.EntryPointHelper;
import com.sap.sailing.gwt.common.communication.routing.ProvidesLeaderboardRouting;
import com.sap.sse.gwt.client.ServiceRoutingProvider;
import com.sap.sse.security.ui.client.AbstractSecureEntryPoint;
public abstract class AbstractSailingEntryPoint extends AbstractSecureEntryPoint<StringMessages> {
protected final SailingServiceAsync sailingService = GWT.create(SailingService.class);
private SailingServiceAsync sailingService;
@Override
protected void doOnModuleLoad() {
super.doOnModuleLoad();
EntryPointHelper.registerASyncService((ServiceDefTarget) sailingService, RemoteServiceMappingConstants.sailingServiceRemotePath);
}
/**
* Lazily initialize sailing service. Concrete entry point subclasses may influence sailing service creation by
* implementing a given routing information providing interface {@link ProvidesLeaderboardRouting}. The routing
* information provided via {@link ProvidesLeaderboardRouting#getLeaderboardName()} needs to be available when this
* method is called for the first time. Repetitive calls will not cause a new leaderboard name to take effect.
*/
protected SailingServiceAsync getSailingService() {
if (sailingService == null) {
if (this instanceof ServiceRoutingProvider) {
sailingService = SailingServiceHelper.createSailingServiceInstance((ServiceRoutingProvider)this);
} else {
sailingService = SailingServiceHelper.createSailingServiceInstance();
}
}
return sailingService;
}
@Override
@@ -1,5 +1,6 @@
package com.sap.sailing.gwt.ui.client;
import com.sap.sailing.gwt.common.communication.routing.ProvidesLeaderboardRouting;
import com.sap.sse.gwt.client.mvp.ClientFactory;
import com.sap.sse.gwt.client.mvp.ErrorView;
import com.sap.sse.security.ui.client.WithSecurity;
@@ -11,9 +12,12 @@ import com.sap.sse.security.ui.client.WithSecurity;
*
*/
public interface SailingClientFactory extends ClientFactory, WithSecurity {
SailingServiceAsync getSailingService();
SailingServiceAsync getSailingService(ProvidesLeaderboardRouting routingProvider);
MediaServiceAsync getMediaService();
ErrorView createErrorView(String errorMessage, Throwable errorReason);
}
@@ -0,0 +1,60 @@
package com.sap.sailing.gwt.ui.client;
import com.google.gwt.core.client.GWT;
import com.google.gwt.user.client.rpc.ServiceDefTarget;
import com.sap.sse.gwt.client.ServiceRoutingProvider;
/**
* Set of convenience factory methods that create a {@link SailingServiceAsync} instance.
*/
public abstract class SailingServiceHelper {
private final static String moduleBaseURL = GWT.getModuleBaseURL();
private SailingServiceHelper() {
}
/**
* Creates a new {@link SailingServiceAsync} instance, should be used when code resides in the same bundle as the sailing service code.
*/
public static SailingServiceAsync createSailingServiceInstance() {
return createSailingServiceInstance(true, null);
}
/**
* Creates a new {@link SailingServiceAsync} instance.
*
* @param sameBundle {@code false} if using {@link SailingService} from a different OSGi bundle (e.g. dashboards), {@code true} otherwise
*/
public static SailingServiceAsync createSailingServiceInstance(boolean sameBundle) {
return createSailingServiceInstance(sameBundle, null);
}
/**
* Creates a new {@link SailingServiceAsync} instance that uses a routing provider, for code in same bundle.
*/
public static SailingServiceAsync createSailingServiceInstance(ServiceRoutingProvider routingProvider) {
return createSailingServiceInstance(true, routingProvider);
}
/**
* Crates a new {@link SailingServiceAsync} instance.
*
* @param sameBundle {@code false} if using {@link SailingService} from a different OSGi bundle (e.g. dashboards), {@code true} otherwise
*/
public static SailingServiceAsync createSailingServiceInstance(boolean sameBundle, ServiceRoutingProvider routingProvider) {
SailingServiceAsync service = GWT.create(SailingService.class);
ServiceDefTarget serviceToRegister = (ServiceDefTarget) service;
StringBuilder baseURL = new StringBuilder();
baseURL.append(moduleBaseURL.substring(0, moduleBaseURL.lastIndexOf('/', moduleBaseURL.length() - 2) + 1));
if (!sameBundle) {
baseURL.append(RemoteServiceMappingConstants.WEB_CONTEXT_PATH).append("/");
}
baseURL.append(RemoteServiceMappingConstants.sailingServiceRemotePath);
if (routingProvider != null) {
baseURL.append(routingProvider.routingSuffixPath());
}
serviceToRegister.setServiceEntryPoint(baseURL.toString());
return service;
}
}
@@ -17,6 +17,7 @@ import com.sap.sailing.domain.common.DetailType;
import com.sap.sailing.domain.common.dto.AbstractLeaderboardDTO;
import com.sap.sailing.gwt.common.authentication.FixedSailingAuthentication;
import com.sap.sailing.gwt.common.authentication.SAPSailingHeaderWithAuthentication;
import com.sap.sailing.gwt.common.communication.routing.ProvidesLeaderboardRouting;
import com.sap.sailing.gwt.settings.client.leaderboard.LeaderboardContextDefinition;
import com.sap.sailing.gwt.settings.client.leaderboard.LeaderboardPerspectiveLifecycle;
import com.sap.sailing.gwt.settings.client.leaderboard.LeaderboardPerspectiveOwnSettings;
@@ -40,12 +41,13 @@ import com.sap.sse.gwt.settings.SettingsToUrlSerializer;
import com.sap.sse.security.ui.settings.ComponentContextWithSettingsStorage;
import com.sap.sse.security.ui.settings.StoredSettingsLocation;
public class LeaderboardEntryPoint extends AbstractSailingEntryPoint {
public class LeaderboardEntryPoint extends AbstractSailingEntryPoint implements ProvidesLeaderboardRouting {
public static final long DEFAULT_REFRESH_INTERVAL_MILLIS = 3000l;
private static final Logger logger = Logger.getLogger(LeaderboardEntryPoint.class.getName());
private StringMessages stringmessages = StringMessages.INSTANCE;
private UUID eventId;
private String leaderboardName;
private String leaderboardGroupName;
private AbstractLeaderboardDTO leaderboardDTO;
@@ -58,7 +60,7 @@ public class LeaderboardEntryPoint extends AbstractSailingEntryPoint {
leaderboardContextDefinition = new SettingsToUrlSerializer()
.deserializeFromCurrentLocation(new LeaderboardContextDefinition());
final UUID eventId = leaderboardContextDefinition.getEventId();
eventId = leaderboardContextDefinition.getEventId();
leaderboardName = leaderboardContextDefinition.getLeaderboardName();
leaderboardGroupName = leaderboardContextDefinition.getLeaderboardGroupName();
@@ -67,9 +69,8 @@ public class LeaderboardEntryPoint extends AbstractSailingEntryPoint {
if (eventId == null) {
checkLeaderboardNameAndCreateUI(); // use null-initialized event field
} else {
// TODO it seems we do not really need the EventDTO. What's the intention of loading it? Should we
// visualize some information in the header?
sailingService.getEventById(eventId, /* withStatisticalData */false,
// TODO it seems we do not really need the EventDTO. What's the intention of loading it? Should we visualize some information in the header?
getSailingService().getEventById(eventId, /* withStatisticalData */false,
new MarkedAsyncCallback<EventDTO>(new AsyncCallback<EventDTO>() {
@Override
public void onFailure(Throwable caught) {
@@ -78,7 +79,7 @@ public class LeaderboardEntryPoint extends AbstractSailingEntryPoint {
@Override
public void onSuccess(EventDTO result) {
if (result != null) {
if(result != null) {
leaderboardDTO = result.getLeaderboardByName(leaderboardName);
}
checkLeaderboardNameAndCreateUI();
@@ -89,27 +90,27 @@ public class LeaderboardEntryPoint extends AbstractSailingEntryPoint {
RootPanel.get().add(new Label(getStringMessages().noSuchLeaderboard()));
}
}
private void checkLeaderboardNameAndCreateUI() {
if (leaderboardDTO == null) {
sailingService.getLeaderboard(leaderboardName,
new MarkedAsyncCallback<StrippedLeaderboardDTO>(new AsyncCallback<StrippedLeaderboardDTO>() {
@Override
public void onSuccess(StrippedLeaderboardDTO leaderboardDTO) {
if (leaderboardDTO != null) {
LeaderboardEntryPoint.this.leaderboardDTO = leaderboardDTO;
Window.setTitle(leaderboardName);
loadSettingsAndCreateUI();
} else {
RootPanel.get().add(new Label(getStringMessages().noSuchLeaderboard()));
if(leaderboardDTO == null) {
getSailingService().getLeaderboard(leaderboardName,
new MarkedAsyncCallback<StrippedLeaderboardDTO>(new AsyncCallback<StrippedLeaderboardDTO>() {
@Override
public void onSuccess(StrippedLeaderboardDTO leaderboardDTO) {
if (leaderboardDTO != null) {
LeaderboardEntryPoint.this.leaderboardDTO = leaderboardDTO;
Window.setTitle(leaderboardName);
loadSettingsAndCreateUI();
} else {
RootPanel.get().add(new Label(getStringMessages().noSuchLeaderboard()));
}
}
}
@Override
public void onFailure(Throwable t) {
reportError("Error trying to obtain list of leaderboard names: " + t.getMessage());
}
}));
@Override
public void onFailure(Throwable t) {
reportError("Error trying to obtain list of leaderboard names: " + t.getMessage());
}
}));
} else {
loadSettingsAndCreateUI();
}
@@ -118,12 +119,12 @@ public class LeaderboardEntryPoint extends AbstractSailingEntryPoint {
private void loadSettingsAndCreateUI() {
long delayBetweenAutoAdvancesInMilliseconds = DEFAULT_REFRESH_INTERVAL_MILLIS;
final Timer timer = new Timer(PlayModes.Live, PlayStates.Paused, delayBetweenAutoAdvancesInMilliseconds);
// make a single live request as the default but don't continue to play by default
final StoredSettingsLocation storageDefinition = StoredSettingsLocationFactory
.createStoredSettingsLocatorForLeaderboard(leaderboardContextDefinition);
sailingService.getAvailableDetailTypesForLeaderboard(leaderboardName,
.createStoredSettingsLocatorForLeaderboard(leaderboardContextDefinition);
getSailingService().getAvailableDetailTypesForLeaderboard(leaderboardName,
null, new AsyncCallback<Iterable<DetailType>>() {
@Override
public void onFailure(Throwable caught) {
@@ -147,7 +148,7 @@ public class LeaderboardEntryPoint extends AbstractSailingEntryPoint {
final MetaLeaderboardViewer leaderboardViewer = new MetaLeaderboardViewer(
null, context, rootComponentLifeCycle, defaultSettings,
sailingService, new AsyncActionsExecutor(), timer, null,
getSailingService(), new AsyncActionsExecutor(), timer, null,
leaderboardGroupName, leaderboardName, LeaderboardEntryPoint.this,
getStringMessages(), getActualChartDetailType(defaultSettings),
result);
@@ -174,7 +175,7 @@ public class LeaderboardEntryPoint extends AbstractSailingEntryPoint {
@Override
public void onSuccess(
PerspectiveCompositeSettings<LeaderboardPerspectiveOwnSettings> defaultSettings) {
sailingService.getAvailableDetailTypesForLeaderboard(leaderboardName,
getSailingService().getAvailableDetailTypesForLeaderboard(leaderboardName,
null, new AsyncCallback<Iterable<DetailType>>() {
@Override
@@ -189,7 +190,7 @@ public class LeaderboardEntryPoint extends AbstractSailingEntryPoint {
configureWithSettings(defaultSettings, timer);
final MultiRaceLeaderboardViewer leaderboardViewer = new MultiRaceLeaderboardViewer(
null, context, rootComponentLifeCycle,
defaultSettings, sailingService,
defaultSettings, getSailingService(),
new AsyncActionsExecutor(), timer,
leaderboardGroupName, leaderboardName,
LeaderboardEntryPoint.this, getStringMessages(),
@@ -212,25 +213,26 @@ public class LeaderboardEntryPoint extends AbstractSailingEntryPoint {
}
}
});
}
private DetailType getActualChartDetailType(
PerspectiveCompositeSettings<LeaderboardPerspectiveOwnSettings> settings) {
MultiCompetitorLeaderboardChartSettings chartSettings = settings
.findSettingsByComponentId(MultiCompetitorLeaderboardChartLifecycle.ID);
DetailType chartDetailType = chartSettings == null ? null : chartSettings.getDetailType();
if (chartDetailType == DetailType.REGATTA_NET_POINTS_SUM) {
return chartDetailType;
}
return MultiCompetitorLeaderboardChartSettings.getDefaultDetailType(leaderboardDTO.type.isMetaLeaderboard());
}
private void createUi(Widget leaderboardViewer,
PerspectiveCompositeSettings<LeaderboardPerspectiveOwnSettings> settings, Timer timer,
LeaderboardContextDefinition leaderboardContextSettings) {
LeaderboardPerspectiveOwnSettings ownSettings = settings.getPerspectiveOwnSettings();
DockLayoutPanel mainPanel = new DockLayoutPanel(Unit.PX);
RootLayoutPanel.get().add(mainPanel);
if (!ownSettings.isEmbedded()) {
@@ -258,11 +260,15 @@ public class LeaderboardEntryPoint extends AbstractSailingEntryPoint {
+ ");-o-transform-origin: 0 0;-webkit-transform: scale(" + zoomTo
+ ");-webkit-transform-origin: 0 0;");
}
if (perspectiveOwnSettings.isLifePlay()) {
timer.setPlayMode(PlayModes.Live); // the leaderboard, viewed via the entry point, goes "live" and "playing"
// if an auto-refresh
}
}
@Override
public String getLeaderboardName() {
return leaderboardName;
}
}
@@ -17,6 +17,7 @@ import com.sap.sailing.domain.common.security.Permission;
import com.sap.sailing.domain.common.security.SailingPermissionsForRoleProvider;
import com.sap.sailing.gwt.common.authentication.FixedSailingAuthentication;
import com.sap.sailing.gwt.common.authentication.SAPSailingHeaderWithAuthentication;
import com.sap.sailing.gwt.common.communication.routing.ProvidesLeaderboardRouting;
import com.sap.sailing.gwt.settings.client.leaderboardedit.LeaderboardEditContextDefinition;
import com.sap.sailing.gwt.ui.client.AbstractSailingEntryPoint;
import com.sap.sailing.gwt.ui.leaderboard.LeaderboardEntryPoint;
@@ -29,22 +30,23 @@ import com.sap.sse.security.ui.authentication.generic.GenericAuthentication;
import com.sap.sse.security.ui.authentication.generic.GenericAuthorizedContentDecorator;
import com.sap.sse.security.ui.authentication.generic.sapheader.SAPHeaderWithAuthentication;
public class LeaderboardEditPage extends AbstractSailingEntryPoint {
public class LeaderboardEditPage extends AbstractSailingEntryPoint implements ProvidesLeaderboardRouting {
private static final Logger logger = Logger.getLogger(LeaderboardEntryPoint.class.getName());
private String leaderboardName;
@Override
protected void doOnModuleLoad() {
super.doOnModuleLoad();
sailingService.getLeaderboardNames(new MarkedAsyncCallback<List<String>>(
final LeaderboardEditContextDefinition settings = new SettingsToUrlSerializer()
.deserializeFromCurrentLocation(new LeaderboardEditContextDefinition());
leaderboardName = settings.getLeaderboardName();
getSailingService().getLeaderboardNames(new MarkedAsyncCallback<List<String>>(
new AsyncCallback<List<String>>() {
@Override
public void onSuccess(List<String> leaderboardNames) {
final LeaderboardEditContextDefinition settings = new SettingsToUrlSerializer()
.deserializeFromCurrentLocation(new LeaderboardEditContextDefinition());
final String leaderboardName = settings.getLeaderboardName();
if (leaderboardNames.contains(leaderboardName)) {
sailingService.getAvailableDetailTypesForLeaderboard(leaderboardName, null, new AsyncCallback<Iterable<DetailType>>() {
getSailingService().getAvailableDetailTypesForLeaderboard(leaderboardName, null, new AsyncCallback<Iterable<DetailType>>() {
@Override
public void onFailure(Throwable caught) {
@@ -60,7 +62,7 @@ public class LeaderboardEditPage extends AbstractSailingEntryPoint {
authorizedContentDecorator.setContentWidgetFactory(new WidgetFactory() {
@Override
public Widget get() {
EditableLeaderboardPanel leaderboardPanel = new EditableLeaderboardPanel(sailingService, new AsyncActionsExecutor(), leaderboardName, null,
EditableLeaderboardPanel leaderboardPanel = new EditableLeaderboardPanel(getSailingService(), new AsyncActionsExecutor(), leaderboardName, null,
LeaderboardEditPage.this, getStringMessages(), userAgent, result);
leaderboardPanel.ensureDebugId("EditableLeaderboardPanel");
return leaderboardPanel;
@@ -91,4 +93,9 @@ public class LeaderboardEditPage extends AbstractSailingEntryPoint {
header.getElement().getStyle().setWidth(100, Unit.PCT);
return header;
}
@Override
public String getLeaderboardName() {
return leaderboardName;
}
}
@@ -18,6 +18,7 @@ import com.google.gwt.user.client.ui.Widget;
import com.sap.sailing.domain.common.dto.PairingListDTO;
import com.sap.sailing.gwt.common.authentication.FixedSailingAuthentication;
import com.sap.sailing.gwt.common.authentication.SAPSailingHeaderWithAuthentication;
import com.sap.sailing.gwt.common.communication.routing.ProvidesLeaderboardRouting;
import com.sap.sailing.gwt.ui.adminconsole.PairingListPreviewDialog;
import com.sap.sailing.gwt.ui.client.AbstractSailingEntryPoint;
import com.sap.sailing.gwt.ui.client.StringMessages;
@@ -25,19 +26,21 @@ import com.sap.sailing.gwt.ui.shared.StrippedLeaderboardDTO;
import com.sap.sse.common.Color;
import com.sap.sse.gwt.settings.SettingsToUrlSerializer;
public class PairingListEntryPoint extends AbstractSailingEntryPoint {
public class PairingListEntryPoint extends AbstractSailingEntryPoint implements ProvidesLeaderboardRouting {
private PairingListContextDefinition pairingListContextDefinition;
private StringMessages stringMessages = StringMessages.INSTANCE;
private StrippedLeaderboardDTO strippedLeaderboardDTO;
private String leaderboardName;
@Override
protected void doOnModuleLoad() {
super.doOnModuleLoad();
pairingListContextDefinition = new SettingsToUrlSerializer()
.deserializeFromCurrentLocation(new PairingListContextDefinition());
this.sailingService.getLeaderboard(pairingListContextDefinition.getLeaderboardName(),
leaderboardName = pairingListContextDefinition.getLeaderboardName();
getSailingService().getLeaderboard(leaderboardName,
new AsyncCallback<StrippedLeaderboardDTO>() {
@Override
public void onFailure(Throwable caught) {
@@ -68,12 +71,12 @@ public class PairingListEntryPoint extends AbstractSailingEntryPoint {
contentPanel.getElement().getStyle().setProperty("marginTop", "15px");
contentPanel.getElement().getStyle().setProperty("marginBottom", "15px");
scrollPanel.add(contentPanel);
sailingService.getPairingListFromRaceLogs(pairingListContextDefinition.getLeaderboardName(),
getSailingService().getPairingListFromRaceLogs(pairingListContextDefinition.getLeaderboardName(),
new AsyncCallback<PairingListDTO>() {
@Override
public void onSuccess(PairingListDTO result) {
if (strippedLeaderboardDTO != null) {
sailingService.getRaceDisplayNamesFromLeaderboard(strippedLeaderboardDTO.getName(),
getSailingService().getRaceDisplayNamesFromLeaderboard(strippedLeaderboardDTO.getName(),
result.getRaceColumnNames(), new AsyncCallback<List<String>>() {
@Override
public void onFailure(Throwable caught) {
@@ -126,7 +129,7 @@ public class PairingListEntryPoint extends AbstractSailingEntryPoint {
pairingListPanel.getElement().getStyle().setProperty("marginTop", "15px");
return pairingListPanel;
}
private native void printPairingListGrid(String pageHTMLContent) /*-{
var frameID = '__gwt_historyFrame';
var frame = $doc.getElementById(frameID);
@@ -167,4 +170,8 @@ public class PairingListEntryPoint extends AbstractSailingEntryPoint {
}, 100);
}-*/;
@Override
public String getLeaderboardName() {
return leaderboardName;
}
}
@@ -25,6 +25,7 @@ import com.sap.sailing.domain.common.dto.BoatDTO;
import com.sap.sailing.domain.common.dto.CompetitorDTO;
import com.sap.sailing.gwt.common.authentication.FixedSailingAuthentication;
import com.sap.sailing.gwt.common.authentication.SAPSailingHeaderWithAuthentication;
import com.sap.sailing.gwt.common.communication.routing.ProvidesLeaderboardRouting;
import com.sap.sailing.gwt.settings.client.raceboard.RaceBoardPerspectiveOwnSettings;
import com.sap.sailing.gwt.ui.client.AbstractSailingEntryPoint;
import com.sap.sailing.gwt.ui.client.CompetitorColorProvider;
@@ -62,7 +63,7 @@ import com.sap.sse.gwt.client.player.Timer.PlayModes;
import com.sap.sse.gwt.shared.GwtHttpRequestUtils;
import com.sap.sse.security.ui.authentication.generic.sapheader.SAPHeaderWithAuthentication;
public class EmbeddedMapAndWindChartEntryPoint extends AbstractSailingEntryPoint {
public class EmbeddedMapAndWindChartEntryPoint extends AbstractSailingEntryPoint implements ProvidesLeaderboardRouting {
private static final String PARAM_REGATTA_LIKE_NAME = "regattaLikeName";
private static final String PARAM_RACE_COLUMN_NAME = "raceColumnName";
private static final String PARAM_FLEET_NAME = "fleetName";
@@ -122,13 +123,13 @@ public class EmbeddedMapAndWindChartEntryPoint extends AbstractSailingEntryPoint
defaultRaceMapSettings.isShowDouglasPeuckerPoints(), true,
defaultRaceMapSettings.getStartCountDownFontSizeScaling());
sailingService.getRaceIdentifier(regattaLikeName, raceColumnName, fleetName, new AsyncCallback<RegattaAndRaceIdentifier>() {
getSailingService().getRaceIdentifier(regattaLikeName, raceColumnName, fleetName, new AsyncCallback<RegattaAndRaceIdentifier>() {
@Override
public void onSuccess(final RegattaAndRaceIdentifier selectedRaceIdentifier) {
if (selectedRaceIdentifier == null) {
createErrorPage(getStringMessages().couldNotObtainRace(regattaLikeName, raceColumnName, fleetName, /* technicalErrorMessage */ ""));
} else {
sailingService.getCompetitorBoats(selectedRaceIdentifier, new AsyncCallback<Map<CompetitorDTO, BoatDTO>>() {
getSailingService().getCompetitorBoats(selectedRaceIdentifier, new AsyncCallback<Map<CompetitorDTO, BoatDTO>>() {
@Override
public void onSuccess(Map<CompetitorDTO, BoatDTO> result) {
createEmbeddedMap(selectedRaceIdentifier, result, raceboardPerspectiveSettings, raceMapSettings,
@@ -187,7 +188,7 @@ public class EmbeddedMapAndWindChartEntryPoint extends AbstractSailingEntryPoint
return true;
}
};
RaceTimesInfoProvider raceTimesInfoProvider = new RaceTimesInfoProvider(sailingService, asyncActionsExecutor, /* errorReporter */ this,
RaceTimesInfoProvider raceTimesInfoProvider = new RaceTimesInfoProvider(getSailingService(), asyncActionsExecutor, /* errorReporter */ this,
Collections.singleton(selectedRaceIdentifier), 30000l /* requestInterval*/);
raceTimesInfoProvider.addRaceTimesInfoProviderListener(new RaceTimesInfoProviderListener() {
@Override
@@ -208,7 +209,7 @@ public class EmbeddedMapAndWindChartEntryPoint extends AbstractSailingEntryPoint
competitorSelection = createEmptyFilterCompetitorModel(colorProvider, competitorsAndBoats); // show no competitors
}
final RaceMap raceMap = new RaceMap(null, null, new RaceMapLifecycle(getStringMessages()), raceMapSettings,
sailingService, asyncActionsExecutor, /* errorReporter */ EmbeddedMapAndWindChartEntryPoint.this, timer,
getSailingService(), asyncActionsExecutor, /* errorReporter */ EmbeddedMapAndWindChartEntryPoint.this, timer,
competitorSelection, new RaceCompetitorSet(competitorSelection), getStringMessages(), selectedRaceIdentifier,
raceMapResources, /* showHeaderPanel */ false, new DefaultQuickRanksDTOProvider()) {
@Override
@@ -219,7 +220,7 @@ public class EmbeddedMapAndWindChartEntryPoint extends AbstractSailingEntryPoint
};
final WindChart windChart;
if (raceboardPerspectiveSettings.isShowWindChart()) {
windChart = new WindChart(null, null, new WindChartLifecycle(getStringMessages()), sailingService,
windChart = new WindChart(null, null, new WindChartLifecycle(getStringMessages()), getSailingService(),
selectedRaceIdentifier, timer,
timeRangeWithZoomProvider, new WindChartSettings(), getStringMessages(),
asyncActionsExecutor, /* errorReporter */
@@ -254,4 +255,9 @@ public class EmbeddedMapAndWindChartEntryPoint extends AbstractSailingEntryPoint
p.insert(raceMap.getEntryWidget(), raceMap, Direction.CENTER, 400);
p.addStyleName("dockLayoutPanel");
}
@Override
public String getLeaderboardName() {
return regattaLikeName;
}
}
@@ -14,6 +14,7 @@ import com.google.gwt.user.client.ui.RootLayoutPanel;
import com.sap.sailing.domain.common.DetailType;
import com.sap.sailing.gwt.common.authentication.FixedSailingAuthentication;
import com.sap.sailing.gwt.common.authentication.SAPSailingHeaderWithAuthentication;
import com.sap.sailing.gwt.common.communication.routing.ProvidesLeaderboardRouting;
import com.sap.sailing.gwt.settings.client.raceboard.RaceBoardPerspectiveOwnSettings;
import com.sap.sailing.gwt.settings.client.raceboard.RaceboardContextDefinition;
import com.sap.sailing.gwt.settings.client.utils.StoredSettingsLocationFactory;
@@ -38,7 +39,7 @@ import com.sap.sse.security.ui.authentication.generic.sapheader.SAPHeaderWithAut
import com.sap.sse.security.ui.settings.ComponentContextWithSettingsStorage;
import com.sap.sse.security.ui.settings.StoredSettingsLocation;
public class RaceBoardEntryPoint extends AbstractSailingEntryPoint {
public class RaceBoardEntryPoint extends AbstractSailingEntryPoint implements ProvidesLeaderboardRouting {
private RaceWithCompetitorsAndBoatsDTO selectedRace;
/**
@@ -48,10 +49,13 @@ public class RaceBoardEntryPoint extends AbstractSailingEntryPoint {
private RaceboardContextDefinition raceboardContextDefinition;
private String leaderBoardName;
@Override
protected void doOnModuleLoad() {
super.doOnModuleLoad();
EntryPointHelper.registerASyncService((ServiceDefTarget) mediaService, RemoteServiceMappingConstants.mediaServiceRemotePath);
EntryPointHelper.registerASyncService((ServiceDefTarget) mediaService,
RemoteServiceMappingConstants.mediaServiceRemotePath);
raceboardContextDefinition = new SettingsToUrlSerializer()
.deserializeFromCurrentLocation(new RaceboardContextDefinition());
final RaceBoardModes finalMode;
@@ -61,12 +65,16 @@ public class RaceBoardEntryPoint extends AbstractSailingEntryPoint {
finalMode = null;
}
if (raceboardContextDefinition.getRegattaName() == null || raceboardContextDefinition.getRegattaName().isEmpty()
|| raceboardContextDefinition.getRaceName() == null || raceboardContextDefinition.getRaceName().isEmpty()
|| raceboardContextDefinition.getRaceName() == null
|| raceboardContextDefinition.getRaceName().isEmpty()
|| raceboardContextDefinition.getLeaderboardName() == null
|| raceboardContextDefinition.getLeaderboardName().isEmpty()) {
createErrorPage(getStringMessages().requiresRegattaRaceAndLeaderboard());
return;
}
leaderBoardName = raceboardContextDefinition.getLeaderboardName();
AsyncCallback<RaceboardDataDTO> asyncCallback = new AsyncCallback<RaceboardDataDTO>() {
@Override
public void onSuccess(RaceboardDataDTO raceboardData) {
@@ -93,17 +101,18 @@ public class RaceBoardEntryPoint extends AbstractSailingEntryPoint {
}
}
if (raceboardData.getRace() == null) {
createErrorPage(getStringMessages().couldNotFindRaceInRegatta(raceboardContextDefinition.getRaceName(), raceboardContextDefinition.getRegattaName()));
createErrorPage(getStringMessages().couldNotFindRaceInRegatta(
raceboardContextDefinition.getRaceName(), raceboardContextDefinition.getRegattaName()));
return;
}
final boolean showChartMarkEditMediaButtonsAndVideo = !DeviceDetector.isMobile();
final StoredSettingsLocation storageDefinition = StoredSettingsLocationFactory
.createStoredSettingsLocatorForRaceBoard(raceboardContextDefinition,
finalMode != null ? finalMode.name() : null);
// TODO bug2822: also determine regatta's boat change parameter and parameterize Leaderboard settings
// --> show boat info column yes/no?
sailingService.determineDetailTypesForCompetitorChart(
getSailingService().determineDetailTypesForCompetitorChart(
raceboardContextDefinition.getLeaderboardGroupName(),
raceboardData.getRace().getRaceIdentifier(), new AsyncCallback<Iterable<DetailType>>() {
@@ -114,7 +123,7 @@ public class RaceBoardEntryPoint extends AbstractSailingEntryPoint {
@Override
public void onSuccess(Iterable<DetailType> chartAllowedTypes) {
sailingService.getAvailableDetailTypesForLeaderboard(
getSailingService().getAvailableDetailTypesForLeaderboard(
raceboardContextDefinition.getLeaderboardName(),
raceboardData.getRace().getRaceIdentifier(), new AsyncCallback<Iterable<DetailType>>() {
@Override
@@ -152,13 +161,13 @@ public class RaceBoardEntryPoint extends AbstractSailingEntryPoint {
}
});
}
@Override
public void onFailure(Throwable caught) {
reportError("Error trying to create the raceboard: " + caught.getMessage());
}
};
sailingService.getRaceboardData(raceboardContextDefinition.getRegattaName(),
getSailingService().getRaceboardData(raceboardContextDefinition.getRegattaName(),
raceboardContextDefinition.getRaceName(), raceboardContextDefinition.getLeaderboardName(),
raceboardContextDefinition.getLeaderboardGroupName(), raceboardContextDefinition.getEventId(),
asyncCallback);
@@ -185,10 +194,10 @@ public class RaceBoardEntryPoint extends AbstractSailingEntryPoint {
selectedRace = raceboardData.getRace();
Window.setTitle(selectedRace.getName());
AsyncActionsExecutor asyncActionsExecutor = new AsyncActionsExecutor();
RaceTimesInfoProvider raceTimesInfoProvider = new RaceTimesInfoProvider(sailingService, asyncActionsExecutor, this,
RaceTimesInfoProvider raceTimesInfoProvider = new RaceTimesInfoProvider(getSailingService(), asyncActionsExecutor, this,
Collections.singletonList(selectedRace.getRaceIdentifier()), 5000l /* requestInterval*/);
RaceBoardPanel raceBoardPerspective = new RaceBoardPanel(parent, context, raceLifeCycle, settings,
sailingService, mediaService, getUserService(), asyncActionsExecutor,
getSailingService(), mediaService, getUserService(), asyncActionsExecutor,
raceboardData.getCompetitorAndTheirBoats(), timer, selectedRace.getRaceIdentifier(),
raceboardContextDefinition.getLeaderboardName(), raceboardContextDefinition.getLeaderboardGroupName(),
raceboardContextDefinition.getEventId(), RaceBoardEntryPoint.this, getStringMessages(), userAgent,
@@ -196,4 +205,9 @@ public class RaceBoardEntryPoint extends AbstractSailingEntryPoint {
RootLayoutPanel.get().add(raceBoardPerspective.getEntryWidget());
return raceBoardPerspective;
}
}
@Override
public String getLeaderboardName() {
return leaderBoardName;
}
}
@@ -53,6 +53,10 @@ import java.util.stream.StreamSupport;
import java.util.zip.GZIPInputStream;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import org.apache.http.client.ClientProtocolException;
import org.apache.shiro.SecurityUtils;
@@ -278,6 +282,7 @@ import com.sap.sailing.domain.common.racelog.tracking.RaceLogTrackingState;
import com.sap.sailing.domain.common.racelog.tracking.TransformationException;
import com.sap.sailing.domain.common.security.Permission;
import com.sap.sailing.domain.common.security.Permission.Mode;
import com.sap.sailing.domain.common.sharding.ShardingType;
import com.sap.sailing.domain.common.tracking.BravoFix;
import com.sap.sailing.domain.common.tracking.GPSFix;
import com.sap.sailing.domain.common.tracking.GPSFixMoving;
@@ -318,6 +323,7 @@ import com.sap.sailing.domain.regattalike.HasRegattaLike;
import com.sap.sailing.domain.regattalike.IsRegattaLike;
import com.sap.sailing.domain.regattalike.LeaderboardThatHasRegattaLike;
import com.sap.sailing.domain.regattalog.RegattaLogStore;
import com.sap.sailing.domain.sharding.ShardingContext;
import com.sap.sailing.domain.swisstimingadapter.StartList;
import com.sap.sailing.domain.swisstimingadapter.SwissTimingAdapter;
import com.sap.sailing.domain.swisstimingadapter.SwissTimingAdapterFactory;
@@ -2539,6 +2545,20 @@ public class SailingServiceImpl extends ProxiedRemoteServiceServlet implements S
}
return results;
}
private void checkLeaderboardRouting(String leaderboardName) {
final String currentRequestUrl = getThreadLocalRequest().getRequestURL().toString();
if (!currentRequestUrl.contains("/leaderboard/")) {
logger.log(Level.WARNING, "Leaderboard routing stacktrace", new RuntimeException("Request without leaderboard routing information"));
} else {
if (currentRequestUrl.contains(leaderboardName)) {
logger.info("leaderboard access matches leaderboard url");
} else {
logger.info("leaderboard access to " + leaderboardName + " does not match request url " + currentRequestUrl);
logger.log(Level.SEVERE, "Leaderboard routing stacktrace", new RuntimeException("Request without leaderboard routing information"));
}
}
}
/**
* Creates a {@link LeaderboardDTO} for <code>leaderboard</code> and fills in the name, race master data
@@ -2549,6 +2569,8 @@ public class SailingServiceImpl extends ProxiedRemoteServiceServlet implements S
* If <code>withGeoLocationData</code> is <code>true</code> the geographical location of all races will be determined.
*/
private StrippedLeaderboardDTO createStrippedLeaderboardDTO(Leaderboard leaderboard, boolean withGeoLocationData, boolean withStatisticalData) {
checkLeaderboardRouting(leaderboard.getName());
StrippedLeaderboardDTO leaderboardDTO = new StrippedLeaderboardDTO(convertToBoatClassDTO(leaderboard.getBoatClass()));
TimePoint startOfLatestRace = null;
Long delayToLiveInMillisForLatestRace = null;
@@ -7851,4 +7873,19 @@ public class SailingServiceImpl extends ProxiedRemoteServiceServlet implements S
}
return result;
}
@Override
public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException {
ShardingType identifiedShardingType = null;
try {
if (req instanceof HttpServletRequest) {
identifiedShardingType = ShardingContext.identifyAndSetShardingConstraint(((HttpServletRequest) req).getPathInfo());
}
super.service(req, res);
} finally {
if (identifiedShardingType != null) {
ShardingContext.clearShardingConstraint(identifiedShardingType);
}
}
}
}
@@ -38,7 +38,7 @@ public class SpectatorEntryPoint extends AbstractSailingEntryPoint implements Re
} else {
groupName = groupParamValue;
Window.setTitle(groupName);
sailingService.getLeaderboardGroupByName(groupName, false /*withGeoLocationData*/, new AsyncCallback<LeaderboardGroupDTO>() {
getSailingService().getLeaderboardGroupByName(groupName, false /*withGeoLocationData*/, new AsyncCallback<LeaderboardGroupDTO>() {
@Override
public void onFailure(Throwable t) {
reportError(getStringMessages().noLeaderboardGroupWithNameFound(groupName));
@@ -58,11 +58,11 @@ public class SpectatorEntryPoint extends AbstractSailingEntryPoint implements Re
// DON'T DELETE -> the EventOverviewPanel will replace the LeaderboardGroupOverviewPanel later on
// EventOverviewPanel eventOverviewPanel = new EventOverviewPanel(sailingService, this, stringMessages, showRaceDetails);
// groupOverviewPanel.add( eventOverviewPanel);
LeaderboardGroupOverviewPanel leaderboardGroupOverviewPanel = new LeaderboardGroupOverviewPanel(sailingService, this, getStringMessages(), settings.isShowRaceDetails());
LeaderboardGroupOverviewPanel leaderboardGroupOverviewPanel = new LeaderboardGroupOverviewPanel(getSailingService(), this, getStringMessages(), settings.isShowRaceDetails());
groupOverviewPanel.add(leaderboardGroupOverviewPanel);
rootPanel.add(groupOverviewPanel);
} else {
LeaderboardGroupPanel groupPanel = new LeaderboardGroupPanel(sailingService, getStringMessages(), this,
LeaderboardGroupPanel groupPanel = new LeaderboardGroupPanel(getSailingService(), getStringMessages(), this,
groupName, settings.getViewMode(), embedded, settings.isShowRaceDetails(), settings.isCanReplayDuringLiveRaces(),
settings.isShowMapControls());
groupAndFeedbackPanel.add(groupPanel);
@@ -0,0 +1,19 @@
package com.sap.sailing.server.util;
import org.junit.Test;
import com.sap.sailing.domain.common.sharding.ShardingType;
import junit.framework.Assert;
public class ShardingLeaderBoardEncodingTest {
@Test
public void testEncoding() {
Assert.assertEquals("/leaderboard/pureascistring", ShardingType.LEADERBOARDNAME.encodeIfNeeded("pureascistring"));
Assert.assertEquals("/leaderboard/unpure_asci_string", ShardingType.LEADERBOARDNAME.encodeIfNeeded("unpure asci string"));
Assert.assertEquals("/leaderboard/c_dille", ShardingType.LEADERBOARDNAME.encodeIfNeeded("cédille"));
Assert.assertEquals("/leaderboard/Hello_World", ShardingType.LEADERBOARDNAME.encodeIfNeeded("Hello+World"));
Assert.assertEquals("/leaderboard/Hello_World_", ShardingType.LEADERBOARDNAME.encodeIfNeeded("Hello(World)"));
}
}
@@ -29,6 +29,17 @@
This can be done from the adminconsole->tracked races->audio & videos tab</li>
<li>In raceboard when you edit a video you do not need to explicitly press "Preview" before saving anymore.
Saving now implicitly applies the changes.</li>
<li>The URLs of our GWT services are extended to include a leaderboard name if a call is context sensitive to a specific leaderboard.
This does not affect the functionality of any service but allows us to setup load balancing with leaderboard specific routing.
The leaderboard names put into the URL are cleaned: Any character that isn't a letter or digit is replaced with an underscore character.
Currently, the following leaderboard specific URLs are used:
<ul>
<li>/gwt/service/sailing/leaderboard/[CLEANED-LEADERBOARD-NAME]</li>
<li>/gwt/service/dispatch/leaderboard/[CLEANED-LEADERBOARD-NAME]</li>
</ul>
Be aware that request without leaderboard suffix may be sent from pages that do not show leaderboard specific contents.
Due to this it is required to define a fallback rule for any unqualified request.
</li>
</ul>
<h2 class="articleSubheadline">May 2018</h2>
@@ -57,6 +57,7 @@ Export-Package: com.google.gwt.user.client.rpc.core.java.util,
com.sap.sse.gwt.dispatch.client.system,
com.sap.sse.gwt.dispatch.client.system.batching,
com.sap.sse.gwt.dispatch.client.system.caching,
com.sap.sse.gwt.dispatch.client.system.routing,
com.sap.sse.gwt.dispatch.client.transport.gwtrpc,
com.sap.sse.gwt.dispatch.servlets,
com.sap.sse.gwt.dispatch.shared.caching,
@@ -0,0 +1,12 @@
package com.sap.sse.gwt.client;
import com.sap.sse.gwt.dispatch.client.system.DispatchSystemDefaultImpl;
/**
* Interface used to append a routing suffix to target url
* in GWT RPC service instances and in {@link DispatchSystemDefaultImpl}
*/
public interface ServiceRoutingProvider {
String routingSuffixPath();
}
@@ -1,11 +1,14 @@
package com.sap.sse.gwt.dispatch.client.system;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;
import com.google.gwt.core.client.Scheduler;
import com.google.gwt.user.client.rpc.AsyncCallback;
import com.sap.sse.gwt.client.ServiceRoutingProvider;
import com.sap.sse.gwt.dispatch.client.system.batching.AutomaticBatchingDispatch;
import com.sap.sse.gwt.dispatch.client.system.caching.CachingDispatch;
import com.sap.sse.gwt.dispatch.client.transport.DefaultTransport;
@@ -27,8 +30,11 @@ public abstract class DispatchSystemDefaultImpl<CTX extends DispatchContext> imp
ProvidesServerTime {
private final Logger LOG = Logger.getLogger(DispatchSystemDefaultImpl.class.getName());
private final DefaultTransport<CTX> simpleDispatch;
private final DispatchSystemAsync<CTX> dispatch;
private final DispatchSystemAsync<CTX> defaultDispatch;
private final Map<String,DispatchSystemAsync<CTX>> routingRegistry = new HashMap<>();
private final boolean processResultsScheduled;
private final String dispatchRPCPath;
public DispatchSystemDefaultImpl(String dispatchRPCPath) {
this(dispatchRPCPath, false);
}
@@ -43,10 +49,25 @@ public abstract class DispatchSystemDefaultImpl<CTX extends DispatchContext> imp
* use a {@link Scheduler} to process the results
*/
public DispatchSystemDefaultImpl(String dispatchRPCPath, boolean processResultsScheduled) {
this.dispatchRPCPath = dispatchRPCPath;
this.processResultsScheduled = processResultsScheduled;
simpleDispatch = new DefaultTransport<CTX>(dispatchRPCPath);
dispatch = new CachingDispatch<CTX>(new AutomaticBatchingDispatch<CTX>(
simpleDispatch, processResultsScheduled));
LOG.finest("Started dispatch system for " + dispatchRPCPath);
defaultDispatch = new CachingDispatch<CTX>(new AutomaticBatchingDispatch<CTX>(simpleDispatch, processResultsScheduled));
LOG.finest("Started default dispatch system for " + dispatchRPCPath);
}
private DispatchSystemAsync<CTX> createDispatchFor(String routing) {
final StringBuilder destinationUrlBuilder = new StringBuilder(dispatchRPCPath);
if (routing != null && !routing.isEmpty()) {
if (!dispatchRPCPath.endsWith("/")) {
destinationUrlBuilder.append("/");
}
destinationUrlBuilder.append(routing.startsWith("/") ? routing.substring(1) : routing);
}
DefaultTransport<CTX> transport = new DefaultTransport<CTX>(destinationUrlBuilder.toString());
DispatchSystemAsync<CTX> dispatch = new CachingDispatch<CTX>(new AutomaticBatchingDispatch<CTX>(
transport, processResultsScheduled));
return dispatch;
}
@Override
@@ -66,7 +87,19 @@ public abstract class DispatchSystemDefaultImpl<CTX extends DispatchContext> imp
callback.onSuccess(result);
}
};
dispatch.execute(action, wrappedCallback);
final DispatchSystemAsync<CTX> dispatchToUse;
if (action instanceof ServiceRoutingProvider) {
ServiceRoutingProvider providesDispatchRoutingKey = (ServiceRoutingProvider) action;
String routingPath = providesDispatchRoutingKey.routingSuffixPath();
dispatchToUse = routingRegistry.computeIfAbsent(routingPath, this::createDispatchFor);
LOG.fine("Using routed dispatch for path "+ routingPath);
} else {
LOG.fine("Using default dispatch for "+ action.getClass().getName());
dispatchToUse = defaultDispatch;
}
dispatchToUse.execute(action, wrappedCallback);
}
@Override