From daa8984498c0c0661149af504339ef22ec8a9396 Mon Sep 17 00:00:00 2001 From: gbq6 <24852447+gbq6@users.noreply.github.com.> Date: Sat, 18 Oct 2025 14:08:48 +0200 Subject: [PATCH 1/2] perf: Performance improvements --- .../internal/caching/impl/DataRouterImpl.java | 2 +- .../caching/impl/ci/CompetitorCiImpl.java | 4 +- .../entities/status/PeriodStatisticsImpl.java | 12 +++--- .../impl/markets/MarketMappingDataImpl.java | 2 +- .../impl/markets/NameExpressionHelper.java | 4 +- .../impl/markets/NameProviderImpl.java | 20 +++++----- .../impl/recovery/RecoveryManagerImpl.java | 29 +++++++------- .../java/com/sportradar/utils/SdkHelper.java | 38 +++++-------------- 8 files changed, 45 insertions(+), 66 deletions(-) diff --git a/sdk-core/src/main/java/com/sportradar/unifiedodds/sdk/internal/caching/impl/DataRouterImpl.java b/sdk-core/src/main/java/com/sportradar/unifiedodds/sdk/internal/caching/impl/DataRouterImpl.java index 68823e937..8e45685b0 100644 --- a/sdk-core/src/main/java/com/sportradar/unifiedodds/sdk/internal/caching/impl/DataRouterImpl.java +++ b/sdk-core/src/main/java/com/sportradar/unifiedodds/sdk/internal/caching/impl/DataRouterImpl.java @@ -591,7 +591,7 @@ private Map provideHomeAway(SapiSportEvent se) { return null; } - Map result = new HashMap<>(2); + Map result = new EnumMap<>(HomeAway.class); result.put(HomeAway.Home, home.getId()); result.put(HomeAway.Away, away.getId()); diff --git a/sdk-core/src/main/java/com/sportradar/unifiedodds/sdk/internal/caching/impl/ci/CompetitorCiImpl.java b/sdk-core/src/main/java/com/sportradar/unifiedodds/sdk/internal/caching/impl/ci/CompetitorCiImpl.java index bc0ac361b..706f19f96 100644 --- a/sdk-core/src/main/java/com/sportradar/unifiedodds/sdk/internal/caching/impl/ci/CompetitorCiImpl.java +++ b/sdk-core/src/main/java/com/sportradar/unifiedodds/sdk/internal/caching/impl/ci/CompetitorCiImpl.java @@ -195,7 +195,7 @@ class CompetitorCiImpl implements CompetitorCi, ExportableCacheItem { ) { this(id, dataRouterManager, defaultLocale, exceptionHandlingStrategy); if (data != null && data.getPlayers() != null && !data.getPlayers().getPlayer().isEmpty()) { - this.lastTimeCompetitorProfileIsFetched = Calendar.getInstance().getTime(); + this.lastTimeCompetitorProfileIsFetched = new Date(); if (cultureCompetitorProfileFetched == null) { this.cultureCompetitorProfileFetched = Collections.synchronizedList(new ArrayList<>()); } @@ -215,7 +215,7 @@ class CompetitorCiImpl implements CompetitorCi, ExportableCacheItem { ) { this(id, dataRouterManager, defaultLocale, exceptionHandlingStrategy); if (data != null && data.getPlayers() != null && !data.getPlayers().getPlayer().isEmpty()) { - this.lastTimeCompetitorProfileIsFetched = Calendar.getInstance().getTime(); + this.lastTimeCompetitorProfileIsFetched = new Date(); if (cultureCompetitorProfileFetched == null) { this.cultureCompetitorProfileFetched = Collections.synchronizedList(new ArrayList<>()); } diff --git a/sdk-core/src/main/java/com/sportradar/unifiedodds/sdk/internal/impl/entities/status/PeriodStatisticsImpl.java b/sdk-core/src/main/java/com/sportradar/unifiedodds/sdk/internal/impl/entities/status/PeriodStatisticsImpl.java index f2d80018b..ef05eae9d 100644 --- a/sdk-core/src/main/java/com/sportradar/unifiedodds/sdk/internal/impl/entities/status/PeriodStatisticsImpl.java +++ b/sdk-core/src/main/java/com/sportradar/unifiedodds/sdk/internal/impl/entities/status/PeriodStatisticsImpl.java @@ -55,13 +55,11 @@ public String toString() { return "PeriodStatisticsImpl{}"; } - String teamStatisticsResult = ""; - for (TeamStatisticsDto teamStatistics : stats.getTeamStatisticDtos()) { - teamStatisticsResult += " | " + teamStatistics.toString(); - } - if (teamStatisticsResult.length() > 3) { - teamStatisticsResult = teamStatisticsResult.substring(3); - } + String teamStatisticsResult = stats + .getTeamStatisticDtos() + .stream() + .map(TeamStatisticsDto::toString) + .collect(Collectors.joining(" | ")); return ( "PeriodStatisticsImpl{" + diff --git a/sdk-core/src/main/java/com/sportradar/unifiedodds/sdk/internal/impl/markets/MarketMappingDataImpl.java b/sdk-core/src/main/java/com/sportradar/unifiedodds/sdk/internal/impl/markets/MarketMappingDataImpl.java index d2e55c2f7..9b56f5885 100644 --- a/sdk-core/src/main/java/com/sportradar/unifiedodds/sdk/internal/impl/markets/MarketMappingDataImpl.java +++ b/sdk-core/src/main/java/com/sportradar/unifiedodds/sdk/internal/impl/markets/MarketMappingDataImpl.java @@ -84,7 +84,7 @@ public Urn getSportId() { public String getMarketId() { StringBuilder sb = new StringBuilder(String.valueOf(marketTypeId)); if (marketSubTypeId != null) { - sb.append(":").append(getMarketSubTypeId()); + sb.append(':').append(getMarketSubTypeId()); } return sb.toString(); } diff --git a/sdk-core/src/main/java/com/sportradar/unifiedodds/sdk/internal/impl/markets/NameExpressionHelper.java b/sdk-core/src/main/java/com/sportradar/unifiedodds/sdk/internal/impl/markets/NameExpressionHelper.java index 73a61563f..f6f7d9aae 100644 --- a/sdk-core/src/main/java/com/sportradar/unifiedodds/sdk/internal/impl/markets/NameExpressionHelper.java +++ b/sdk-core/src/main/java/com/sportradar/unifiedodds/sdk/internal/impl/markets/NameExpressionHelper.java @@ -27,8 +27,8 @@ static AbstractMap.SimpleImmutableEntry> parseDescriptor(St List expressions = new ArrayList<>(); for (int currentIndex = 0; currentIndex < descriptor.length(); currentIndex++) { - int startIndex = descriptor.indexOf("{", currentIndex); - int endIndex = descriptor.indexOf("}", currentIndex); + int startIndex = descriptor.indexOf('{', currentIndex); + int endIndex = descriptor.indexOf('}', currentIndex); if (startIndex < 0 && endIndex < 0) { break; diff --git a/sdk-core/src/main/java/com/sportradar/unifiedodds/sdk/internal/impl/markets/NameProviderImpl.java b/sdk-core/src/main/java/com/sportradar/unifiedodds/sdk/internal/impl/markets/NameProviderImpl.java index 222499ecf..88adb61cf 100644 --- a/sdk-core/src/main/java/com/sportradar/unifiedodds/sdk/internal/impl/markets/NameProviderImpl.java +++ b/sdk-core/src/main/java/com/sportradar/unifiedodds/sdk/internal/impl/markets/NameProviderImpl.java @@ -604,9 +604,6 @@ static class StatusMessage { @Override public String toString() { - StringBuilder sb = new StringBuilder("An error occurred while generating the name for event=[") - .append(sportEvent) - .append("], market=["); String specifierString = marketSpecifiers == null ? "null" : marketSpecifiers @@ -614,19 +611,24 @@ public String toString() { .stream() .map(e -> "{" + e.getKey() + "}={" + e.getValue() + "}") .collect(Collectors.joining("|")); - sb.append(" MarketId=").append(marketId); - sb.append(" Specifiers=[").append(specifierString).append("]"); + + StringBuilder sb = new StringBuilder(200) + .append("An error occurred while generating the name for event=[") + .append(sportEvent) + .append("], market=[ MarketId=") + .append(marketId) + .append(" Specifiers=[") + .append(specifierString) + .append(']'); if (outcomeId != null) { sb.append(" OutcomeId=").append(outcomeId); } - sb.append("]"); - - sb.append(" Locale=").append(locales); + sb.append("] Locale=").append(locales); if (outcomeName != null) { - sb.append(" Retrieved nameDescriptor=[").append(outcomeName).append("]"); + sb.append(" Retrieved nameDescriptor=[").append(outcomeName).append(']'); } sb.append("]. Additional message: ").append(message); diff --git a/sdk-core/src/main/java/com/sportradar/unifiedodds/sdk/internal/impl/recovery/RecoveryManagerImpl.java b/sdk-core/src/main/java/com/sportradar/unifiedodds/sdk/internal/impl/recovery/RecoveryManagerImpl.java index f01e58626..c14bbe327 100644 --- a/sdk-core/src/main/java/com/sportradar/unifiedodds/sdk/internal/impl/recovery/RecoveryManagerImpl.java +++ b/sdk-core/src/main/java/com/sportradar/unifiedodds/sdk/internal/impl/recovery/RecoveryManagerImpl.java @@ -405,9 +405,10 @@ public void handleRecovery(Recoverable recoverable) { MDC.setContextMap(sdkMdcContextDescription); long now = timeUtils.now(); - StringBuilder notificationString = new StringBuilder( - "Connection reestablished. Last valid producers alive(w\\s=1 && producer up) messages received: " - ); + StringBuilder notificationString = new StringBuilder(200) + .append( + "Connection reestablished. Last valid producers alive(w\\s=1 && producer up) messages received: " + ); for (ProducerInfo pi : perProducerInfo.values()) { if (pi.isDisabled()) continue; @@ -418,7 +419,7 @@ public void handleRecovery(Recoverable recoverable) { } else { secondsAgo = -99; } - notificationString.append("(").append(pi).append(":").append(secondsAgo).append(")"); + notificationString.append('(').append(pi).append(':').append(secondsAgo).append(')'); } notificationString.append( " seconds ago. Recovery will be initiated when the Alive messages start to process." @@ -668,19 +669,19 @@ private static void updateLogStringBuilders( ) { long systemInactivityInterval = now - pi.getLastSystemAliveReceivedTimestamp(); heartBeatBuilder - .append("(") + .append('(') .append(pi) - .append(":") + .append(':') .append(systemInactivityInterval / 1000) - .append(")"); + .append(')'); - statusBuilder.append("(").append(pi); + statusBuilder.append('(').append(pi); long lastMessageReceivedAgo = 0; if (pi.getLastMessageReceivedTimestamp() != 0) { lastMessageReceivedAgo = TimeUnit.SECONDS.convert(now - pi.getLastMessageReceivedTimestamp(), TimeUnit.MILLISECONDS); } - statusBuilder.append(":").append(lastMessageReceivedAgo); + statusBuilder.append(':').append(lastMessageReceivedAgo); long lastMessageProcessingDelay = 0; if (pi.getLastProcessedMessageGenTimestamp() != 0) { @@ -690,9 +691,7 @@ private static void updateLogStringBuilders( TimeUnit.MILLISECONDS ); } - statusBuilder.append(":").append(lastMessageProcessingDelay); - - statusBuilder.append(":"); + statusBuilder.append(':').append(lastMessageProcessingDelay).append(':'); if (!pi.isFlaggedDown()) { statusBuilder.append("UP"); } else { @@ -707,7 +706,7 @@ private static void updateLogStringBuilders( } statusBuilder.append(", RecoveryState=").append(pi.getRecoveryState()); } - statusBuilder.append(")"); + statusBuilder.append(')'); } private void performProducerRecovery(ProducerInfo pi) { @@ -1245,11 +1244,11 @@ private String createInitiateRecoveryUrl() { reqBuilder.append("recovery/initiate_request?"); if (fromTimestamp != 0) { - reqBuilder.append("after=").append(fromTimestamp).append("&"); + reqBuilder.append("after=").append(fromTimestamp).append('&'); } if (config.getSdkNodeId() != null) { - reqBuilder.append("node_id=").append(config.getSdkNodeId()).append("&"); + reqBuilder.append("node_id=").append(config.getSdkNodeId()).append('&'); } reqBuilder.append("request_id=").append(recoveryId); diff --git a/sdk-core/src/main/java/com/sportradar/utils/SdkHelper.java b/sdk-core/src/main/java/com/sportradar/utils/SdkHelper.java index 8d228e588..1697cda6f 100644 --- a/sdk-core/src/main/java/com/sportradar/utils/SdkHelper.java +++ b/sdk-core/src/main/java/com/sportradar/utils/SdkHelper.java @@ -304,66 +304,46 @@ public static String stringSetToString(Set set) { if (set == null || set.isEmpty()) { return null; } - String result = ""; - for (String key : set) { - result += "," + key; - } - if (result.length() > 1) { - result = result.substring(1); - } - return result; + return String.join(",", set); } public static String integerSetToString(Set set) { if (set == null || set.isEmpty()) { return null; } - String result = ""; - for (int key : set) { - result += "," + key; - } - if (result.length() > 1) { - result = result.substring(1); - } - return result; + return set.stream().map(String::valueOf).collect(Collectors.joining(",")); } public static String dictionaryToString(Map dict) { if (dict == null || dict.isEmpty()) { return null; } - String result = null; - for (String key : dict.keySet()) { - result += "," + key + "=" + dict.get(key); + StringBuilder result = new StringBuilder(); + for (Map.Entry entry : dict.entrySet()) { + result.append(',').append(entry.getKey()).append('=').append(entry.getValue()); } - return result; + return result.toString(); } public static String specifierListToString(List specifiers) { if (specifiers == null || specifiers.isEmpty()) { return null; } - String result = specifiers - .stream() - .map(n -> String.valueOf(n)) - .collect(Collectors.joining("|", "{", "}")); - return result; + return specifiers.stream().map(String::valueOf).collect(Collectors.joining("|", "{", "}")); } public static String specifierKeyListToString(List specifiers) { if (specifiers == null || specifiers.isEmpty()) { return null; } - String result = specifiers.stream().map(n -> n.getName()).collect(Collectors.joining("|", "{", "}")); - return result; + return specifiers.stream().map(Specifier::getName).collect(Collectors.joining("|", "{", "}")); } public static String localeListToString(List locales) { if (locales == null || locales.isEmpty()) { return null; } - String result = locales.stream().map(Locale::getLanguage).collect(Collectors.joining(", ")); - return result; + return locales.stream().map(Locale::getLanguage).collect(Collectors.joining(", ")); } public static boolean checkCauseReason(Throwable cause, String message) { From ab0a66e270e46f6ad2fca762c3f3ac9dacbec50e Mon Sep 17 00:00:00 2001 From: gbq6 <24852447+gbq6@users.noreply.github.com.> Date: Sat, 18 Oct 2025 21:54:26 +0200 Subject: [PATCH 2/2] Extracted comparator --- .../unifiedodds/sdk/entities/Change.java | 27 +++++++++++++++++++ .../sdk/entities/FixtureChange.java | 19 +------------ .../sdk/entities/ResultChange.java | 19 +------------ .../internal/impl/EventChangeManagerImpl.java | 16 +++++------ 4 files changed, 35 insertions(+), 46 deletions(-) create mode 100644 sdk-core/src/main/java/com/sportradar/unifiedodds/sdk/entities/Change.java diff --git a/sdk-core/src/main/java/com/sportradar/unifiedodds/sdk/entities/Change.java b/sdk-core/src/main/java/com/sportradar/unifiedodds/sdk/entities/Change.java new file mode 100644 index 000000000..c8a8ced8a --- /dev/null +++ b/sdk-core/src/main/java/com/sportradar/unifiedodds/sdk/entities/Change.java @@ -0,0 +1,27 @@ +/* + * Copyright (C) Sportradar AG. See LICENSE for full license governing this code + */ + +package com.sportradar.unifiedodds.sdk.entities; + +import com.sportradar.utils.Urn; +import java.util.Date; + +/** + * Defines methods used to access data of a change + */ +public interface Change { + /** + * Returns the {@link Urn} instance specifying the sport event + * + * @return - the {@link Urn} instance specifying the sport event + */ + Urn getSportEventId(); + + /** + * Returns the {@link Date} instance specifying the last update time + * + * @return - the {@link Date} instance specifying the last update time + */ + Date getUpdateTime(); +} diff --git a/sdk-core/src/main/java/com/sportradar/unifiedodds/sdk/entities/FixtureChange.java b/sdk-core/src/main/java/com/sportradar/unifiedodds/sdk/entities/FixtureChange.java index 92d395b25..3a7c6f51b 100644 --- a/sdk-core/src/main/java/com/sportradar/unifiedodds/sdk/entities/FixtureChange.java +++ b/sdk-core/src/main/java/com/sportradar/unifiedodds/sdk/entities/FixtureChange.java @@ -4,24 +4,7 @@ package com.sportradar.unifiedodds.sdk.entities; -import com.sportradar.utils.Urn; -import java.util.Date; - /** * Defines methods used to access data of a fixture change */ -public interface FixtureChange { - /** - * Returns the {@link Urn} instance specifying the sport event - * - * @return - the {@link Urn} instance specifying the sport event - */ - Urn getSportEventId(); - - /** - * Returns the {@link Date} instance specifying the last update time - * - * @return - the {@link Date} instance specifying the last update time - */ - Date getUpdateTime(); -} +public interface FixtureChange extends Change {} diff --git a/sdk-core/src/main/java/com/sportradar/unifiedodds/sdk/entities/ResultChange.java b/sdk-core/src/main/java/com/sportradar/unifiedodds/sdk/entities/ResultChange.java index 9d4c4334b..74bea2244 100644 --- a/sdk-core/src/main/java/com/sportradar/unifiedodds/sdk/entities/ResultChange.java +++ b/sdk-core/src/main/java/com/sportradar/unifiedodds/sdk/entities/ResultChange.java @@ -4,24 +4,7 @@ package com.sportradar.unifiedodds.sdk.entities; -import com.sportradar.utils.Urn; -import java.util.Date; - /** * Defines methods used to access data of a result change */ -public interface ResultChange { - /** - * Returns the {@link Urn} instance specifying the sport event - * - * @return - the {@link Urn} instance specifying the sport event - */ - Urn getSportEventId(); - - /** - * Returns the {@link Date} instance specifying the last update time - * - * @return - the {@link Date} instance specifying the last update time - */ - Date getUpdateTime(); -} +public interface ResultChange extends Change {} diff --git a/sdk-core/src/main/java/com/sportradar/unifiedodds/sdk/internal/impl/EventChangeManagerImpl.java b/sdk-core/src/main/java/com/sportradar/unifiedodds/sdk/internal/impl/EventChangeManagerImpl.java index 198bd327a..077b60a2c 100644 --- a/sdk-core/src/main/java/com/sportradar/unifiedodds/sdk/internal/impl/EventChangeManagerImpl.java +++ b/sdk-core/src/main/java/com/sportradar/unifiedodds/sdk/internal/impl/EventChangeManagerImpl.java @@ -4,6 +4,7 @@ import com.google.inject.Inject; import com.sportradar.unifiedodds.sdk.EventChangeListener; import com.sportradar.unifiedodds.sdk.LoggerDefinitions; +import com.sportradar.unifiedodds.sdk.entities.Change; import com.sportradar.unifiedodds.sdk.entities.FixtureChange; import com.sportradar.unifiedodds.sdk.entities.ResultChange; import com.sportradar.unifiedodds.sdk.entities.SportEvent; @@ -62,6 +63,9 @@ public EventUpdate(Urn id, Date updated, SportEvent sportEvent, boolean isFixtur private static final Logger clientInteractionLogger = LoggerFactory.getLogger( LoggerDefinitions.UfSdkClientInteractionLog.class ); + private static final Comparator BY_UPDATE_TIME = Comparator.comparing(change -> + change.getUpdateTime().getTime() + ); private final SdkInternalConfiguration configuration; private final SportDataProviderImpl sportDataProvider; private final SportEventCache sportEventCache; @@ -330,11 +334,7 @@ private void fetchFixtures() { } if (changes != null) { - changes = - changes - .stream() - .sorted(Comparator.comparing(c -> c.getUpdateTime().getTime())) - .collect(Collectors.toList()); + changes = changes.stream().sorted(BY_UPDATE_TIME).collect(Collectors.toList()); } for (FixtureChange fixtureChange : changes) { @@ -413,11 +413,7 @@ private void fetchResults() { } if (changes != null) { - changes = - changes - .stream() - .sorted(Comparator.comparing(c -> c.getUpdateTime().getTime())) - .collect(Collectors.toList()); + changes = changes.stream().sorted(BY_UPDATE_TIME).collect(Collectors.toList()); } for (ResultChange resultChange : changes) {