java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/whatsnew/resources/SailingAnalyticsNotes.html
... ...
@@ -17,6 +17,9 @@
17 17
their dampened COG/SOG values based on the newer fixes. This sacrifices short
18 18
maneuver calculation delays for better performance due to fewer re-calculations
19 19
and reliable results with no difference between live and replay analysis.</li>
20
+ <li>The polar data export service now allows clients to filter the result down to one or
21
+ more boat classes. See <a href="/polars/webservices/api/polar_data.html">https://dev.sapsailing.com/polars/webservices/api/polar_data.html</a>
22
+ for more details.</li>
20 23
</ul>
21 24
<h5 class="articleSubheadline">December 2025</h5>
22 25
<ul class="bulletList">
java/com.sap.sailing.landscape/resources/stringmessages/SailingLandscape_StringMessages_cs.properties
... ...
@@ -16,3 +16,5 @@ FinishedToArchiveReplicaSetSubject=Archivace sady replik {0} je dokončena.
16 16
FinishedToArchiveReplicaSetBody=Archivace sady replik {0} je dokončena.\nPokud jste to vyžadovali, původní sada replik byla odebrána.\n\nTento e-mail vám byl doručen, protože máte oprávnění správce pro {0}.\nNechcete-li taková hlášení nadále dostávat, na <https://sapsailing.com/gwt/AdminConsole.html#UserManagementPlace:> tato oprávnění odeberte.
17 17
NewArchiveCandidateReadyForSpotChecksAndRotationSubject=Nový kandidát {0} je připraven na namátkové kontroly
18 18
NewArchiveCandidateReadyForSpotChecksAndRotationBody=Spustili jsme následující kontroly:\n{3}.\nNový kandidát {0} je připraven na namátkové kontroly, a pokud je to v pořádku, rotace se stane novou produkcí {0}.\nSpusťte namátkové kontroly v <https://{1}/gwt/Home.html#EventsPlace:> a porovnejte s <https://{2}/gwt/Home.html#EventsPlace:>.\nPo úspěšných kontrolách spusťte rotaci na nový produkční server na adrese <{4}/gwt/AdminConsole.html#LandscapeManagementPlace:>.
19
+NewArchiveCandidateFailedSubject=Kontrola {1} během spouštění {0} se nezdařila
20
+NewArchiveCandidateFailedBody=Kontrola „{1}“ při spouštění {0} se nezdařila se zprávou „{2}“. Zkontrolujte infrastrukturu a proveďte manuální opravu.
java/com.sap.sailing.landscape/resources/stringmessages/SailingLandscape_StringMessages_da.properties
... ...
@@ -16,3 +16,5 @@ FinishedToArchiveReplicaSetSubject=Arkivering af et replikasæt {0} er afsluttet
16 16
FinishedToArchiveReplicaSetBody=Arkivering af et replikasæt {0} er afsluttet.\nHvis du har anmodet om dette, er det oprindelige replikasæt fjernet.\n\nDu modtager denne e-mail, fordi du har administrationsrettigheder til {0}.\nFjern disse rettigheder på <https://sapsailing.com/gwt/AdminConsole.html#UserManagementPlace:>, hvis du ikke længere vil modtage disse meddelelser.
17 17
NewArchiveCandidateReadyForSpotChecksAndRotationSubject=Den nye {0}-kandidat er klar til stikprøvekontrol
18 18
NewArchiveCandidateReadyForSpotChecksAndRotationBody=Vi har kørt følgende kontroller:\n{3}.\nDen nye {0}-kandidat er klar til stikprøvekontroller, og hvis OK, er rotationen klar til at blive den nye produktion {0}.\nKør dine stikprøvekontroller på <https://{1}/gwt/Home.html#EventsPlace:>, og sammenlign med <https://{2}/gwt/Home.html#EventsPlace:>.\nStart rotationen til den nye produktionsserver på <{4}/gwt/AdminConsole.html#LandscapeManagementPlace:> efter fuldførte kontroller.
19
+NewArchiveCandidateFailedSubject=Kontrollen af {1} mislykkedes under opstart af {0}
20
+NewArchiveCandidateFailedBody=Kontrollen "{1}" mislykkedes med meddelelsen "{2}" under opstart af {0}. Kontroller landskabet, og ret manuelt.
java/com.sap.sailing.landscape/resources/stringmessages/SailingLandscape_StringMessages_es.properties
... ...
@@ -16,3 +16,5 @@ FinishedToArchiveReplicaSetSubject=Archivo de conjunto de réplicas en {0} final
16 16
FinishedToArchiveReplicaSetBody=El archivo de un conjunto de réplicas {0} ha finalizado.\nSi así lo ha solicitado, el conjunto de réplicas original se ha quitado.\n\nEstá recibiendo este correo porque tiene permisos administrativos para {0}.\nRetire esos permisos en <https://sapsailing.com/gwt/AdminConsole.html#UserManagementPlace:> si ya no desea recibir estos mensajes.
17 17
NewArchiveCandidateReadyForSpotChecksAndRotationSubject=El candidato nuevo {0} está listo para los controles puntuales
18 18
NewArchiveCandidateReadyForSpotChecksAndRotationBody=Hemos ejecutado los siguientes controles:\n{3}.\nEl candidato nuevo {0} está listo para los controles puntuales y, si es correcto, la rotación para convertirse en la producción nueva {0}.\nEjecute sus controles puntuales en <https://{1}/gwt/Home.html#EventsPlace:> y compárelos con <https://{2}/gwt/Home.html#EventsPlace:>.\nInicie la rotación al servidor de producción nuevo en <{4}/gwt/AdminConsole.html#LandscapeManagementPlace:> tras los controles correctos.
19
+NewArchiveCandidateFailedSubject=La verificación {1} ha fallado durante el inicio de {0}
20
+NewArchiveCandidateFailedBody=La verificación "{1}" ha fallado con el mensaje "{2}" al iniciar {0}. Verifique la infraestructura y corríjala manualmente.
java/com.sap.sailing.landscape/resources/stringmessages/SailingLandscape_StringMessages_fr.properties
... ...
@@ -16,3 +16,5 @@ FinishedToArchiveReplicaSetSubject=Archivage de l''ensemble de réplicas {0} ter
16 16
FinishedToArchiveReplicaSetBody=L''archivage de l''ensemble de réplicas {0} est terminé.\nSi vous en avez fait la demande, l''ensemble de réplicas d''origine a été supprimé.\n\nVous recevez cet e-mail car vous disposez des autorisations de gestion pour {0}.\nSi vous ne voulez plus recevoir ces messages, retirez ces autorisations sur <https://sapsailing.com/gwt/AdminConsole.html#UserManagementPlace>.
17 17
NewArchiveCandidateReadyForSpotChecksAndRotationSubject=Le nouveau candidat {0} est prêt pour des contrôles ponctuels.
18 18
NewArchiveCandidateReadyForSpotChecksAndRotationBody=Nous avons exécuté les contrôles suivants :\n{3}.\nLe nouveau candidat {0} est prêt pour les contrôles ponctuels et, s''ils donnent de bons résultats, pour la rotation afin de devenir le nouvel élément {0} de production.\nEffectuez vos contrôles ponctuels via le lien <https://{1}/gwt/Home.html#EventsPlace:> et comparez-les à <https://{2}/gwt/Home.html#EventsPlace:>.\nSi les contrôles sont réussis, lancez la rotation vers le nouveau serveur de production via le lien <{4}/gwt/AdminConsole.html#LandscapeManagementPlace:>.
19
+NewArchiveCandidateFailedSubject=Échec de la vérification {1} lors du lancement de {0}
20
+NewArchiveCandidateFailedBody=La vérification "{1}" a échoué avec le message "{2}" lors du lancement de {0}. Vérifiez l''infrastructure et corrigez l''erreur manuellement.
java/com.sap.sailing.landscape/resources/stringmessages/SailingLandscape_StringMessages_it.properties
... ...
@@ -16,3 +16,5 @@ FinishedToArchiveReplicaSetSubject=Archiviazione di un set di replica {0} comple
16 16
FinishedToArchiveReplicaSetBody=L''archiviazione di un set di replica {0} è stata completata.\nSe richiesto, il set di replica originale è stato rimosso.\n\nSi riceve questa e-mail perché si dispone di autorizzazioni amministrative per {0}.\nRimuovere queste autorizzazioni all''indirizzo <https://sapsailing.com/gwt/AdminConsole.html#UserManagementPlace:> se non si desidera ricevere più questi messaggi.
17 17
NewArchiveCandidateReadyForSpotChecksAndRotationSubject=Il nuovo candidato {0} è pronto per i controlli a campione
18 18
NewArchiveCandidateReadyForSpotChecksAndRotationBody=Sono stati eseguiti i seguenti controlli:\n{3}.\nIl nuovo candidato {0} è pronto per i controlli a campione e, se li supera, inizierà la rotazione per diventare il nuovo {0} di produzione .\nEseguire i controlli a campione all''indirizzo <https://{1}/gwt/Home.html#EventsPlace:> e confrontarli con <https://{2}/gwt/Home.html#EventsPlace:>.\nAvviare la rotazione al nuovo server di produzione all''indirizzo <{4}/gwt/AdminConsole.html#LandscapeManagementPlace:> dopo aver eseguito correttamente i controlli.
19
+NewArchiveCandidateFailedSubject=Controllo {1} non riuscito durante l’avvio di {0}
20
+NewArchiveCandidateFailedBody=Il controllo "{1}" non è riuscito con il messaggio "{2}" durante l''avvio di {0}. Controllare l''infrastruttura e correggere l’errore manualmente.
java/com.sap.sailing.landscape/resources/stringmessages/SailingLandscape_StringMessages_ja.properties
... ...
@@ -16,3 +16,5 @@ FinishedToArchiveReplicaSetSubject=複製セット {0} のアーカイブが終
16 16
FinishedToArchiveReplicaSetBody=複製セット {0} のアーカイブが終了しました。\nそのように依頼している場合には、オリジナルの複製セットは削除されています。\n\nこのメールを受信しているのは、{0} の管理権限をお持ちであるためです。\nこれらのメッセージをもう受信しないようにするには、<https://sapsailing.com/gwt/AdminConsole.html#UserManagementPlace:> でそれらの権限を削除してください。
17 17
NewArchiveCandidateReadyForSpotChecksAndRotationSubject=新規 {0} 候補のスポットチェックの準備が完了
18 18
NewArchiveCandidateReadyForSpotChecksAndRotationBody=以下のチェックが実行されました:\n{3}。\n新規 {0} 候補はスポットチェックの準備が完了しており、OK の場合は、ローテーションして新規本稼動 {0} になります。\nスポットチェックを <https://{1}/gwt/Home.html#EventsPlace:> で実行し、<https://{2}/gwt/Home.html#EventsPlace:> と比較します。\nチェックが正常に終了した後、<{4}/gwt/AdminConsole.html#LandscapeManagementPlace:> で新規本稼動サーバへのローテーションを開始します。
19
+NewArchiveCandidateFailedSubject=チェック {1} が {0} 起動時に失敗
20
+NewArchiveCandidateFailedBody={0} の起動時に、チェック "{1}" が失敗し、メッセージ "{2}" が表示されました。ランドスケープを確認し、マニュアルで修正してください。
java/com.sap.sailing.landscape/resources/stringmessages/SailingLandscape_StringMessages_pt.properties
... ...
@@ -16,3 +16,5 @@ FinishedToArchiveReplicaSetSubject=Arquivamento de conjunto de réplicas {0} con
16 16
FinishedToArchiveReplicaSetBody=O arquivamento de conjunto de réplicas {0} foi concluído.\nSe você tiver solicitado, o conjunto de réplicas original terá sido removido.\n\nVocê está recebendo este correio porque tem permissões administrativas para {0}.\nRemova essas permissões em <https://sapsailing.com/gwt/AdminConsole.html#UserManagementPlace:> se você não quiser mais receber estas mensagens.
17 17
NewArchiveCandidateReadyForSpotChecksAndRotationSubject=O novo candidato {0} está pronto para verificações pontuais
18 18
NewArchiveCandidateReadyForSpotChecksAndRotationBody=Executamos as seguintes verificações:\n{3}.\nO novo candidato {0} está pronto para verificações pontuais e, se OK, rotação para se tornar o novo {0} de produção.\nExecute suas verificações pontuais em <https://{1}/gwt/Home.html#EventsPlace:> e compare com <https://{2}/gwt/Home.html#EventsPlace:>.\nInicie a rotação para o novo servidor de produção em <{4}/gwt/AdminConsole.html#LandscapeManagementPlace:> após verificações com êxito.
19
+NewArchiveCandidateFailedSubject=A verificação {1} falhou durante a inicialização {0}
20
+NewArchiveCandidateFailedBody=A verificação "{1}" falhou com a mensagem "{2}" ao inicializar {0}. Verifique a estrutura e corrija manualmente.
java/com.sap.sailing.landscape/resources/stringmessages/SailingLandscape_StringMessages_ru.properties
... ...
@@ -16,3 +16,5 @@ FinishedToArchiveReplicaSetSubject=Завершена архивация наб
16 16
FinishedToArchiveReplicaSetBody=Завершена архивация набора реплик {0}.\nИсходный набор реплик был удален, если вы запросили удаление.\n\nВы получили это письмо, поскольку имеете полномочия администратора для {0}.\nЕсли вы больше не хотите получать эти письма, отмените свои полномочия на странице https://sapsailing.com/gwt/AdminConsole.html#UserManagementPlace:> .
17 17
NewArchiveCandidateReadyForSpotChecksAndRotationSubject=Новый кандидат {0} готов к выборочным проверкам
18 18
NewArchiveCandidateReadyForSpotChecksAndRotationBody=Выполнены следующие проверки:\n{3}.\nНовый кандидат {0} готов к выборочным проверкам и, если все в порядке, к переводу в производство {0}.\nВыполните выборочные проверки по адресу <https://{1}/gwt/Home.html#EventsPlace:> и выполните сравнение с <https://{2}/gwt/Home.html#EventsPlace:>.\nПосле успешных проверок запустите переход на новый продуктивный сервер по адресу <{4}/gwt/AdminConsole.html#LandscapeManagementPlace:> .
19
+NewArchiveCandidateFailedSubject=Проверка {1} не удалась при запуске {0}
20
+NewArchiveCandidateFailedBody=Проверка "{1}" не удалась (сообщение: "{2}") при запуске {0}. Проверьте ландшафт и исправьте вручную.
java/com.sap.sailing.landscape/resources/stringmessages/SailingLandscape_StringMessages_sl.properties
... ...
@@ -16,3 +16,5 @@ FinishedToArchiveReplicaSetSubject=Arhiviranje niza replik {0} je končano
16 16
FinishedToArchiveReplicaSetBody=Arhiviranje niza replik v {0} je končano.\nČe ste to zahtevali, je bil izvirni replik odstranjen.\n\nTo elektronsko sporočilo ste prejeli, ker imate upravljavska dovoljenja za {0}.\nČe teh sporočil ne želite več prejemati, odstranite ta dovoljenja na <https://sapsailing.com/gwt/AdminConsole.html#UserManagementPlace:>.
17 17
NewArchiveCandidateReadyForSpotChecksAndRotationSubject=Novi kandidat za {0} je pripravljen na preglede
18 18
NewArchiveCandidateReadyForSpotChecksAndRotationBody=Izvedeni so naslednji pregledi:\n{3}.\nNovi kandidat za {0} je pripravljen za preglede in v primeru ustreznosti za rotacijo v proizvodnjo kot novi {0}.\nIzvedite preglede na <https://{1}/gwt/Home.html#EventsPlace:> in jih primerjajte z <https://{2}/gwt/Home.html#EventsPlace:>.\nPo uspešnih pregledih zaženite rotacijo v novi proizvodni strežnik na <{4}/gwt/AdminConsole.html#LandscapeManagementPlace:>.
19
+NewArchiveCandidateFailedSubject=Preverjanje {1} ni uspelo med zagonom {0}
20
+NewArchiveCandidateFailedBody=Preverjanje "{1}" ni uspelo s sporočilom "{2}" med zagonom {0}. Preverite infrastrukturo in ročno popravite.
java/com.sap.sailing.landscape/resources/stringmessages/SailingLandscape_StringMessages_zh.properties
... ...
@@ -16,3 +16,5 @@ FinishedToArchiveReplicaSetSubject=归档复本集 {0} 已完成
16 16
FinishedToArchiveReplicaSetBody=归档复本集 {0} 已完成。\n如果您要求这样做,原始复本集已移除。\n\n您之所以收到此邮件,是因为您具有 {0} 的管理权限。\n如果不想再收到这些消息,请在 <https://sapsailing.com/gwt/AdminConsole.html#UserManagementPlace:> 移除这些权限。
17 17
NewArchiveCandidateReadyForSpotChecksAndRotationSubject=新 {0} 候选项已准备好进行抽查
18 18
NewArchiveCandidateReadyForSpotChecksAndRotationBody=我们已运行以下检查:\n{3}。\n 新 {0} 候选项已准备好进行抽查,如果良好,则轮换到新生产{0}。\n在 <https://{1}/gwt/Home.html#EventsPlace:> 上运行抽查,并与 <https://{2}/gwt/Home.html#EventsPlace:> 进行比较。\n检查成功后,在 <{4}/gwt/AdminConsole.html#LandscapeManagementPlace:> 上启动轮换到新生产服务器。
19
+NewArchiveCandidateFailedSubject={1} 启动期间的检查 {0} 失败
20
+NewArchiveCandidateFailedBody=检查 "{1}" 在启动 {0} 时失败,并显示消息 "{2}"。请检查架构并手动修复。
java/com.sap.sailing.polars/src/com/sap/sailing/polars/impl/PolarDataServiceImpl.java
... ...
@@ -74,6 +74,13 @@ public class PolarDataServiceImpl extends AbstractReplicableWithObjectInputStrea
74 74
resetState();
75 75
}
76 76
77
+ public PolarDataServiceImpl filterToBoatClasses(Iterable<BoatClass> boatClassesToFilterTo) {
78
+ final PolarDataMiner filteredPolarDataMiner = polarDataMiner.filterToBoatClasses(boatClassesToFilterTo);
79
+ final PolarDataServiceImpl filteredService = new PolarDataServiceImpl();
80
+ filteredService.polarDataMiner = filteredPolarDataMiner;
81
+ return filteredService;
82
+ }
83
+
77 84
@Override
78 85
public void resetState() {
79 86
PolarSheetGenerationSettings settings = PolarSheetGenerationSettingsImpl.createBackendPolarSettings();
java/com.sap.sailing.polars/src/com/sap/sailing/polars/jaxrs/api/PolarDataResource.java
... ...
@@ -2,11 +2,13 @@ package com.sap.sailing.polars.jaxrs.api;
2 2
3 3
import java.io.IOException;
4 4
import java.io.OutputStream;
5
+import java.util.List;
5 6
import java.util.logging.Logger;
6 7
7 8
import javax.ws.rs.GET;
8 9
import javax.ws.rs.Path;
9 10
import javax.ws.rs.Produces;
11
+import javax.ws.rs.QueryParam;
10 12
import javax.ws.rs.WebApplicationException;
11 13
import javax.ws.rs.core.Response;
12 14
import javax.ws.rs.core.StreamingOutput;
... ...
@@ -14,9 +16,12 @@ import javax.ws.rs.core.StreamingOutput;
14 16
import org.apache.shiro.SecurityUtils;
15 17
import org.apache.shiro.subject.Subject;
16 18
19
+import com.sap.sailing.domain.base.BoatClass;
17 20
import com.sap.sailing.domain.common.security.SecuredDomainType;
21
+import com.sap.sailing.polars.impl.PolarDataServiceImpl;
18 22
import com.sap.sailing.polars.jaxrs.AbstractPolarResource;
19 23
import com.sap.sse.ServerInfo;
24
+import com.sap.sse.common.Util;
20 25
import com.sap.sse.security.shared.HasPermissions.DefaultActions;
21 26
import com.sap.sse.security.shared.TypeRelativeObjectIdentifier;
22 27
... ...
@@ -26,7 +31,7 @@ public class PolarDataResource extends AbstractPolarResource {
26 31
27 32
@GET
28 33
@Produces("application/octet-stream;charset=UTF-8")
29
- public Response getRegressions() throws IOException {
34
+ public Response getRegressions(@QueryParam("boatClassName") final List<String> boatClassNames) throws IOException {
30 35
final Subject subject = SecurityUtils.getSubject();
31 36
logger.info("Polar Data requested by "+ (subject.getPrincipal() == null ? "anonymous user" : subject.getPrincipal().toString()));
32 37
subject.checkPermission(SecuredDomainType.POLAR_DATA.getStringPermissionForTypeRelativeIdentifier(DefaultActions.READ,
... ...
@@ -34,7 +39,24 @@ public class PolarDataResource extends AbstractPolarResource {
34 39
return Response.ok(new StreamingOutput() {
35 40
@Override
36 41
public void write(OutputStream output) throws IOException, WebApplicationException {
37
- getPolarDataServiceImpl().serializeForInitialReplication(output);
42
+ PolarDataServiceImpl polarDataService = getPolarDataServiceImpl();
43
+ @SuppressWarnings("unchecked")
44
+ final Iterable<BoatClass>[] boatClassesToFilterTo = new Iterable[1];
45
+ if (boatClassNames == null || boatClassNames.isEmpty()) {
46
+ boatClassesToFilterTo[0] = null;
47
+ } else {
48
+ try {
49
+ polarDataService.runWithDomainFactory(domainFactory->{
50
+ boatClassesToFilterTo[0] = Util.map(boatClassNames, bcn->domainFactory.getBoatClass(bcn));
51
+ });
52
+ } catch (InterruptedException e) {
53
+ throw new RuntimeException(e);
54
+ }
55
+ }
56
+ if (boatClassesToFilterTo[0] != null) {
57
+ polarDataService = polarDataService.filterToBoatClasses(boatClassesToFilterTo[0]);
58
+ }
59
+ polarDataService.serializeForInitialReplication(output);
38 60
}
39 61
}).header("Content-Type", "application/octet-stream").build();
40 62
}
java/com.sap.sailing.polars/src/com/sap/sailing/polars/mining/CubicRegressionPerCourseProcessor.java
... ...
@@ -18,11 +18,13 @@ import com.sap.sailing.domain.common.Tack;
18 18
import com.sap.sailing.domain.common.polars.NotEnoughDataHasBeenAddedException;
19 19
import com.sap.sailing.domain.polars.PolarsChangedListener;
20 20
import com.sap.sse.common.Speed;
21
+import com.sap.sse.common.Util;
21 22
import com.sap.sse.datamining.components.AdditionalResultDataBuilder;
22 23
import com.sap.sse.datamining.components.Processor;
23 24
import com.sap.sse.datamining.factories.GroupKeyFactory;
24 25
import com.sap.sse.datamining.impl.components.GroupedDataEntry;
25 26
import com.sap.sse.datamining.shared.GroupKey;
27
+import com.sap.sse.datamining.shared.impl.GenericGroupKey;
26 28
27 29
/**
28 30
* Groups incoming fixes by boatclass and legtype into {@link AngleAndSpeedRegression} instances and
... ...
@@ -45,6 +47,40 @@ public class CubicRegressionPerCourseProcessor implements
45 47
*/
46 48
private transient ConcurrentMap<BoatClass, Set<PolarsChangedListener>> listeners;
47 49
50
+ public CubicRegressionPerCourseProcessor filterToBoatClasses(Iterable<BoatClass> boatClasses) {
51
+ final Set<BoatClass> allowedBoatClasses = Util.asSet(boatClasses);
52
+ final CubicRegressionPerCourseProcessor filteredProcessor = new CubicRegressionPerCourseProcessor();
53
+ for (final Map.Entry<GroupKey, AngleAndSpeedRegression> entry : regressions.entrySet()) {
54
+ GroupKey key = entry.getKey();
55
+ BoatClass boatClass = extractBoatClass(key);
56
+ if (boatClass != null && allowedBoatClasses.contains(boatClass)) {
57
+ filteredProcessor.regressions.put(key, entry.getValue());
58
+ }
59
+ }
60
+ return filteredProcessor;
61
+ }
62
+
63
+ private BoatClass extractBoatClass(GroupKey key) {
64
+ final BoatClass result;
65
+ if (key.hasSubKeys()) {
66
+ // In the compound key, BoatClass is the second dimension (index 1)
67
+ GroupKey boatClassKey = key.getKeys().get(1);
68
+ if (boatClassKey instanceof GenericGroupKey) {
69
+ Object value = ((GenericGroupKey<?>) boatClassKey).getValue();
70
+ if (value instanceof BoatClass) {
71
+ result = (BoatClass) value;
72
+ } else {
73
+ result = null;
74
+ }
75
+ } else {
76
+ result = null;
77
+ }
78
+ } else {
79
+ result = null;
80
+ }
81
+ return result;
82
+ }
83
+
48 84
@Override
49 85
public boolean canProcessElements() {
50 86
return true;
... ...
@@ -109,7 +145,6 @@ public class CubicRegressionPerCourseProcessor implements
109 145
110 146
private GroupKey createGroupKey(final BoatClass boatClass, final LegType legType) {
111 147
LegTypePolarClusterKey key = new LegTypePolarClusterKey() {
112
-
113 148
@Override
114 149
public BoatClass getBoatClass() {
115 150
return boatClass;
java/com.sap.sailing.polars/src/com/sap/sailing/polars/mining/PolarDataDimensionCollectionFactory.java
... ...
@@ -40,7 +40,6 @@ public class PolarDataDimensionCollectionFactory {
40 40
Collection<Function<?>> dimensions = new ArrayList<>();
41 41
FunctionFactory functionFactory = new FunctionFactory();
42 42
addTackAndLegTypeDimensions(dimensions, functionFactory);
43
-
44 43
addPolarBaseDimension(dimensions, functionFactory);
45 44
return dimensions;
46 45
}
java/com.sap.sailing.polars/src/com/sap/sailing/polars/mining/PolarDataMiner.java
... ...
@@ -136,6 +136,13 @@ public class PolarDataMiner {
136 136
throw new RuntimeException(e);
137 137
}
138 138
}
139
+
140
+ public PolarDataMiner filterToBoatClasses(Iterable<BoatClass> boatClasses) {
141
+ return new PolarDataMiner(backendPolarSheetGenerationSettings,
142
+ cubicRegressionPerCourseProcessor.filterToBoatClasses(boatClasses),
143
+ speedRegressionPerAngleClusterProcessor.filterToBoatClasses(boatClasses),
144
+ angleClusterGroup);
145
+ }
139 146
140 147
private void setUpWorkflow() throws ClassCastException, NoSuchMethodException, SecurityException {
141 148
Collection<Processor<GroupedDataEntry<GPSFixMovingWithPolarContext>, ?>> regressionPerCourseGrouperResultReceivers = new ArrayList<Processor<GroupedDataEntry<GPSFixMovingWithPolarContext>, ?>>();
java/com.sap.sailing.polars/src/com/sap/sailing/polars/mining/SpeedRegressionPerAngleClusterProcessor.java
... ...
@@ -22,6 +22,7 @@ import com.sap.sailing.polars.regression.IncrementalLeastSquares;
22 22
import com.sap.sailing.polars.regression.impl.IncrementalAnyOrderLeastSquaresImpl;
23 23
import com.sap.sse.common.Bearing;
24 24
import com.sap.sse.common.Speed;
25
+import com.sap.sse.common.Util;
25 26
import com.sap.sse.common.Util.Pair;
26 27
import com.sap.sse.common.impl.DegreeBearingImpl;
27 28
import com.sap.sse.common.impl.KnotSpeedImpl;
... ...
@@ -32,6 +33,7 @@ import com.sap.sse.datamining.data.ClusterGroup;
32 33
import com.sap.sse.datamining.factories.GroupKeyFactory;
33 34
import com.sap.sse.datamining.impl.components.GroupedDataEntry;
34 35
import com.sap.sse.datamining.shared.GroupKey;
36
+import com.sap.sse.datamining.shared.impl.GenericGroupKey;
35 37
36 38
/**
37 39
* Holds one speed regression per BoatClass, WindSpeed, Beat Angle Range combination and provides means for adding and
... ...
@@ -63,6 +65,49 @@ public class SpeedRegressionPerAngleClusterProcessor implements
63 65
this.angleClusterGroup = angleClusterGroup;
64 66
}
65 67
68
+ public SpeedRegressionPerAngleClusterProcessor filterToBoatClasses(Iterable<BoatClass> boatClasses) {
69
+ final Set<BoatClass> allowedBoatClasses = Util.asSet(boatClasses);
70
+ final SpeedRegressionPerAngleClusterProcessor filteredProcessor = new SpeedRegressionPerAngleClusterProcessor(angleClusterGroup);
71
+ synchronized (regressions) {
72
+ for (Map.Entry<GroupKey, IncrementalLeastSquares> entry : regressions.entrySet()) {
73
+ GroupKey key = entry.getKey();
74
+ BoatClass boatClass = extractBoatClass(key);
75
+ if (boatClass != null && allowedBoatClasses.contains(boatClass)) {
76
+ filteredProcessor.regressions.put(key, entry.getValue());
77
+ }
78
+ }
79
+ }
80
+ synchronized (fixCountPerBoatClass) {
81
+ for (Map.Entry<BoatClass, Long> entry : fixCountPerBoatClass.entrySet()) {
82
+ if (allowedBoatClasses.contains(entry.getKey())) {
83
+ filteredProcessor.fixCountPerBoatClass.put(entry.getKey(), entry.getValue());
84
+ }
85
+ }
86
+ }
87
+ return filteredProcessor;
88
+ }
89
+
90
+ private BoatClass extractBoatClass(GroupKey key) {
91
+ final BoatClass result;
92
+ if (key.hasSubKeys()) {
93
+ // In the compound key, BoatClass is the first dimension (index 0)
94
+ GroupKey boatClassKey = key.getKeys().get(0);
95
+ if (boatClassKey instanceof GenericGroupKey) {
96
+ Object value = ((GenericGroupKey<?>) boatClassKey).getValue();
97
+ if (value instanceof BoatClass) {
98
+ result = (BoatClass) value;
99
+ } else {
100
+ result = null;
101
+ }
102
+ } else {
103
+ result = null;
104
+ }
105
+ } else {
106
+ result = null;
107
+ }
108
+ return result;
109
+ }
110
+
66 111
@Override
67 112
public boolean canProcessElements() {
68 113
// TODO Auto-generated method stub
java/com.sap.sailing.polars/webservices/api/polar_data.html
... ...
@@ -13,7 +13,9 @@
13 13
14 14
<b>Description:</b>
15 15
<p>
16
-Gets the binary representation of the server's polar data for all boat classes.
16
+Gets the binary representation of the server's polar data. By default, data for all boat classes is returned.
17
+Optionally, the results can be filtered to specific boat classes using the <tt>boatClassName</tt> query parameter,
18
+which may be specified multiple times to include several boat classes.
17 19
</p>
18 20
<p>
19 21
You need the <tt>POLAR_DATA:READ</tt> permission for this. The output can be deserialized into a Java object of type
... ...
@@ -36,9 +38,29 @@ class.
36 38
<td>Binary Java Object</td>
37 39
</tr>
38 40
<tr>
39
- <td>Example:</td>
40
- <td><a href="https://www.sapsailing.com/polars/api/polar_data">
41
- curl -o polar.dat -H 'Authorization: Bearer {your-access-token-here}' <a href="https://www.sapsailing.com/polars/api/polar_data">https://www.sapsailing.com/polars/api/polar_data</a>
41
+ <td valign="top">Query Parameters:</td>
42
+ <td>
43
+ <table border="1" cellpadding="4" cellspacing="0">
44
+ <tr>
45
+ <th>Name</th><th>Required</th><th>Description</th>
46
+ </tr>
47
+ <tr>
48
+ <td><tt>boatClassName</tt></td>
49
+ <td>No</td>
50
+ <td>Name of a boat class to include in the response. May be specified multiple times
51
+ to request data for several boat classes. If omitted, data for all boat classes is returned.</td>
52
+ </tr>
53
+ </table>
54
+ </td>
55
+ </tr>
56
+ <tr>
57
+ <td valign="top">Examples:</td>
58
+ <td>
59
+ All boat classes:<br/>
60
+ <tt>curl -o polar.dat -H 'Authorization: Bearer {your-access-token-here}' <a href="https://www.sapsailing.com/polars/api/polar_data">https://www.sapsailing.com/polars/api/polar_data</a></tt>
61
+ <br/><br/>
62
+ Filtered to specific boat classes:<br/>
63
+ <tt>curl -o polar.dat -H 'Authorization: Bearer {your-access-token-here}' "<a href="https://www.sapsailing.com/polars/api/polar_data?boatClassName=49er&amp;boatClassName=Nacra17">https://www.sapsailing.com/polars/api/polar_data?boatClassName=49er&amp;boatClassName=Nacra17</a>"</tt>
42 64
</td>
43 65
</tr>
44 66
</table>