diff --git a/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/RegattaAndRaceIdentifier.java b/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/RegattaAndRaceIdentifier.java index 960ae85b74e..92916be016d 100755 --- a/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/RegattaAndRaceIdentifier.java +++ b/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/RegattaAndRaceIdentifier.java @@ -4,6 +4,5 @@ import com.sap.sse.security.shared.TypeRelativeObjectIdentifier; import com.sap.sse.security.shared.WithQualifiedObjectIdentifier; public interface RegattaAndRaceIdentifier extends RegattaIdentifier, RaceIdentifier, WithQualifiedObjectIdentifier { - TypeRelativeObjectIdentifier getTypeRelativeObjectIdentifier(); } diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/server/SailingServiceImpl.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/server/SailingServiceImpl.java index da4a75d772f..e6cd9f0b7b7 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/server/SailingServiceImpl.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/server/SailingServiceImpl.java @@ -1833,7 +1833,6 @@ public class SailingServiceImpl extends ResultCachingProxiedRemoteServiceServlet .hasCurrentUserAnyPermission(SecuredDomainType.SIMULATOR.getPermission(DefaultActions.READ))) { throw new UnauthorizedException("Not permitted to see simulator results."); } - // get simulation-results from smart-future-cached simulation-service SimulatorResultsDTO result = null; SimulationService simulationService = getService().getSimulationService(); diff --git a/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/jaxrs/api/AbstractLeaderboardsResource.java b/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/jaxrs/api/AbstractLeaderboardsResource.java index 03bea35290e..7c31c0f26eb 100644 --- a/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/jaxrs/api/AbstractLeaderboardsResource.java +++ b/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/jaxrs/api/AbstractLeaderboardsResource.java @@ -196,15 +196,19 @@ public abstract class AbstractLeaderboardsResource extends AbstractSailingServer protected abstract JSONObject getLeaderboardJson(Leaderboard leaderboard, TimePoint resultTimePoint, ResultStates resultState, Integer maxCompetitorsCount, List raceColumnNames, - List raceDetailNames, boolean competitorAndBoatIdsOnly) throws NoWindException, InterruptedException, ExecutionException; + List raceDetailNames, boolean competitorAndBoatIdsOnly, + List showOnlyActiveRacesForCompetitorIds) + throws NoWindException, InterruptedException, ExecutionException; protected JSONObject getLeaderboardJson(ResultStates resultState, Integer maxCompetitorsCount, TimePoint requestTimePoint, Leaderboard leaderboard, TimePoint timePoint, List raceColumnNames, - List raceDetailNames, boolean competitorAndBoatIdsOnly) throws NoWindException, InterruptedException, ExecutionException { + List raceDetailNames, boolean competitorAndBoatIdsOnly, + List showOnlyActiveRacesForCompetitorIds) + throws NoWindException, InterruptedException, ExecutionException { final JSONObject jsonLeaderboard; if (timePoint != null || resultState == ResultStates.Live) { jsonLeaderboard = getLeaderboardJson(leaderboard, timePoint, resultState, maxCompetitorsCount, - raceColumnNames, raceDetailNames, competitorAndBoatIdsOnly); + raceColumnNames, raceDetailNames, competitorAndBoatIdsOnly, showOnlyActiveRacesForCompetitorIds); } else { jsonLeaderboard = createEmptyLeaderboardJson(leaderboard, resultState, maxCompetitorsCount); } diff --git a/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/jaxrs/api/LeaderboardsResource.java b/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/jaxrs/api/LeaderboardsResource.java index 8033c415bed..de365107ad7 100755 --- a/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/jaxrs/api/LeaderboardsResource.java +++ b/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/jaxrs/api/LeaderboardsResource.java @@ -200,7 +200,8 @@ public class LeaderboardsResource extends AbstractLeaderboardsResource { TimePoint timePoint = calculateTimePointForResultState(leaderboard, resultState); JSONObject jsonLeaderboard; jsonLeaderboard = getLeaderboardJson(resultState, maxCompetitorsCount, requestTimePoint, - leaderboard, timePoint, /* race column names */ null, /* race detail names */ null, competitorAndBoatIdsOnly); + leaderboard, timePoint, /* race column names */ null, /* race detail names */ null, competitorAndBoatIdsOnly, + /* showOnlyActiveRacesForCompetitorIds */ null); StringWriter sw = new StringWriter(); jsonLeaderboard.writeJSONString(sw); String json = sw.getBuffer().toString(); @@ -220,7 +221,7 @@ public class LeaderboardsResource extends AbstractLeaderboardsResource { @Override protected JSONObject getLeaderboardJson(Leaderboard leaderboard, TimePoint resultTimePoint, ResultStates resultState, Integer maxCompetitorsCount, List raceColumnNames, - List raceDetailNames, boolean competitorIdsOnly) + List raceDetailNames, boolean competitorIdsOnly, List showOnlyActiveRacesForCompetitorIds) throws NoWindException, InterruptedException, ExecutionException { LeaderboardDTO leaderboardDTO = leaderboard.getLeaderboardDTO( resultTimePoint, Collections. emptyList(), /* addOverallDetails */ diff --git a/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/jaxrs/api/LeaderboardsResourceV2.java b/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/jaxrs/api/LeaderboardsResourceV2.java index f7e91341b25..4d706ce9321 100644 --- a/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/jaxrs/api/LeaderboardsResourceV2.java +++ b/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/jaxrs/api/LeaderboardsResourceV2.java @@ -27,6 +27,7 @@ import org.apache.shiro.SecurityUtils; import org.json.simple.JSONArray; import org.json.simple.JSONObject; +import com.sap.sailing.domain.base.Competitor; import com.sap.sailing.domain.base.RaceColumn; import com.sap.sailing.domain.common.DetailType; import com.sap.sailing.domain.common.ManeuverType; @@ -46,6 +47,7 @@ import com.sap.sse.InvalidDateException; import com.sap.sse.common.Distance; import com.sap.sse.common.Duration; import com.sap.sse.common.TimePoint; +import com.sap.sse.common.Util; import com.sap.sse.common.Util.Pair; import com.sap.sse.security.shared.HasPermissions.DefaultActions; import com.sap.sse.security.shared.impl.SecuredSecurityTypes; @@ -63,7 +65,8 @@ public class LeaderboardsResourceV2 extends AbstractLeaderboardsResource { @QueryParam("time") String time, @QueryParam("timeasmillis") Long timeasmillis, @QueryParam("maxCompetitorsCount") Integer maxCompetitorsCount, @QueryParam("secret") String regattaSecret, - @DefaultValue("false") @QueryParam("competitorAndBoatIdsOnly") boolean competitorAndBoatIdsOnly) { + @DefaultValue("false") @QueryParam("competitorAndBoatIdsOnly") boolean competitorAndBoatIdsOnly, + @QueryParam("showOnlyActiveRacesForCompetitorIds") List showOnlyActiveRacesForCompetitorIds) { ShardingContext.setShardingConstraint(ShardingType.LEADERBOARDNAME, leaderboardName); try { Response response; @@ -87,7 +90,9 @@ public class LeaderboardsResourceV2 extends AbstractLeaderboardsResource { } JSONObject jsonLeaderboard; if (timePoint != null || resultState == ResultStates.Live) { - jsonLeaderboard = getLeaderboardJson(leaderboard, timePoint, resultState, maxCompetitorsCount, raceColumnNames, raceDetails, competitorAndBoatIdsOnly); + jsonLeaderboard = getLeaderboardJson(leaderboard, timePoint, resultState, maxCompetitorsCount, + raceColumnNames, raceDetails, competitorAndBoatIdsOnly, + showOnlyActiveRacesForCompetitorIds); } else { jsonLeaderboard = createEmptyLeaderboardJson(leaderboard, resultState, maxCompetitorsCount); } @@ -109,9 +114,9 @@ public class LeaderboardsResourceV2 extends AbstractLeaderboardsResource { @Override protected JSONObject getLeaderboardJson(Leaderboard leaderboard, TimePoint resultTimePoint, ResultStates resultState, Integer maxCompetitorsCount, - List raceColumnNames, List raceDetailNames, boolean competitorAndBoatIdsOnly) + List raceColumnNames, List raceDetailNames, boolean competitorAndBoatIdsOnly, List showOnlyActiveRacesForCompetitorIds) throws NoWindException, InterruptedException, ExecutionException { - List raceColumnsToShow = calculateRaceColumnsToShow(raceColumnNames, leaderboard.getRaceColumns()); + List raceColumnsToShow = calculateRaceColumnsToShow(leaderboard, raceColumnNames, showOnlyActiveRacesForCompetitorIds, resultTimePoint); List raceDetailsToShow = calculateRaceDetailTypesToShow(raceDetailNames); LeaderboardDTO leaderboardDTO = leaderboard.getLeaderboardDTO( resultTimePoint, raceColumnsToShow, /* addOverallDetails */ @@ -424,22 +429,80 @@ public class LeaderboardsResourceV2 extends AbstractLeaderboardsResource { } /** - * If {@code raceColumnNames} is empty or {@code null}, return the names of all {@link raceColumnsOfLeaderboard}; otherwise - * return those race column names from {@code raceColumnsOfLeaderboard} that are also in {@code raceColumnNames}. + * If {@code raceColumnNames} is empty or {@code null}, return the names of all {@link raceColumnsOfLeaderboard}; + * otherwise return those race column names from {@code raceColumnsOfLeaderboard} that are also in + * {@code raceColumnNames}. + * @param leaderboard TODO + * @param showOnlyActiveRacesForCompetitorIds + * {@code null}, or specifies zero or more competitor IDs, requesting that the result contained the race + * column holding that competitor's "active" race at the time requested; see also the + * {@code resultTimePoint} parameter. A race is active if it is currently live or is the last race for + * which the competitor has a result. In case multiple competitor IDs are given, all race columns that + * contain an active race of any of the competitors specified will be added to the result. It is possible + * that no such race is found, e.g., because racing has not started yet and the leaderboard is empty. No + * race column will be delivered then. In case the {@code raceColumnNames} parameter is used, too, the + * combined set of race columns from the columnNames parameter and this parameter will be delivered. + * @param resultTimePoint + * used together with {@code showOnlyActiveRacesForCompetitorIds} to determine which races are "active" + * for the competitors whose IDs are specified in {@link showOnlyActiveRacesForCompetitorIds} at that + * time */ - private List calculateRaceColumnsToShow(List raceColumnNames, Iterable raceColumnsOfLeaderboard) { + private List calculateRaceColumnsToShow(Leaderboard leaderboard, + List raceColumnNames, Iterable showOnlyActiveRacesForCompetitorIds, + TimePoint resultTimePoint) { final Set raceColumnNamesAsSet = new HashSet<>(); if (raceColumnNames != null) { raceColumnNamesAsSet.addAll(raceColumnNames); } + if (showOnlyActiveRacesForCompetitorIds != null) { + Util.addAll(getRaceColumnNamesOfActiveRaceColumnsForCompetitorIds(showOnlyActiveRacesForCompetitorIds, + leaderboard, resultTimePoint), raceColumnNamesAsSet); + } // Calculates the race columns to retrieve data for final List raceColumnsToShow = new ArrayList<>(); - for (final RaceColumn raceColumn : raceColumnsOfLeaderboard) { - if (raceColumnNamesAsSet.isEmpty() || raceColumnNamesAsSet.contains(raceColumn.getName())) { + for (final RaceColumn raceColumn : leaderboard.getRaceColumns()) { + // if showOnlyActiveRacesForCompetitorIds specifies at least one ID, don't default to delivering + // all columns, even if raceColumnNames is empty, but only show what resulted from finding the + // active races combined with columns explicitly specified in raceColumnNames. + if ((raceColumnNamesAsSet.isEmpty() && (showOnlyActiveRacesForCompetitorIds==null || Util.isEmpty(showOnlyActiveRacesForCompetitorIds))) + || raceColumnNamesAsSet.contains(raceColumn.getName())) { raceColumnsToShow.add(raceColumn.getName()); } } return raceColumnsToShow; } + private Iterable getRaceColumnNamesOfActiveRaceColumnsForCompetitorIds( + Iterable showOnlyActiveRacesForCompetitorIds, Leaderboard leaderboard, TimePoint timePoint) { + final Set result = new HashSet<>(); + for (final String showOnlyActiveRacesForCompetitorId : showOnlyActiveRacesForCompetitorIds) { + final String nameOfActiveRaceColumnForCompetitor = getNameOfActiveRaceColumnForCompetitor(showOnlyActiveRacesForCompetitorId, leaderboard, timePoint); + if (nameOfActiveRaceColumnForCompetitor != null) { + result.add(nameOfActiveRaceColumnForCompetitor); + } + } + return result; + } + + private String getNameOfActiveRaceColumnForCompetitor(String showOnlyActiveRacesForCompetitorId, Leaderboard leaderboard, TimePoint timePoint) { + final String result; + final TimePoint timePointOrLiveTimeIfNull = timePoint != null ? timePoint : leaderboard.getNowMinusDelay(); + final Competitor competitor = leaderboard.getCompetitorByIdAsString(showOnlyActiveRacesForCompetitorId); + if (competitor != null) { + RaceColumn lastRaceColumnWithResultForCompetitorAtTimePoint = null; + for (final RaceColumn raceColumn : leaderboard.getRaceColumns()) { + if (leaderboard.getTotalPoints(competitor, raceColumn, timePointOrLiveTimeIfNull) != null) { + lastRaceColumnWithResultForCompetitorAtTimePoint = raceColumn; + } + } + if (lastRaceColumnWithResultForCompetitorAtTimePoint != null) { + result = lastRaceColumnWithResultForCompetitorAtTimePoint.getName(); + } else { + result = null; + } + } else { + result = null; + } + return result; + } } diff --git a/java/com.sap.sailing.server.gateway/webservices/api/v2/leaderboardGetDoc.html b/java/com.sap.sailing.server.gateway/webservices/api/v2/leaderboardGetDoc.html index ddd6ef186d5..696cd1044fa 100644 --- a/java/com.sap.sailing.server.gateway/webservices/api/v2/leaderboardGetDoc.html +++ b/java/com.sap.sailing.server.gateway/webservices/api/v2/leaderboardGetDoc.html @@ -46,7 +46,23 @@ There is also the 'ALL' shortcut constant which can be used to get all available   - columnNames [Default = all columns] + columnNames [Default = all columns or what showOnlyActiveRacesForCompetitorIds specifies] + + +   + +
showOnlyActiveRacesForCompetitorIds: specify a competitor ID, and the result will contain + the race column holding that competitor's "active" race at the time requested; see also the time and + timeasmillis parameters. A race is active if it is currently live or is the last race for which the + competitor has a result. The parameter can be specified multiple times, thus providing more than + one competitor ID. In case multiple competitor IDs are given, all race columns that contain an + active race of any of the competitors specified will be added to the result. It is possible that no such + race is found, e.g., because racing has not started yet and the leaderboard is empty. No race column + will be delivered then. In case the columnNames parameter is used, too, the combined set of + race columns from the columnNames parameter and this parameter will be delivered. If + this parameter is used but columnNames is not, only the columns specified by this parameter + will be delivered.
+