mirror of
https://github.com/eclipse-sailing-analytics/sailing-analytics.git
synced 2026-09-20 04:35:32 +00:00
Merge branch 'master' of ssh://sapsailing.com/home/trac/git
This commit is contained in:
+1
-1
@@ -33,7 +33,7 @@ import com.sap.sse.common.Util.Pair;
|
||||
* <p>
|
||||
*
|
||||
* Those carried wins are added to the
|
||||
* {@link #isWin(com.sap.sailing.domain.leaderboard.Leaderboard, com.sap.sailing.domain.base.Competitor, com.sap.sailing.domain.base.RaceColumn, com.sap.sse.common.TimePoint, com.sap.sailing.domain.tracking.WindLegTypeAndLegBearingAndORCPerformanceCurveCache, Function<Competitor, Double>)
|
||||
* {@link #isWin(Leaderboard, Competitor, RaceColumn, TimePoint, Function, WindLegTypeAndLegBearingAndORCPerformanceCurveCache)
|
||||
* wins} achieved in the medal series. More wins rank better. Equal numbers of races won make the score in the last race
|
||||
* in that series the first tie-breaker. Note that "last race" can be different races in case of multiple fleets in that
|
||||
* medal series, such as in a semi-final medal series split into fleets A and B. Should the tie not be resolved this
|
||||
|
||||
+3
@@ -26,6 +26,9 @@
|
||||
solved this issue.</li>
|
||||
<li>Data mining now offers administrators with the necessary permissions to analyze role, permission,
|
||||
session and subscription data for administrative purposes.</li>
|
||||
<li>The <tt>.../v2/leaderboards</tt> API now supports the <tt>LEG_AVERAGE_SPEED_OVER_GROUND_IN_KNOTS</tt> detail type,
|
||||
also included when specifying <tt>ALL</tt>. It produces the field <tt>currentLegAverageSpeedOverGround-kts</tt>
|
||||
in the <tt>data</tt> part of the result document.</li>
|
||||
</ul>
|
||||
<h5 class="articleSubheadline">January 2023</h5>
|
||||
<ul class="bulletList">
|
||||
|
||||
+34
-2
@@ -1,5 +1,6 @@
|
||||
package com.sap.sailing.landscape.ui.client;
|
||||
|
||||
import com.google.gwt.user.client.rpc.AsyncCallback;
|
||||
import com.google.gwt.user.client.ui.CheckBox;
|
||||
import com.google.gwt.user.client.ui.FocusWidget;
|
||||
import com.google.gwt.user.client.ui.Grid;
|
||||
@@ -11,6 +12,7 @@ import com.sap.sailing.landscape.common.SharedLandscapeConstants;
|
||||
import com.sap.sailing.landscape.ui.client.i18n.StringMessages;
|
||||
import com.sap.sse.common.Util;
|
||||
import com.sap.sse.gwt.client.ErrorReporter;
|
||||
import com.sap.sse.gwt.client.async.AsyncActionsExecutor;
|
||||
import com.sap.sse.gwt.client.controls.IntegerBox;
|
||||
import com.sap.sse.gwt.client.dialog.DataEntryDialog;
|
||||
|
||||
@@ -114,9 +116,39 @@ public class CreateApplicationReplicaSetDialog extends AbstractApplicationReplic
|
||||
|
||||
private static class Validator implements DataEntryDialog.Validator<CreateApplicationReplicaSetInstructions> {
|
||||
private final StringMessages stringMessages;
|
||||
private final LandscapeManagementWriteServiceAsync landscapeManagementService;
|
||||
|
||||
public Validator(StringMessages stringMessages) {
|
||||
public Validator(StringMessages stringMessages, LandscapeManagementWriteServiceAsync landscapeManagementService) {
|
||||
this.stringMessages = stringMessages;
|
||||
this.landscapeManagementService = landscapeManagementService;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void validate(CreateApplicationReplicaSetInstructions valueToValidate, AsyncCallback<String> callback,
|
||||
AsyncActionsExecutor validationExecutor) {
|
||||
// TODO Auto-generated method stub
|
||||
final String localErrorMessage = getErrorMessage(valueToValidate);
|
||||
if (localErrorMessage != null) {
|
||||
validationExecutor.execute(cb->cb.onSuccess(localErrorMessage), VALIDATION_ACTION_CATEGORY, callback);
|
||||
} else {
|
||||
// check availability of DNS name remotely:
|
||||
landscapeManagementService.hasDNSResourceRecordsForReplicaSet(valueToValidate.getName(), valueToValidate.getOptionalDomainName(),
|
||||
new AsyncCallback<Boolean>() {
|
||||
@Override
|
||||
public void onFailure(Throwable caught) {
|
||||
callback.onFailure(caught);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSuccess(Boolean hasDNSResourceRecordsForReplicaSet) {
|
||||
if (hasDNSResourceRecordsForReplicaSet) {
|
||||
callback.onSuccess(stringMessages.dnsNameAlreadyInUse());
|
||||
} else {
|
||||
callback.onSuccess(null); // no error
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -154,7 +186,7 @@ public class CreateApplicationReplicaSetDialog extends AbstractApplicationReplic
|
||||
boolean mayUseDynamicLoadBalancer) {
|
||||
super(stringMessages
|
||||
.createApplicationReplicaSet(), landscapeManagementService, releaseNames, stringMessages,
|
||||
errorReporter, new Validator(stringMessages), callback);
|
||||
errorReporter, new Validator(stringMessages, landscapeManagementService), callback);
|
||||
this.stringMessages = stringMessages;
|
||||
this.useExistingSharedMasterInstance = useExistingSharedMasterInstance;
|
||||
nameBox = createTextBox("", 40);
|
||||
|
||||
+2
@@ -160,4 +160,6 @@ public interface LandscapeManagementWriteService extends RemoteService {
|
||||
|
||||
void moveAllApplicationProcessesAwayFrom(AwsInstanceDTO host, String optionalInstanceTypeForNewInstance,
|
||||
String optionalKeyName, byte[] privateKeyEncryptionPassphrase) throws Exception;
|
||||
|
||||
boolean hasDNSResourceRecordsForReplicaSet(String replicaSetName, String optionalDomainName);
|
||||
}
|
||||
|
||||
+2
@@ -300,4 +300,6 @@ public interface LandscapeManagementWriteServiceAsync {
|
||||
*/
|
||||
void moveAllApplicationProcessesAwayFrom(AwsInstanceDTO host, String optionalInstanceTypeForNewInstance,
|
||||
String optionalKeyName, byte[] privateKeyEncryptionPassphrase, AsyncCallback<Void> callback);
|
||||
|
||||
void hasDNSResourceRecordsForReplicaSet(String replicaSetName, String optionalDomainName, AsyncCallback<Boolean> callback);
|
||||
}
|
||||
|
||||
+1
@@ -163,4 +163,5 @@ com.sap.sse.gwt.adminconsole.StringMessages {
|
||||
String moveTheFollowingMasterAndReplicaProcessesAway(String fromHostWithId, String masterProcesses, String replicaProcesses);
|
||||
String processOfReplicaSet(int portOfProcess, String replicaSetName);
|
||||
String successfullyMovedAllProcessesAwayFromHost(String hostname);
|
||||
String dnsNameAlreadyInUse();
|
||||
}
|
||||
|
||||
+2
-1
@@ -151,4 +151,5 @@ moveAllApplicationProcessesAwayFromMaster=Move all application processes away fr
|
||||
sameAsExistingHost=Same as existing host
|
||||
moveTheFollowingMasterAndReplicaProcessesAway=Moving master processes [{1}] and replica processes [{2}] from host with ID {0} to a new host.
|
||||
processOfReplicaSet=on port {0} (application replica set {1})
|
||||
successfullyMovedAllProcessesAwayFromHost=Successfully moved all processes away from host {0}
|
||||
successfullyMovedAllProcessesAwayFromHost=Successfully moved all processes away from host {0}
|
||||
dnsNameAlreadyInUse=DNS name already in use
|
||||
+2
-1
@@ -150,4 +150,5 @@ moveAllApplicationProcessesAwayFromMaster=Alle Anwendungs-Prozesse vom Master-Se
|
||||
sameAsExistingHost=Gleich wie beim bestehenden Server
|
||||
moveTheFollowingMasterAndReplicaProcessesAway=Verschieben der Master-Prozesse [{1}] und Replika-Prozesse [{2}] vom Server mit der Kennung {0} auf einen neuen Server
|
||||
processOfReplicaSet=auf Port {0} (Anwendungs-Cluster {1})
|
||||
successfullyMovedAllProcessesAwayFromHost=Alle Prozesse erfolgreich von Server {0} verschoben
|
||||
successfullyMovedAllProcessesAwayFromHost=Alle Prozesse erfolgreich von Server {0} verschoben
|
||||
dnsNameAlreadyInUse=DNS-Name wird bereits benutzt
|
||||
+11
@@ -110,6 +110,7 @@ import com.sap.sse.util.ThreadPoolUtil;
|
||||
import software.amazon.awssdk.services.ec2.model.AvailabilityZone;
|
||||
import software.amazon.awssdk.services.ec2.model.InstanceType;
|
||||
import software.amazon.awssdk.services.ec2.model.KeyPairInfo;
|
||||
import software.amazon.awssdk.services.route53.model.ResourceRecordSet;
|
||||
|
||||
public class LandscapeManagementWriteServiceImpl extends ResultCachingProxiedRemoteServiceServlet
|
||||
implements LandscapeManagementWriteService {
|
||||
@@ -950,4 +951,14 @@ public class LandscapeManagementWriteServiceImpl extends ResultCachingProxiedRem
|
||||
: InstanceType.valueOf(optionalInstanceTypeForNewInstance)),
|
||||
optionalKeyName, privateKeyEncryptionPassphrase);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasDNSResourceRecordsForReplicaSet(String replicaSetName, String optionalDomainName) {
|
||||
final AwsLandscape<String> landscape = getLandscape();
|
||||
final LandscapeService landscapeService = getLandscapeService();
|
||||
final String hostname = landscapeService.getHostname(replicaSetName, optionalDomainName);
|
||||
final Iterable<ResourceRecordSet> existingDNSRulesForHostname = landscape.getResourceRecordSets(hostname);
|
||||
// Failing early in case DNS record already exists (see also bug 5826):
|
||||
return existingDNSRulesForHostname != null && !Util.isEmpty(existingDNSRulesForHostname);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -449,4 +449,6 @@ public interface LandscapeService {
|
||||
moveAllApplicationProcessesAwayFrom(SailingAnalyticsHost<String> host,
|
||||
Optional<InstanceType> optionalInstanceTypeForNewInstance,
|
||||
String optionalKeyName, byte[] privateKeyEncryptionPassphrase) throws Exception;
|
||||
|
||||
String getHostname(String replicaSetName, String optionalDomainName);
|
||||
}
|
||||
|
||||
+21
-3
@@ -127,6 +127,7 @@ import software.amazon.awssdk.services.elasticloadbalancingv2.model.Listener;
|
||||
import software.amazon.awssdk.services.elasticloadbalancingv2.model.Rule;
|
||||
import software.amazon.awssdk.services.elasticloadbalancingv2.model.TargetHealthDescription;
|
||||
import software.amazon.awssdk.services.route53.model.RRType;
|
||||
import software.amazon.awssdk.services.route53.model.ResourceRecordSet;
|
||||
import software.amazon.awssdk.services.sts.model.Credentials;
|
||||
|
||||
public class LandscapeServiceImpl implements LandscapeService {
|
||||
@@ -168,6 +169,12 @@ public class LandscapeServiceImpl implements LandscapeService {
|
||||
Integer optionalMemoryTotalSizeFactorOrNull, Optional<Integer> minimumAutoScalingGroupSize,
|
||||
Optional<Integer> maximumAutoScalingGroupSize) throws Exception {
|
||||
final AwsLandscape<String> landscape = getLandscape();
|
||||
final String hostname = getHostname(name, optionalDomainName);
|
||||
final Iterable<ResourceRecordSet> existingDNSRulesForHostname = landscape.getResourceRecordSets(hostname);
|
||||
// Failing early in case DNS record already exists (see also bug 5826):
|
||||
if (existingDNSRulesForHostname != null && !Util.isEmpty(existingDNSRulesForHostname)) {
|
||||
throw new IllegalArgumentException("DNS record for "+hostname+" already exists");
|
||||
}
|
||||
final AwsRegion region = new AwsRegion(regionId, landscape);
|
||||
final Release release = getRelease(releaseNameOrNullForLatestMaster);
|
||||
final com.sap.sailing.landscape.procedures.SailingAnalyticsMasterConfiguration.Builder<?, String> masterConfigurationBuilder =
|
||||
@@ -217,7 +224,6 @@ public class LandscapeServiceImpl implements LandscapeService {
|
||||
});
|
||||
// if an unmanaged replica process was launched, return a replica set that contains it; otherwise use the one we already have (without any replica)
|
||||
return unmanagedReplica.map(ur->{
|
||||
|
||||
try {
|
||||
return getLandscape().getApplicationReplicaSet(region, name, master, Collections.singleton(ur));
|
||||
} catch (InterruptedException | ExecutionException | TimeoutException e) {
|
||||
@@ -318,6 +324,12 @@ public class LandscapeServiceImpl implements LandscapeService {
|
||||
Integer optionalMemoryTotalSizeFactorOrNull, Optional<InstanceType> optionalInstanceType,
|
||||
Optional<SailingAnalyticsHost<String>> optionalPreferredInstanceToDeployTo) throws Exception {
|
||||
final AwsLandscape<String> landscape = getLandscape();
|
||||
final String hostname = getHostname(replicaSetName, optionalDomainName);
|
||||
final Iterable<ResourceRecordSet> existingDNSRulesForHostname = landscape.getResourceRecordSets(hostname);
|
||||
// Failing early in case DNS record already exists (see also bug 5826):
|
||||
if (existingDNSRulesForHostname != null && !Util.isEmpty(existingDNSRulesForHostname)) {
|
||||
throw new IllegalArgumentException("DNS record for "+hostname+" already exists");
|
||||
}
|
||||
final Release release = getRelease(releaseNameOrNullForLatestMaster);
|
||||
final AppConfigBuilderT masterConfigurationBuilder = createMasterConfigurationBuilder(replicaSetName,
|
||||
masterReplicationBearerToken, optionalMemoryInMegabytesOrNull, optionalMemoryTotalSizeFactorOrNull,
|
||||
@@ -834,8 +846,7 @@ public class LandscapeServiceImpl implements LandscapeService {
|
||||
}
|
||||
final CreateLoadBalancerMapping.Builder<?, ?, String, SailingAnalyticsMetrics, SailingAnalyticsProcess<String>> createLoadBalancerMappingBuilder =
|
||||
dynamicLoadBalancerMapping ? CreateDynamicLoadBalancerMapping.builder() : CreateDNSBasedLoadBalancerMapping.builder();
|
||||
final String domainName = Optional.ofNullable(optionalDomainName).orElse(SharedLandscapeConstants.DEFAULT_DOMAIN_NAME);
|
||||
final String masterHostname = replicaSetName+"."+domainName;
|
||||
final String masterHostname = getHostname(replicaSetName, optionalDomainName);
|
||||
final CreateLoadBalancerMapping<String, SailingAnalyticsMetrics, SailingAnalyticsProcess<String>> createLoadBalancerMapping = createLoadBalancerMappingBuilder
|
||||
.setProcess(master)
|
||||
.setHostname(masterHostname)
|
||||
@@ -885,6 +896,13 @@ public class LandscapeServiceImpl implements LandscapeService {
|
||||
return applicationReplicaSet;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getHostname(String replicaSetName, String optionalDomainName) {
|
||||
final String domainName = Optional.ofNullable(optionalDomainName).orElse(SharedLandscapeConstants.DEFAULT_DOMAIN_NAME);
|
||||
final String masterHostname = replicaSetName+"."+domainName;
|
||||
return masterHostname;
|
||||
}
|
||||
|
||||
@Override
|
||||
public AwsApplicationReplicaSet<String, SailingAnalyticsMetrics, SailingAnalyticsProcess<String>> upgradeApplicationReplicaSet(AwsRegion region,
|
||||
AwsApplicationReplicaSet<String, SailingAnalyticsMetrics, SailingAnalyticsProcess<String>> replicaSet,
|
||||
|
||||
+7
@@ -320,6 +320,7 @@ public class LeaderboardsResourceV2 extends AbstractLeaderboardsResource {
|
||||
DetailType.LEG_WINDWARD_DISTANCE_TO_GO_IN_METERS,
|
||||
DetailType.LEG_CURRENT_ABSOLUTE_CROSS_TRACK_ERROR_IN_METERS,
|
||||
DetailType.LEG_CURRENT_SIGNED_CROSS_TRACK_ERROR_IN_METERS,
|
||||
DetailType.LEG_AVERAGE_SPEED_OVER_GROUND_IN_KNOTS,
|
||||
DetailType.OVERALL_TIME_ON_TIME_FACTOR,
|
||||
DetailType.OVERALL_TIME_ON_DISTANCE_ALLOWANCE_IN_SECONDS_PER_NAUTICAL_MILE };
|
||||
}
|
||||
@@ -463,6 +464,12 @@ public class LeaderboardsResourceV2 extends AbstractLeaderboardsResource {
|
||||
value = currentLegEntry.currentOrAverageSignedCrossTrackErrorInMeters;
|
||||
}
|
||||
break;
|
||||
case LEG_AVERAGE_SPEED_OVER_GROUND_IN_KNOTS:
|
||||
name = "currentLegAverageSpeedOverGround-kts";
|
||||
if (currentLegEntry != null && currentLegEntry.averageSpeedOverGroundInKnots != null) {
|
||||
value = currentLegEntry.averageSpeedOverGroundInKnots;
|
||||
}
|
||||
break;
|
||||
case OVERALL_TIME_ON_TIME_FACTOR:
|
||||
name = CompetitorJsonConstants.FIELD_TIME_ON_TIME_FACTOR;
|
||||
value = leaderboardRowDTO.effectiveTimeOnTimeFactor;
|
||||
|
||||
@@ -31,6 +31,7 @@ The supported race detail constants right now are:<br/>
|
||||
- LEG_WINDWARD_DISTANCE_TO_GO_IN_METERS<br/>
|
||||
- LEG_CURRENT_ABSOLUTE_CROSS_TRACK_ERROR_IN_METERS<br/>
|
||||
- LEG_CURRENT_SIGNED_CROSS_TRACK_ERROR_IN_METERS<br/>
|
||||
- LEG_AVERAGE_SPEED_OVER_GROUND_IN_KNOTS<br/>
|
||||
- OVERALL_MAXIMUM_SPEED_OVER_GROUND_IN_KNOTS
|
||||
- OVERALL_TIME_ON_TIME_FACTOR<br/>
|
||||
- OVERALL_TIME_ON_DISTANCE_ALLOWANCE_IN_SECONDS_PER_NAUTICAL_MILE<br/>
|
||||
|
||||
+1
-1
@@ -4748,7 +4748,7 @@ Replicator {
|
||||
public Map<Integer, Statistics> getLocalStatisticsByYear() {
|
||||
final Map<Integer, StatisticsCalculator> calculators = new HashMap<>();
|
||||
getAllEvents().forEach((event) -> {
|
||||
if (getSecurityService().hasCurrentUserReadPermission(event)) {
|
||||
if (getSecurityService().hasCurrentUserReadPermission(event) && event.isPublic()) {
|
||||
final Integer eventYear = EventUtil.getYearOfEvent(event);
|
||||
// The year may be null if the event has no start date set
|
||||
// In this case the event is ignored for the yearly
|
||||
|
||||
@@ -48,6 +48,10 @@
|
||||
for AWS landscape management. This removes the requirement to convert new OpenSSH keys to PEM format before
|
||||
starting to work with them.
|
||||
</li>
|
||||
<li>For the DNS name resulting from a new replica set name and an optional domain name or the default domain name
|
||||
(<tt>sapsailing.com</tt>) it is now checked that this name is not taken yet. An error message will be shown
|
||||
otherwise.
|
||||
</li>
|
||||
</ul>
|
||||
<h2 class="articleSubheadline">February 2023</h2>
|
||||
<ul class="bulletList">
|
||||
|
||||
@@ -72,7 +72,7 @@ public abstract class DataEntryDialog<T> {
|
||||
private final FlowPanel rightButtonPanel;
|
||||
private final FlowPanel leftButtonPanel;
|
||||
private final AsyncActionsExecutor validationExecutor;
|
||||
private static final String VALIDATION_ACTION_CATEGORY = "validation";
|
||||
protected static final String VALIDATION_ACTION_CATEGORY = "validation";
|
||||
|
||||
private boolean dialogInInvalidState = false;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user