Merge branch 'master' into bug5419

# Conflicts:
#	java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/Refresher.java
This commit is contained in:
Udo Wessels
2021-08-30 10:07:55 +02:00
71 changed files with 1089 additions and 435 deletions
+2 -1
View File
@@ -1,4 +1,4 @@
FROM donaldduck70/sapjvm8:8.1.073
FROM donaldduck70/sapjvm8:8.1.078
LABEL maintainer=axel.uhl@sap.com
# Download and extract the release
WORKDIR /home/sailing/servers/server
@@ -12,6 +12,7 @@ RUN wget -O /tmp/RELEASE.tar.gz http://releases.sapsailing.com/RELEASE/RELEASE.t
&& tar xzvpf /tmp/RELEASE.tar.gz \
&& rm /tmp/RELEASE.tar.gz
COPY env.sh .
RUN cat env-default-rules.sh >>env.sh
COPY start .
COPY JavaSE-11.profile .
EXPOSE 8888 14888 8000 7091 6666
+4 -3
View File
@@ -1,12 +1,13 @@
FROM buildpack-deps:stretch-scm
FROM buildpack-deps:latest
LABEL maintainer=axel.uhl@sap.com
# Download and extract the SAP JVM 8
ENV PATH=${PATH}:/opt/sapjvm_8/bin
ENV JAVA_HOME=/opt/sapjvm_8
WORKDIR /opt
RUN apt-get update \
&& apt-get install -y wget unzip \
&& curl --cookie eula_3_1_agreed=tools.hana.ondemand.com/developer-license-3_1.txt "https://tools.hana.ondemand.com/additional/sapjvm-7.1.073-linux-x64.zip" --output sapjvm8-linux-x64.zip \
&& apt-get install -y wget apt-utils unzip \
&& apt-get -y upgrade \
&& curl --cookie eula_3_1_agreed=tools.hana.ondemand.com/developer-license-3_1.txt "https://tools.hana.ondemand.com/additional/sapjvm-8.1.078-linux-x64.zip" --output sapjvm8-linux-x64.zip \
&& unzip sapjvm8-linux-x64.zip \
&& rm sapjvm8-linux-x64.zip \
&& echo "export JAVA_HOME=/opt/sapjvm_8; export PATH=\${PATH}:/opt/sapjvm_8/bin" > /etc/profile.d/javahome.sh
@@ -63,6 +63,9 @@ public enum BoatClassMasterdata {
HOBIE_TIGER ("Hobie Tiger", true, 5.51, 2.60, BoatHullType.CATAMARAN, true),
HOBIE_WILD_CAT ("Hobie Wild Cat", true, 5.49, 2.59, BoatHullType.CATAMARAN, true, "Hobie Wild Cat F18"),
INTERNATIONAL_14("International 14", true, 4.27, 1.83, BoatHullType.MONOHULL, true, "I14", "Int.14", "Int14"),
IQFOIL_MEN("iQFOil Men", true, 2.20, 0.95, BoatHullType.SURFERBOARD, false, "iQFOil 95 Men"),
IQFOIL_WOMEN("iQFOil Women", true, 2.20, 0.95, BoatHullType.SURFERBOARD, false, "iQFOil 95 Women"),
IQFOIL_YOUTH("iQFOil Youth", true, 2.15, 0.85, BoatHullType.SURFERBOARD, false, "iQFOil 85 Youth"),
J22 ("J/22", true, 6.86, 2.44, BoatHullType.MONOHULL, true, "J22", "J-22"),
J24 ("J/24", true, 7.32, 2.67, BoatHullType.MONOHULL, true, "J24", "J-24"),
J70 ("J/70", true, 6.93, 2.25, BoatHullType.MONOHULL, true, "J70", "J-70"),
@@ -76,9 +79,9 @@ public enum BoatClassMasterdata {
KIELZUGVOGEL ("Kielzugvogel", true, 5.80, 1.88, BoatHullType.MONOHULL, false, "KZV"),
FORMULA_KITE ("Kite", true, 3.35, 1.52, BoatHullType.MONOHULL, false, "Formula Kite"),
LASER_2 ("Laser 2", true, 4.39, 1.42, BoatHullType.MONOHULL, false, "Laser II", "Laser2", "Laser-2", "Laser-II"),
LASER_4_7 ("Laser 4.7", true, 4.20, 1.39, BoatHullType.MONOHULL, false, "L4.7"),
LASER_RADIAL ("Laser Radial", true, 4.19, 1.41, BoatHullType.MONOHULL, false, "LAR", "Laser RAD", "RAD", "Radial"),
LASER_INT ("Laser Int.", true, 4.19, 1.39, BoatHullType.MONOHULL, false, "Laser", "LSR", "Laser Standard"),
LASER_4_7 ("Laser 4.7", true, 4.20, 1.39, BoatHullType.MONOHULL, false, "L4.7", "ILCA 4", "ILCA4"),
LASER_RADIAL ("Laser Radial", true, 4.19, 1.41, BoatHullType.MONOHULL, false, "LAR", "Laser RAD", "RAD", "Radial", "ILCA 6", "ILCA6"),
LASER_INT ("Laser Int.", true, 4.19, 1.39, BoatHullType.MONOHULL, false, "Laser", "LSR", "Laser Standard", "ILCA 7", "ILCA7"),
LASER_SB3 ("Laser SB3", true, 6.15, 2.15, BoatHullType.MONOHULL, false, "LSB3", "SB20"),
LAGO_26 ("Lago 26", true, 7.95, 2.50, BoatHullType.MONOHULL, true, "Lago26"),
LONGTZE ("Longtze", true, 6.85, 2.57, BoatHullType.MONOHULL, true, "Swiss Longtze Class"),
@@ -31,6 +31,7 @@ import org.eclipse.jetty.websocket.client.ClientUpgradeRequest;
import org.eclipse.jetty.websocket.client.WebSocketClient;
import org.junit.After;
import org.junit.Before;
import org.junit.Ignore;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.Timeout;
@@ -131,6 +132,7 @@ public class WebSocketTest {
Activator.getInstance().setSecurityService(null);
}
@Ignore("echo.websocket.org is (2021-08-19) down; http://www.websocket.org/index.html says ''Service no longer available''")
@Test
public void simpleWebSocketEchoTest() throws Exception {
String destUri = "ws://echo.websocket.org"; // wss currently doesn't seem to work with Jetty 9.0.4 WebSocket implementation
@@ -3,6 +3,7 @@ package com.sap.sailing.domain.persistence.racelog.tracking;
import java.net.UnknownHostException;
import com.mongodb.MongoException;
import com.mongodb.ReadConcern;
import com.mongodb.WriteConcern;
import com.sap.sailing.domain.persistence.DomainObjectFactory;
import com.sap.sailing.domain.persistence.MongoObjectFactory;
@@ -24,9 +25,10 @@ public interface MongoSensorFixStoreFactory {
* Like {@link #getMongoGPSFixStore(MongoObjectFactory, DomainObjectFactory, TypeBasedServiceFinderFactory)}, but
* additionally the write concern for the MongoDB writes can be controlled which otherwise usually defaults
* to {@link WriteConcern#UNACKNOWLEDGED} for the fixes as well as the metadata.
* @param readConcern TODO
*/
MongoSensorFixStore getMongoGPSFixStore(MongoObjectFactory mongoObjectFactory, DomainObjectFactory domainObjectFactory,
TypeBasedServiceFinderFactory serviceFinderFactory, WriteConcern writeConcern)
TypeBasedServiceFinderFactory serviceFinderFactory, ReadConcern readConcern, WriteConcern writeConcern)
throws UnknownHostException, MongoException;
}
@@ -48,13 +48,15 @@ public class MetadataCollection extends MongoFixHandler {
private final MongoCollection<Document> metadataCollection;
private final ConcurrentHashMap<DeviceIdentifier, MetadataUpdater> metadataUpdaters;
private final WriteConcern writeConcern;
private final ReadConcern readConcern;
public MetadataCollection(MongoObjectFactoryImpl mongoOF,
TypeBasedServiceFinder<FixMongoHandler<?>> fixServiceFinder,
TypeBasedServiceFinder<DeviceIdentifierMongoHandler> deviceServiceFinder, WriteConcern writeConcern) {
TypeBasedServiceFinder<DeviceIdentifierMongoHandler> deviceServiceFinder, ReadConcern readConcern, WriteConcern writeConcern) {
super(fixServiceFinder, deviceServiceFinder);
this.metadataCollection = mongoOF.getGPSFixMetadataCollection();
this.metadataUpdaters = new ConcurrentHashMap<>();
this.readConcern = readConcern;
this.writeConcern = writeConcern;
}
@@ -74,7 +76,7 @@ public class MetadataCollection extends MongoFixHandler {
*/
private Document findMetadataObjectInternal(DeviceIdentifier device) throws TransformationException {
Bson query = getDeviceQuery(device);
Document result = metadataCollection.withReadConcern(ReadConcern.MAJORITY).find(query).first();
Document result = metadataCollection.withReadConcern(readConcern).find(query).first();
return result;
}
@@ -3,6 +3,7 @@ package com.sap.sailing.domain.persistence.racelog.tracking.impl;
import java.net.UnknownHostException;
import com.mongodb.MongoException;
import com.mongodb.ReadConcern;
import com.mongodb.WriteConcern;
import com.sap.sailing.domain.persistence.DomainObjectFactory;
import com.sap.sailing.domain.persistence.MongoObjectFactory;
@@ -21,7 +22,7 @@ public class MongoSensorFixStoreFactoryImpl implements MongoSensorFixStoreFactor
@Override
public MongoSensorFixStore getMongoGPSFixStore(MongoObjectFactory mongoObjectFactory,
DomainObjectFactory domainObjectFactory, TypeBasedServiceFinderFactory serviceFinderFactory,
WriteConcern writeConcern) throws UnknownHostException, MongoException {
return new MongoSensorFixStoreImpl(mongoObjectFactory, domainObjectFactory, serviceFinderFactory, writeConcern);
ReadConcern readConcern, WriteConcern writeConcern) throws UnknownHostException, MongoException {
return new MongoSensorFixStoreImpl(mongoObjectFactory, domainObjectFactory, serviceFinderFactory, readConcern, writeConcern);
}
}
@@ -17,6 +17,7 @@ import java.util.logging.Logger;
import org.bson.Document;
import org.bson.conversions.Bson;
import com.mongodb.ReadConcern;
import com.mongodb.WriteConcern;
import com.mongodb.client.FindIterable;
import com.mongodb.client.MongoCollection;
@@ -72,16 +73,16 @@ public class MongoSensorFixStoreImpl extends MongoFixHandler implements MongoSen
public MongoSensorFixStoreImpl(MongoObjectFactory mongoObjectFactory, DomainObjectFactory domainObjectFactory,
TypeBasedServiceFinderFactory serviceFinderFactory) {
this(mongoObjectFactory, domainObjectFactory, serviceFinderFactory, WriteConcern.UNACKNOWLEDGED);
this(mongoObjectFactory, domainObjectFactory, serviceFinderFactory, ReadConcern.DEFAULT, WriteConcern.UNACKNOWLEDGED);
}
public MongoSensorFixStoreImpl(MongoObjectFactory mongoObjectFactory, DomainObjectFactory domainObjectFactory,
TypeBasedServiceFinderFactory serviceFinderFactory, WriteConcern writeConcern) {
TypeBasedServiceFinderFactory serviceFinderFactory, ReadConcern readConcern, WriteConcern writeConcern) {
super(serviceFinderFactory != null ? createFixServiceFinder(serviceFinderFactory) : null,
serviceFinderFactory != null ? serviceFinderFactory.createServiceFinder(DeviceIdentifierMongoHandler.class) : null);
mongoOF = (MongoObjectFactoryImpl) mongoObjectFactory;
fixesCollection = mongoOF.getGPSFixCollection();
metadataCollection = new MetadataCollection(mongoOF, fixServiceFinder, deviceServiceFinder, writeConcern);
metadataCollection = new MetadataCollection(mongoOF, fixServiceFinder, deviceServiceFinder, readConcern, writeConcern);
this.writeConcern = writeConcern;
}
@@ -10,6 +10,7 @@ import java.util.UUID;
import org.junit.After;
import org.junit.Before;
import com.mongodb.ReadConcern;
import com.mongodb.WriteConcern;
import com.sap.sailing.domain.abstractlog.race.impl.RaceLogImpl;
import com.sap.sailing.domain.abstractlog.regatta.RegattaLog;
@@ -84,7 +85,7 @@ public class AbstractGPSFixStoreTest extends RaceLogTrackingTestHelper {
regattaLog = new RegattaLogImpl("regattalog");
dropPersistedData();
store = new MongoSensorFixStoreImpl(service.getMongoObjectFactory(), service.getDomainObjectFactory(),
serviceFinderFactory, WriteConcern.MAJORITY);
serviceFinderFactory, ReadConcern.MAJORITY, WriteConcern.MAJORITY);
}
@After
@@ -14,6 +14,7 @@ import org.junit.Before;
import org.junit.Test;
import com.mongodb.MongoException;
import com.mongodb.ReadConcern;
import com.mongodb.WriteConcern;
import com.sap.sailing.domain.abstractlog.AbstractLogEventAuthor;
import com.sap.sailing.domain.abstractlog.impl.LogEventAuthorImpl;
@@ -93,7 +94,7 @@ public class RaceLogFixTrackerManagerTest {
raceLog2 = new RaceLogImpl("racelog2");
regattaLog = new RegattaLogImpl("regattalog");
store = new MongoSensorFixStoreImpl(PersistenceFactory.INSTANCE.getDefaultMongoObjectFactory(),
PersistenceFactory.INSTANCE.getDefaultDomainObjectFactory(), serviceFinderFactory, WriteConcern.MAJORITY);
PersistenceFactory.INSTANCE.getDefaultDomainObjectFactory(), serviceFinderFactory, ReadConcern.MAJORITY, WriteConcern.MAJORITY);
Course course = new CourseImpl("course",
Arrays.asList(new Waypoint[] { new WaypointImpl(mark), new WaypointImpl(mark2) }));
Map<Competitor, Boat> competitorsAndBoats = new HashMap<>();
@@ -24,6 +24,7 @@ import org.junit.Before;
import org.junit.Test;
import com.mongodb.MongoException;
import com.mongodb.ReadConcern;
import com.mongodb.WriteConcern;
import com.mongodb.client.MongoDatabase;
import com.sap.sailing.domain.abstractlog.AbstractLogEventAuthor;
@@ -153,7 +154,7 @@ public class SensorFixStoreAndLoadTest {
raceLog.add(new RaceLogEndOfTrackingEventImpl(new MillisecondsTimePoint(END_OF_TRACKING), author, 0));
regattaLog = new RegattaLogImpl("regattalog");
store = new MongoSensorFixStoreImpl(PersistenceFactory.INSTANCE.getDefaultMongoObjectFactory(),
PersistenceFactory.INSTANCE.getDefaultDomainObjectFactory(), serviceFinderFactory, WriteConcern.MAJORITY);
PersistenceFactory.INSTANCE.getDefaultDomainObjectFactory(), serviceFinderFactory, ReadConcern.MAJORITY, WriteConcern.MAJORITY);
regattaLog.add(new RegattaLogDefineMarkEventImpl(new MillisecondsTimePoint(1), author,
new MillisecondsTimePoint(1), 0, mark));
regattaLog.add(new RegattaLogDefineMarkEventImpl(new MillisecondsTimePoint(2), author,
@@ -8,11 +8,13 @@ import java.util.List;
import java.util.function.Consumer;
import org.junit.After;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.mockito.Mockito;
import com.mongodb.MongoException;
import com.mongodb.ReadConcern;
import com.mongodb.WriteConcern;
import com.mongodb.client.MongoDatabase;
import com.sap.sailing.domain.common.DeviceIdentifier;
@@ -37,8 +39,6 @@ import com.sap.sse.common.impl.DegreeBearingImpl;
import com.sap.sse.common.impl.MillisecondsTimePoint;
import com.sap.sse.common.impl.TimeRangeImpl;
import org.junit.Assert;
public class SensorFixStoreTest {
private static final long FIX_TIMESTAMP = 110;
private static final long FIX_TIMESTAMP2 = 120;
@@ -63,7 +63,7 @@ public class SensorFixStoreTest {
private void newStore() {
store = new MongoSensorFixStoreImpl(PersistenceFactory.INSTANCE.getDefaultMongoObjectFactory(),
PersistenceFactory.INSTANCE.getDefaultDomainObjectFactory(), serviceFinderFactory, WriteConcern.MAJORITY);
PersistenceFactory.INSTANCE.getDefaultDomainObjectFactory(), serviceFinderFactory, ReadConcern.MAJORITY, WriteConcern.MAJORITY);
}
@After
@@ -149,8 +149,7 @@ public class TracTracConnectivityParamsHandler extends AbstractRaceTrackingConne
final String creatorName = SessionUtils.getPrincipal().toString();
final TracTracConfigurationImpl tracTracConfiguration = new TracTracConfigurationImpl(creatorName, tractracRace.getEvent().getName(), jsonURL,
(params.getLiveURI() == null ? null : params.getLiveURI().toString()),
/* stored URI */ params.isPreferReplayIfAvailable() && params.isReplayRace(tractracRace)
? null // we mainly want to enable the user to list the event's races again in case they are removed;
/* stored URI */ params.isReplayRace(tractracRace) ? null // we mainly want to enable the user to list the event's races again in case they are removed;
: (params.getStoredURI() == null ? null : params.getStoredURI().toString()), // live/stored stuff comes from the tracking params
params.getCourseDesignUpdateURI()==null?null:params.getCourseDesignUpdateURI().toString(), params.getTracTracUsername(), params.getTracTracPassword());
tractracMongoObjectFactory.updateTracTracConfiguration(tracTracConfiguration);
@@ -56,7 +56,6 @@ public interface TracTracConfiguration extends WithQualifiedObjectIdentifier {
}
public static TypeRelativeObjectIdentifier getTypeRelativeObjectIdentifier(String jsonUrl, String username) {
return username == null ? new TypeRelativeObjectIdentifier(jsonUrl)
: new TypeRelativeObjectIdentifier(jsonUrl, username);
}
@@ -1,5 +1,7 @@
package com.sap.sailing.domain.tracking.impl;
import java.io.IOException;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collections;
@@ -7,6 +9,7 @@ import java.util.Comparator;
import java.util.LinkedList;
import java.util.List;
import java.util.ListIterator;
import java.util.NavigableSet;
import java.util.TreeSet;
import com.sap.sailing.domain.base.BoatClass;
@@ -49,7 +52,12 @@ public class CourseChangeBasedTrackApproximation implements Serializable, GPSTra
private final GPSFixTrack<Competitor, GPSFixMoving> track;
private final BoatClass boatClass;
private final FixWindow fixWindow;
private final TreeSet<GPSFixMoving> maneuverCandidates;
/**
* The following set is a {@code synchronized} navigable set; all simple access methods synchronize trivially on it.
* All iterations, including serializing this object, must {@code synchronize} on it.
*/
private final NavigableSet<GPSFixMoving> maneuverCandidates;
/**
* The fix window consists of the list of fixes, a corresponding list with the course
@@ -309,11 +317,17 @@ public class CourseChangeBasedTrackApproximation implements Serializable, GPSTra
this.track = track;
this.boatClass = boatClass;
this.fixWindow = new FixWindow();
this.maneuverCandidates = new TreeSet<>(TimedComparator.INSTANCE);
this.maneuverCandidates = Collections.synchronizedNavigableSet(new TreeSet<>(TimedComparator.INSTANCE));
track.addListener(this);
addAllFixesOfTrack();
}
private void writeObject(ObjectOutputStream oos) throws IOException {
synchronized (maneuverCandidates) {
oos.defaultWriteObject();
}
}
private synchronized void addAllFixesOfTrack() {
track.lockForRead();
try {
@@ -424,7 +438,9 @@ public class CourseChangeBasedTrackApproximation implements Serializable, GPSTra
}
}
if (from.before(to)) {
result = new ArrayList<>(maneuverCandidates.subSet(createDummyFix(from), /* fromInclusive */ true, createDummyFix(to), /* toInclusive */ true));
synchronized (maneuverCandidates) {
result = new ArrayList<>(maneuverCandidates.subSet(createDummyFix(from), /* fromInclusive */ true, createDummyFix(to), /* toInclusive */ true));
}
} else {
result = Collections.emptySet();
}
@@ -77,6 +77,9 @@ public class BoatClassImageResolver {
boatClassIconsMap.put(BoatClassMasterdata.HOBIE_TIGER.getDisplayName(), imageResources.HobieTigerIcon());
boatClassIconsMap.put(BoatClassMasterdata.HOBIE_WILD_CAT.getDisplayName(), imageResources.HobieWildCatIcon());
boatClassIconsMap.put(BoatClassMasterdata.INTERNATIONAL_14.getDisplayName(), imageResources.International14Icon());
boatClassIconsMap.put(BoatClassMasterdata.IQFOIL_MEN.getDisplayName(), imageResources.IQFOilMenIcon());
boatClassIconsMap.put(BoatClassMasterdata.IQFOIL_WOMEN.getDisplayName(), imageResources.IQFOilWoenIcon());
boatClassIconsMap.put(BoatClassMasterdata.IQFOIL_YOUTH.getDisplayName(), imageResources.IQFOilYouthIcon());
boatClassIconsMap.put(BoatClassMasterdata.J22.getDisplayName(), imageResources.J22Icon());
boatClassIconsMap.put(BoatClassMasterdata.J24.getDisplayName(), imageResources.J24Icon());
boatClassIconsMap.put(BoatClassMasterdata.J70.getDisplayName(), imageResources.J70Icon());
@@ -396,6 +396,18 @@ public interface BoatClassImageResources extends ClientBundle {
@ImageOptions(preventInlining = true)
ImageResource International14Icon();
@Source("com/sap/sailing/gwt/ui/client/images/boatclass/IQFOIL_MEN.png")
@ImageOptions(preventInlining = true)
ImageResource IQFOilMenIcon();
@Source("com/sap/sailing/gwt/ui/client/images/boatclass/IQFOIL_WOMEN.png")
@ImageOptions(preventInlining = true)
ImageResource IQFOilWoenIcon();
@Source("com/sap/sailing/gwt/ui/client/images/boatclass/IQFOIL_YOUTH.png")
@ImageOptions(preventInlining = true)
ImageResource IQFOilYouthIcon();
@Source("com/sap/sailing/gwt/ui/client/images/boatclass/OPEN_BIC.png")
@ImageOptions(preventInlining = true)
ImageResource OpenBicIcon();
@@ -74,7 +74,7 @@ public class AbstractRegattaLogFixesAddMappingsDialog extends DataEntryDialog<Co
sailingServiceWrite, stringMessages, errorReporter);
boatTable = new BoatTableWrapper<RefreshableSingleSelectionModel<BoatDTO>>(sailingServiceWrite, userService,
/* boatsRefresher not needed; registered boats taken from regatta log */ null,
/* competitorsRefresher not neede */ null, stringMessages, errorReporter, /* multiSelection */ false,
/* competitorsRefresher not needed */ null, stringMessages, errorReporter, /* multiSelection */ false,
/* enable Pager */ true, /* allowActions */ false);
registerSelectionChangeHandler(competitorTable.getSelectionModel(), this::mappedToSelectionChanged);
@@ -60,7 +60,7 @@ public abstract class AbstractRegattaLogSensorDataAddMappingsDialog extends Data
event -> deviceSelectionChanged(deviceIdTable.getSelectionModel().getSelectedObject()));
boatTable = new BoatTableWrapper<RefreshableSingleSelectionModel<BoatDTO>>(sailingServiceWrite, userService,
/* boatsRefresher not needed; registrations are fetched for the leaderboard specifically */ null,
/* competitorsRefresher not neede */ null,
/* competitorsRefresher not needed */ null,
stringMessages, errorReporter, /* multiSelection */ false, /* enable Pager */ true, /* allowActions */ false);
competitorTable = new CompetitorTableWrapper<>(sailingServiceWrite, userService,
/* competitorsRefresher not needed; registrations are fetched for the leaderboard specifically */ null,
@@ -283,7 +283,7 @@ public abstract class AbstractRegattaWithSeriesAndFleetsDialog<T> extends DataEn
sailingEventsListBox.addItem(stringMessages.selectSailingEvent(), stringMessages.selectSailingEvent());
final Iterable<EventDTO> eventsSortedByName = Util.stream(existingEvents)
.filter(event->userService.hasPermission(event, DefaultActions.UPDATE))
.sorted(Util.naturalNamedComparator())::iterator;
.sorted(Util.naturalNamedComparator(/* caseSensitive */ true))::iterator;
for (EventDTO event : eventsSortedByName) {
sailingEventsListBox.addItem(event.getName(), event.getId().toString());
if (defaultEvent != null) {
@@ -542,7 +542,7 @@ widthInPx=Bredde (pixel)
heightInPx=Højde (pixel)
tags=Tags
size=Størrelse
duration=Varighed (t:mm:ss.ms)
duration=Varighed (t:mm:ss)
addMediaTrack=Tilføj lyd/video
addYoutubeTrack=Tilføj Youtube
youtubeId=Youtube-id
@@ -542,7 +542,7 @@ widthInPx=Ancho (píxeles)
heightInPx=Alto (píxeles)
tags=Etiquetas
size=Tamaño
duration=Duración (h:mm:ss.ms)
duration=Duración (h:mm:ss)
addMediaTrack=Añadir audio/vídeo
addYoutubeTrack=Añadir Youtube
youtubeId=ID de Youtube
@@ -542,7 +542,7 @@ widthInPx=Largeur (pixel)
heightInPx=Hauteur (pixel)
tags=Balises
size=Taille
duration=Durée (h:mm:ss.ms)
duration=Durée (h:mm:ss)
addMediaTrack=Ajouter audio/vidéo
addYoutubeTrack=Ajouter Youtube
youtubeId=ID Youtube
@@ -542,7 +542,7 @@ widthInPx=Larghezza (pixel)
heightInPx=Altezza (pixel)
tags=Tags
size=Dimensione
duration=Durata (h:mm:ss.ms)
duration=Durata (h:mm:ss)
addMediaTrack=Aggiungi audio/video
addYoutubeTrack=Aggiungi Youtube
youtubeId=ID Youtube
@@ -542,7 +542,7 @@ widthInPx=幅 (ピクセル)
heightInPx=高さ (ピクセル)
tags=タグ
size=サイズ
duration=時間 (h:mm:ss.ms)
duration=時間 (h:mm:ss)
addMediaTrack=音声/動画追加
addYoutubeTrack=YouTube 追加
youtubeId=YouTube ID
@@ -542,7 +542,7 @@ widthInPx=Largura (pixels)
heightInPx=Altura (pixels)
tags=Etiquetas
size=Tamanho
duration=Duração (h:mm:ss.ms)
duration=Duração (h:mm:ss)
addMediaTrack=Adicionar áudio/vídeo
addYoutubeTrack=Adicionar Youtube
youtubeId=ID do Youtube
@@ -542,7 +542,7 @@ widthInPx=Ширина (в пикселях)
heightInPx=Высота (в пикселях)
tags=Теги
size=Размер
duration=Длительность (ч:мм:сс.мс)
duration=Длительность (ч:мм:сс)
addMediaTrack=Добавить аудио/видео
addYoutubeTrack=Добавить Youtube
youtubeId=Ид. Youtube
@@ -542,7 +542,7 @@ widthInPx=Širina (slikovne pike)
heightInPx=Višina (slikovne pike)
tags=Oznake
size=Velikost
duration=Trajanje (h:mm:ss.ms)
duration=Trajanje (h:mm:ss)
addMediaTrack=Dodaj zvok/video
addYoutubeTrack=Dodaj Youtube
youtubeId=ID za Youtube
@@ -542,7 +542,7 @@ widthInPx=宽度(像素)
heightInPx=高度(像素)
tags=标记
size=大小
duration=持续时间 (h:mm:ss.ms)
duration=持续时间 (h:mm:ss)
addMediaTrack=添加音频/视频
addYoutubeTrack=添加 Youtube
youtubeId=Youtube 编号
@@ -31,6 +31,7 @@ public class BoatClassVectorGraphicsResolver {
BoatClassMasterdata.FINN, BoatClassMasterdata.MUSTO_SKIFF, BoatClassMasterdata.OPEN_BIC,
BoatClassMasterdata.OPTIMIST, BoatClassMasterdata.PWA,
BoatClassMasterdata.RS_AERO, BoatClassMasterdata.RS_X,
BoatClassMasterdata.IQFOIL_MEN, BoatClassMasterdata.IQFOIL_WOMEN, BoatClassMasterdata.IQFOIL_YOUTH,
BoatClassMasterdata.SPLASH_BLUE, BoatClassMasterdata.SPLASH_RED, BoatClassMasterdata.SPLASH_GREEN,
BoatClassMasterdata.STAR, BoatClassMasterdata.TECHNO_293, BoatClassMasterdata.TECHNO_293_PLUS);
BoatClassVectorGraphics _49er = new _49erVectorGraphics(BoatClassMasterdata._49ER, BoatClassMasterdata._49ERFX,
Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

@@ -1,5 +1,4 @@
DELETE FROM SAILING."CompetitorRace" CASCADE;
DELETE FROM SAILING."Event" CASCADE;
DELETE FROM SAILING."RaceResult" CASCADE;
DELETE FROM SAILING."RaceStats" CASCADE;
DELETE FROM SAILING."Leg" CASCADE;
@@ -7,6 +6,7 @@ DELETE FROM SAILING."LegStats" CASCADE;
DELETE FROM SAILING."Maneuver" CASCADE;
DELETE FROM SAILING."Race" CASCADE;
DELETE FROM SAILING."Regatta" CASCADE;
DELETE FROM SAILING."Event" CASCADE;
DELETE FROM SAILING."Competitor" CASCADE;
DELETE FROM SAILING."BoatClass" CASCADE;
DELETE FROM SAILING."IRM" CASCADE;
@@ -6,7 +6,7 @@ CREATE COLUMN TABLE SAILING."Event" (
"venue" NVARCHAR(255),
"isListed" BOOLEAN,
"description" NVARCHAR(5000),
"location" ST_POINT
"location" ST_POINT(3857)
);
CREATE ROW TABLE SAILING."ScoringScheme" (
"id" NVARCHAR(255) PRIMARY KEY,
@@ -49,14 +49,14 @@ CREATE COLUMN TABLE SAILING."Race" (
FOREIGN KEY ("regatta") REFERENCES SAILING."Regatta" ("name")
);
CREATE TABLE SAILING."Competitor" (
"id" NVARCHAR(36) PRIMARY KEY,
"id" NVARCHAR(255) PRIMARY KEY,
"name" NVARCHAR(255) NOT NULL,
"shortName" NVARCHAR(20),
"nationality" NVARCHAR(3) NOT NULL,
"sailNumber" NVARCHAR(255)
);
CREATE TABLE SAILING."CompetitorRace" (
"competitorId" NVARCHAR(36),
"competitorId" NVARCHAR(255),
"race" NVARCHAR(255),
"regatta" NVARCHAR(255),
PRIMARY KEY ("competitorId", "race"),
@@ -66,7 +66,7 @@ CREATE TABLE SAILING."CompetitorRace" (
CREATE TABLE SAILING."RaceResult" (
"regatta" NVARCHAR(255) NOT NULL,
"raceColumn" NVARCHAR(255) NOT NULL,
"competitorId" NVARCHAR(36) NOT NULL,
"competitorId" NVARCHAR(255) NOT NULL,
"points" DOUBLE,
"discarded" BOOLEAN,
"irm" NVARCHAR(4),
@@ -76,7 +76,7 @@ CREATE TABLE SAILING."RaceResult" (
CREATE TABLE SAILING."RaceStats" (
"race" NVARCHAR(255) NOT NULL,
"regatta" NVARCHAR(255) NOT NULL,
"competitorId" NVARCHAR(36) NOT NULL,
"competitorId" NVARCHAR(255) NOT NULL,
"rankOneBased" INTEGER,
"distanceSailedInMeters" DOUBLE,
"elapsedTimeInSeconds" DOUBLE,
@@ -105,7 +105,7 @@ CREATE TABLE SAILING."LegStats" (
"race" NVARCHAR(255) NOT NULL,
"regatta" NVARCHAR(255) NOT NULL,
"number" INTEGER NOT NULL,
"competitorId" NVARCHAR(36) NOT NULL,
"competitorId" NVARCHAR(255) NOT NULL,
"rankOneBased" INTEGER,
"distanceSailedInMeters" DOUBLE,
"elapsedTimeInSeconds" DOUBLE,
@@ -123,7 +123,7 @@ CREATE TABLE SAILING."LegStats" (
CREATE TABLE SAILING."Maneuver" (
"race" NVARCHAR(255) NOT NULL,
"regatta" NVARCHAR(255) NOT NULL,
"competitorId" NVARCHAR(36) NOT NULL,
"competitorId" NVARCHAR(255) NOT NULL,
"timepoint" TIMESTAMP NOT NULL,
"type" NVARCHAR(20) NOT NULL,
"newTack" NVARCHAR(20),
@@ -2,11 +2,12 @@ package com.sap.sailing.hanaexport;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.Optional;
import com.sap.sailing.hanaexport.impl.HanaConnectionFactoryImpl;
public interface HanaConnectionFactory {
static HanaConnectionFactory INSTANCE = new HanaConnectionFactoryImpl();
Connection getConnection() throws SQLException;
Connection getConnection(Optional<String> dbEndpoint, Optional<String> dbUser, Optional<String> dbPassword) throws SQLException;
}
@@ -6,6 +6,7 @@ import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Optional;
import java.util.logging.Logger;
import com.sap.sailing.domain.common.BoatClassMasterdata;
@@ -20,7 +21,7 @@ public class HanaConnectionFactoryImpl implements HanaConnectionFactory {
public void test() throws SQLException {
System.out.println("Java version: " + com.sap.db.jdbc.Driver.getJavaVersion());
System.out.println("Minimum supported Java version and SAP driver version number: " + com.sap.db.jdbc.Driver.getVersionInfo());
final Connection connection = getConnection();
final Connection connection = getConnection(Optional.empty(), Optional.empty(), Optional.empty());
if (connection == null) {
logger.warning("Couldn't get database connection for end point "+System.getProperty(HANADB_ENDPOINT_PROPERTY_NAME));
} else {
@@ -42,11 +43,33 @@ public class HanaConnectionFactoryImpl implements HanaConnectionFactory {
}
@Override
public Connection getConnection() throws SQLException {
public Connection getConnection(Optional<String> dbEndpoint, Optional<String> dbUser, Optional<String> dbPassword) throws SQLException {
final String dbEndpointFromSystemProperty = System.getProperty(HANADB_ENDPOINT_PROPERTY_NAME);
final String dbUserFromSystemProperty = System.getProperty(HANADB_USERNAME_SYSTEM_PROPERTY_NAME);
final String dbPasswordFromSystemProperty = System.getProperty(HANADB_PASSWORD_SYSTEM_PROPERTY_NAME);
final String dbUrl = "jdbc:sap://"+dbEndpoint.orElseGet(()->{
if (dbEndpointFromSystemProperty != null) {
return dbEndpointFromSystemProperty;
} else {
throw new IllegalStateException("Missing DB URL, either as parameter or from system property "+HANADB_ENDPOINT_PROPERTY_NAME);
}
});
return DriverManager.getConnection(
"jdbc:sap://"+System.getProperty(HANADB_ENDPOINT_PROPERTY_NAME)+"/?encrypt=true&validateCertificate=false",
System.getProperty(HANADB_USERNAME_SYSTEM_PROPERTY_NAME),
System.getProperty(HANADB_PASSWORD_SYSTEM_PROPERTY_NAME));
dbUrl,
dbUser.orElseGet(()->{
if (dbUserFromSystemProperty != null) {
return dbUserFromSystemProperty;
} else {
throw new IllegalStateException("Missing DB user name, either as parameter or from system property "+HANADB_USERNAME_SYSTEM_PROPERTY_NAME);
}
}),
dbPassword.orElseGet(()->{
if (dbPasswordFromSystemProperty != null) {
return dbPasswordFromSystemProperty;
} else {
throw new IllegalStateException("Missing DB password, either as parameter or from system property "+HANADB_PASSWORD_SYSTEM_PROPERTY_NAME);
}
}));
}
public static void main(String[] args) throws SQLException {
@@ -0,0 +1,40 @@
package com.sap.sailing.hanaexport.jaxrs.api;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import com.sap.sse.common.Distance;
import com.sap.sse.common.Duration;
public abstract class AbstractPreparedInsertStatement<T> implements PreparedInsertStatement<T> {
private final PreparedStatement preparedStatement;
protected AbstractPreparedInsertStatement(PreparedStatement preparedStatement) {
this.preparedStatement = preparedStatement;
}
@Override
public PreparedStatement getPreparedStatement() {
return preparedStatement;
}
protected void setDouble(int parameterIndex, double value) throws SQLException {
if (Double.isNaN(value) || Double.isInfinite(value)) {
setDouble(parameterIndex, 0.0);
} else {
getPreparedStatement().setDouble(parameterIndex, value);
}
}
protected int intOr0ForNull(Integer i) {
return i==null?0:i;
}
protected double metersOr0ForNull(final Distance distance) {
return distance == null ? 0 : distance.getMeters();
}
protected double secondsOr0ForNull(final Duration duration) {
return duration == null ? 0 : duration.asSeconds();
}
}
@@ -3,14 +3,18 @@ package com.sap.sailing.hanaexport.jaxrs.api;
import java.io.IOException;
import java.io.StringWriter;
import java.sql.Connection;
import java.sql.Date;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.util.Arrays;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.NavigableSet;
import java.util.List;
import java.util.Optional;
import java.util.Set;
import java.util.UUID;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.ws.rs.FormParam;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
@@ -20,40 +24,30 @@ import javax.ws.rs.core.Response;
import org.apache.commons.io.IOUtils;
import org.apache.shiro.SecurityUtils;
import com.sap.sailing.domain.base.BoatClass;
import com.sap.sailing.domain.base.Competitor;
import com.sap.sailing.domain.base.CompetitorWithBoat;
import com.sap.sailing.domain.base.Event;
import com.sap.sailing.domain.base.Fleet;
import com.sap.sailing.domain.base.RaceColumn;
import com.sap.sailing.domain.base.Regatta;
import com.sap.sailing.domain.base.SpeedWithConfidence;
import com.sap.sailing.domain.base.Waypoint;
import com.sap.sailing.domain.common.LegType;
import com.sap.sailing.domain.common.ManeuverType;
import com.sap.sailing.domain.common.MaxPointsReason;
import com.sap.sailing.domain.common.NoWindException;
import com.sap.sailing.domain.common.Position;
import com.sap.sailing.domain.common.ScoringSchemeType;
import com.sap.sailing.domain.common.Tack;
import com.sap.sailing.domain.leaderboard.Leaderboard;
import com.sap.sailing.domain.leaderboard.LeaderboardGroup;
import com.sap.sailing.domain.leaderboard.RegattaLeaderboard;
import com.sap.sailing.domain.leaderboard.ScoringScheme;
import com.sap.sailing.domain.leaderboard.caching.LeaderboardDTOCalculationReuseCache;
import com.sap.sailing.domain.ranking.RankingMetric.RankingInfo;
import com.sap.sailing.domain.tracking.Maneuver;
import com.sap.sailing.domain.tracking.MarkPassing;
import com.sap.sailing.domain.tracking.TrackedLeg;
import com.sap.sailing.domain.tracking.TrackedLegOfCompetitor;
import com.sap.sailing.domain.tracking.TrackedRace;
import com.sap.sailing.domain.tracking.WindLegTypeAndLegBearingAndORCPerformanceCurveCache;
import com.sap.sailing.domain.tracking.WindPositionMode;
import com.sap.sailing.hanaexport.HanaConnectionFactory;
import com.sap.sailing.hanaexport.jaxrs.api.InsertRegattaStatement.RegattaAndEvent;
import com.sap.sailing.server.interfaces.RacingEventService;
import com.sap.sailing.shared.server.gateway.jaxrs.SharedAbstractSailingServerResource;
import com.sap.sse.ServerInfo;
import com.sap.sse.common.Distance;
import com.sap.sse.common.Duration;
import com.sap.sse.common.Speed;
import com.sap.sse.common.TimePoint;
import com.sap.sse.common.Util;
import com.sap.sse.security.shared.TypeRelativeObjectIdentifier;
@@ -63,37 +57,72 @@ import com.sap.sse.security.shared.impl.SecuredSecurityTypes;
public class HanaCloudSacExportResource extends SharedAbstractSailingServerResource {
private static final Logger logger = Logger.getLogger(HanaCloudSacExportResource.class.getName());
private class AlreadyInsertedContent {
private final Set<Event> events;
private final Set<Competitor> competitors;
private final InsertCompetitorStatement insertCompetitors;
private final InsertEventStatement insertEvents;
public AlreadyInsertedContent(InsertEventStatement insertEvents, InsertCompetitorStatement insertCompetitors) {
events = new HashSet<>();
competitors = new HashSet<>();
this.insertEvents = insertEvents;
this.insertCompetitors = insertCompetitors;
}
public void ensureEventIsInserted(Event event) throws SQLException {
if (!events.contains(event)) {
events.add(event);
insertEvents.insert(event);
}
}
public void ensureCompetitorIsInserted(Competitor competitor) throws SQLException {
if (!competitors.contains(competitor)) {
competitors.add(competitor);
insertCompetitors.insert(competitor);
}
}
}
@POST
@Produces("application/json;charset=UTF-8")
@Path("clear")
public Response clear() throws SQLException, IOException {
public Response clear(
@FormParam("dbendpoint") String dbEndpoint,
@FormParam("dbuser") String dbUser,
@FormParam("dbpassword") String dbPassword) throws SQLException, IOException {
SecurityUtils.getSubject().checkPermission(SecuredSecurityTypes.SERVER.getStringPermissionForTypeRelativeIdentifier(
SecuredSecurityTypes.ServerActions.CAN_EXPORT_MASTERDATA,
new TypeRelativeObjectIdentifier(ServerInfo.getName())));
logger.info("Clearing HANA Cloud SAILING DB on behalf of user "+SecurityUtils.getSubject().getPrincipal());
final Connection connection = HanaConnectionFactory.INSTANCE.getConnection();
final Connection connection = HanaConnectionFactory.INSTANCE.getConnection(Optional.ofNullable(dbEndpoint),
Optional.ofNullable(dbUser), Optional.ofNullable(dbPassword));
tryExecutingQueriesFromSqlResource("/cleartables.sql", connection);
logger.info("Done learing HANA Cloud SAILING DB on behalf of user "+SecurityUtils.getSubject().getPrincipal());
logger.info("Done clearing HANA Cloud SAILING DB on behalf of user "+SecurityUtils.getSubject().getPrincipal());
return Response.ok().build();
}
@POST
@Produces("application/json;charset=UTF-8")
@Path("export")
public Response export() throws SQLException {
public Response export(@QueryParam("leaderboardgroupid") List<String> leaderboardGroupIds,
@QueryParam("eventid") List<String> eventIds,
@FormParam("dbendpoint") String dbEndpoint,
@FormParam("dbuser") String dbUser,
@FormParam("dbpassword") String dbPassword) throws SQLException {
SecurityUtils.getSubject().checkPermission(SecuredSecurityTypes.SERVER.getStringPermissionForTypeRelativeIdentifier(
SecuredSecurityTypes.ServerActions.CAN_EXPORT_MASTERDATA,
new TypeRelativeObjectIdentifier(ServerInfo.getName())));
logger.info("Exporting HANA Cloud SAILING DB content on behalf of user "+SecurityUtils.getSubject().getPrincipal());
final RacingEventService racingEventService = getService();
try {
final Connection connection = HanaConnectionFactory.INSTANCE.getConnection();
final Connection connection = HanaConnectionFactory.INSTANCE.getConnection(Optional.ofNullable(dbEndpoint),
Optional.ofNullable(dbUser), Optional.ofNullable(dbPassword));
exportBoatClasses(racingEventService, connection);
exportIrms(racingEventService, connection);
exportScoringSchemes(racingEventService, connection);
exportCompetitors(racingEventService, connection);
exportEvents(racingEventService, connection);
exportRaces(racingEventService, connection);
final Iterable<Regatta> regattasToExport = getRegattasToExport(racingEventService, leaderboardGroupIds, eventIds);
exportRaces(racingEventService, regattasToExport, connection);
} catch (Exception e) {
logger.log(Level.SEVERE, "Problem exporting data to HANA", e);
throw e;
@@ -102,356 +131,148 @@ public class HanaCloudSacExportResource extends SharedAbstractSailingServerResou
return Response.ok().build();
}
private void exportCompetitors(RacingEventService racingEventService, Connection connection) throws SQLException {
final PreparedStatement insertCompetitors = connection.prepareStatement(
"INSERT INTO SAILING.\"Competitor\" (\"id\", \"name\", \"shortName\", \"nationality\", \"sailNumber\") VALUES (?, ?, ?, ?, ?);");
for (final Competitor competitor : racingEventService.getCompetitorAndBoatStore().getAllCompetitors()) {
insertCompetitors.setString(1, competitor.getId().toString());
insertCompetitors.setString(2, competitor.getName());
insertCompetitors.setString(3, competitor.getShortName());
insertCompetitors.setString(4, competitor.getNationality() == null ? " " : competitor.getNationality().getThreeLetterIOCAcronym());
insertCompetitors.setString(5, competitor.hasBoat() ? ((CompetitorWithBoat) competitor).getBoat().getSailID() : null);
insertCompetitors.execute();
private Iterable<Regatta> getRegattasToExport(RacingEventService racingEventService, List<String> leaderboardGroupIds, List<String> eventIds) {
final Set<LeaderboardGroup> leaderboardGroups = new HashSet<>();
final Iterable<Regatta> result;
boolean atLeastOneIdProvided = false;
if (leaderboardGroupIds != null) {
for (final String leaderboardGroupIdAsString : leaderboardGroupIds) {
atLeastOneIdProvided = true;
try {
leaderboardGroups.add(racingEventService.getLeaderboardGroupByID(UUID.fromString(leaderboardGroupIdAsString)));
} catch (IllegalArgumentException e) {
logger.log(Level.WARNING, "Couldn't parse "+leaderboardGroupIdAsString+" as a leaderboard group's UUID. Ignoring.");
}
}
}
if (eventIds != null) {
for (final String eventIdAsString : eventIds) {
atLeastOneIdProvided = true;
try {
final Event event = racingEventService.getEvent(UUID.fromString(eventIdAsString));
Util.addAll(event.getLeaderboardGroups(), leaderboardGroups);
} catch (IllegalArgumentException e) {
logger.log(Level.WARNING, "Couldn't parse "+eventIdAsString+" as an event's UUID. Ignoring.");
}
}
}
if (atLeastOneIdProvided) {
final Set<Regatta> resultSet = new HashSet<>();
for (final LeaderboardGroup leaderboardGroup : leaderboardGroups) {
for (final Leaderboard leaderboard : leaderboardGroup.getLeaderboards()) {
if (leaderboard.getLeaderboardType().isRegattaLeaderboard()) {
resultSet.add(((RegattaLeaderboard) leaderboard).getRegatta());
}
}
}
result = resultSet;
} else {
result = racingEventService.getAllRegattas();
}
return result;
}
private void exportIrms(RacingEventService racingEventService, Connection connection) throws SQLException {
final PreparedStatement insertBoatClasses = connection.prepareStatement(
"INSERT INTO SAILING.\"IRM\" (\"name\", \"discardable\", \"advanceCompetitorsTrackedWorse\", \"appliesAtStartOfRace\") VALUES (?, ?, ?, ?);");
for (final MaxPointsReason irm : MaxPointsReason.values()) {
insertBoatClasses.setString(1, irm.name());
insertBoatClasses.setBoolean(2, irm.isDiscardable());
insertBoatClasses.setBoolean(3, irm.isAdvanceCompetitorsTrackedWorse());
insertBoatClasses.setBoolean(4, irm.isAppliesAtStartOfRace());
insertBoatClasses.execute();
}
final InsertIrmStatement insertIrms = new InsertIrmStatement(connection);
insertIrms.insertBatch(Arrays.asList(MaxPointsReason.values()));
insertIrms.executeBatch();
}
private void exportScoringSchemes(RacingEventService racingEventService, Connection connection) throws SQLException {
final PreparedStatement insertBoatClasses = connection.prepareStatement(
"INSERT INTO SAILING.\"ScoringScheme\" (\"id\", \"higherIsBetter\") VALUES (?, ?);");
final InsertScoringSchemeStatement insertScoringScheme = new InsertScoringSchemeStatement(connection);
for (final ScoringSchemeType scoringSchemeType : ScoringSchemeType.values()) {
final ScoringScheme scoringScheme = racingEventService.getBaseDomainFactory().createScoringScheme(scoringSchemeType);
insertBoatClasses.setString(1, scoringScheme.getType().name());
insertBoatClasses.setBoolean(2, scoringScheme.isHigherBetter());
insertBoatClasses.execute();
insertScoringScheme.insertBatch(scoringScheme);
}
insertScoringScheme.executeBatch();
}
private void exportBoatClasses(final RacingEventService racingEventService, final Connection connection)
throws SQLException {
final PreparedStatement insertBoatClasses = connection.prepareStatement(
"INSERT INTO SAILING.\"BoatClass\" (\"id\", \"description\", \"hullLengthInMeters\", \"hullBeamInMeters\", \"hullType\") VALUES (?, ?, ?, ?, ?);");
for (final BoatClass boatClass : racingEventService.getBaseDomainFactory().getBoatClasses()) {
if (boatClass.getName() == null) {
insertBoatClasses.setString(1, "<null>");
} else {
insertBoatClasses.setString(1, boatClass.getName().substring(0, Math.min(boatClass.getName().length(), 255)));
}
insertBoatClasses.setString(2, "Type "+boatClass.getHullType().name()+", length "+
boatClass.getHullLength().getMeters()+"m, beam "+boatClass.getHullBeam().getMeters()+"m");
setDouble(insertBoatClasses, 3, boatClass.getHullLength().getMeters());
setDouble(insertBoatClasses, 4, boatClass.getHullBeam().getMeters());
insertBoatClasses.setString(5, boatClass.getHullType().name());
insertBoatClasses.execute();
}
final InsertBoatClassStatement insertBoatClasses = new InsertBoatClassStatement(connection);
insertBoatClasses.insertBatch(racingEventService.getBaseDomainFactory().getBoatClasses());
insertBoatClasses.executeBatch();
}
private void exportEvents(RacingEventService racingEventService, Connection connection) throws SQLException {
final PreparedStatement insertEvents = connection.prepareStatement(
"INSERT INTO SAILING.\"Event\" (\"id\", \"name\", \"startDate\", \"endDate\", \"venue\", \"isListed\", \"description\", \"location\") "+
"VALUES (?, ?, ?, ?, ?, ?, ?, NEW ST_POINT(?));");
for (final Event event : racingEventService.getAllEvents()) {
insertEvents.setString(1, event.getId().toString());
insertEvents.setString(2, event.getName());
insertEvents.setDate(3, event.getStartDate()==null?null:new Date(event.getStartDate().asMillis()));
insertEvents.setDate(4, event.getEndDate()==null?null:new Date(event.getEndDate().asMillis()));
insertEvents.setString(5, event.getVenue().getName());
insertEvents.setBoolean(6, event.isPublic());
insertEvents.setString(7, event.getDescription());
final Position location = event.getLocation();
insertEvents.setString(8, location != null ? String.format("POINT(%1.5f %1.5f)", location.getLatDeg(), location.getLngDeg()) : null);
insertEvents.execute();
}
}
private void exportRaces(RacingEventService racingEventService, Connection connection) throws SQLException {
private void exportRaces(RacingEventService racingEventService, Iterable<Regatta> regattasToExport, Connection connection) throws SQLException {
final TimePoint now = TimePoint.now();
final PreparedStatement insertRegattas = connection.prepareStatement(
"INSERT INTO SAILING.\"Regatta\" (\"name\", \"boatClass\", \"scoringScheme\", \"rankingMetric\", \"eventId\") "+
"VALUES (?, ?, ?, ?, ?);");
final PreparedStatement insertRaces = connection.prepareStatement(
"INSERT INTO SAILING.\"Race\" (\"name\", \"regatta\", \"raceColumn\", \"fleet\", \"startOfTracking\", "+
"\"startOfRace\", \"endOfTracking\", \"endOfRace\", \"avgWindSpeedInKnots\") "+
"VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?);");
final PreparedStatement insertRaceResults = connection.prepareStatement(
"INSERT INTO SAILING.\"RaceResult\" (\"regatta\", \"raceColumn\", \"competitorId\", \"points\", "+
"\"discarded\", \"irm\") "+
"VALUES (?, ?, ?, ?, ?, ?);");
final PreparedStatement insertRaceStats = connection.prepareStatement(
"INSERT INTO SAILING.\"RaceStats\" (\"race\", \"regatta\", \"competitorId\", \"rankOneBased\", \"distanceSailedInMeters\", \"elapsedTimeInSeconds\", "+
"\"avgCrossTrackErrorInMeters\", \"absoluteAvgCrossTrackErrorInMeters\", \"numberOfTacks\", "+
"\"numberOfGybes\", \"numberOfPenaltyCircles\", \"startDelayInSeconds\", \"distanceFromStartLineInMetersAtStart\", "+
"\"speedWhenCrossingStartLineInKnots\", \"startTack\") "+
"VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?);");
final PreparedStatement insertLegs = connection.prepareStatement(
"INSERT INTO SAILING.\"Leg\" (\"race\", \"regatta\", \"number\", \"type\") "+
"VALUES (?, ?, ?, ?);");
final PreparedStatement insertLegStats = connection.prepareStatement(
"INSERT INTO SAILING.\"LegStats\" (\"race\", \"regatta\", \"number\", \"competitorId\", \"rankOneBased\", \"distanceSailedInMeters\", \"elapsedTimeInSeconds\", "+
"\"avgCrossTrackErrorInMeters\", \"absoluteAvgCrossTrackErrorInMeters\", \"numberOfTacks\", "+
"\"numberOfGybes\", \"numberOfPenaltyCircles\", \"avgVelocityMadeGoodInKnots\", \"gapToLeaderInSeconds\") "+
"VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?);");
final PreparedStatement insertManeuvers = connection.prepareStatement(
"INSERT INTO SAILING.\"Maneuver\" (\"race\", \"regatta\", \"competitorId\", \"timepoint\", \"type\", \"newTack\", "+
"\"lossInMeters\", \"speedBeforeInKnots\", \"speedAfterInKnots\", "+
"\"courseBeforeInTrueDegrees\", \"courseAfterInTrueDegrees\", \"directionChangeInDegrees\", \"maximumTurningRateInDegreesPerSecond\", "+
"\"lowestSpeedInKnots\", \"toSide\") "+
"VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?);");
for (final Regatta regatta : racingEventService.getAllRegattas()) {
final InsertEventStatement insertEvents = new InsertEventStatement(connection);
final InsertCompetitorStatement insertCompetitors = new InsertCompetitorStatement(connection);
final AlreadyInsertedContent alreadyInsertedContent = new AlreadyInsertedContent(insertEvents, insertCompetitors);
final InsertRegattaStatement insertRegattas = new InsertRegattaStatement(connection);
final InsertRaceStatement insertRaces = new InsertRaceStatement(connection);
final InsertRaceResultStatement insertRaceResults = new InsertRaceResultStatement(connection);
final InsertRaceStatsStatement insertRaceStats = new InsertRaceStatsStatement(connection);
final InsertLegStatement insertLegs = new InsertLegStatement(connection);
final InsertLegStatsStatement insertLegStats = new InsertLegStatsStatement(connection);
final InsertManeuverStatement insertManeuvers = new InsertManeuverStatement(connection);
for (final Regatta regatta : regattasToExport) {
final Leaderboard leaderboard = racingEventService.getLeaderboardByName(regatta.getName());
if (leaderboard != null) {
final Event event = racingEventService.findEventContainingLeaderboardAndMatchingAtLeastOneCourseArea(leaderboard);
insertRegattas.setString(1, regatta.getName());
insertRegattas.setString(2, regatta.getBoatClass().getName());
insertRegattas.setString(3, regatta.getScoringScheme().getType().name());
insertRegattas.setString(4, regatta.getRankingMetricType().name());
insertRegattas.setString(5, event == null ? null : event.getId().toString());
insertRegattas.execute();
if (leaderboard != null) {
for (final RaceColumn raceColumn : leaderboard.getRaceColumns()) {
for (final Competitor competitor : raceColumn.getAllCompetitors()) {
parameterizeInsertRaceResult(insertRaceResults, now, competitor, leaderboard, raceColumn, regatta);
insertRaceResults.addBatch();
}
insertRaceResults.executeBatch();
for (final Fleet fleet : raceColumn.getFleets()) {
final TrackedRace trackedRace = raceColumn.getTrackedRace(fleet);
if (trackedRace != null) {
final RankingInfo rankingInfo = trackedRace.getRankingMetric().getRankingInfo(now);
final WindLegTypeAndLegBearingAndORCPerformanceCurveCache cache = new LeaderboardDTOCalculationReuseCache(now);
parameterizeInsertRacesStatement(insertRaces, regatta, raceColumn, fleet, trackedRace);
insertRaces.addBatch();
for (final TrackedLeg trackedLeg : trackedRace.getTrackedLegs()) {
parameterizeInsertLegsStatement(insertLegs, now, regatta, trackedRace, trackedLeg);
insertLegs.addBatch();
for (final Competitor competitor : trackedRace.getRace().getCompetitors()) {
parameterizeInsertLegStatsStatement(insertLegStats, now, trackedLeg.getTrackedLeg(competitor), rankingInfo, cache);
insertLegStats.addBatch();
}
}
if (event != null) {
alreadyInsertedContent.ensureEventIsInserted(event);
insertRegattas.insert(new RegattaAndEvent(regatta, event));
if (leaderboard != null) {
for (final RaceColumn raceColumn : leaderboard.getRaceColumns()) {
for (final Competitor competitor : raceColumn.getAllCompetitors()) {
alreadyInsertedContent.ensureCompetitorIsInserted(competitor);
insertRaceResults.insertBatch(new InsertRaceResultStatement.RaceResult(regatta, leaderboard, competitor, raceColumn, now));
}
final Waypoint startWaypoint = trackedRace == null ? null : trackedRace.getRace().getCourse().getFirstWaypoint();
if (trackedRace != null) {
for (final Competitor competitor : trackedRace.getRace().getCompetitors()) {
parameterizeInsertRaceStats(insertRaceStats, now, startWaypoint, competitor, trackedRace);
insertRaceStats.addBatch();
final LinkedHashMap<TimePoint, Maneuver> timepointUniqueManeuvers = new LinkedHashMap<>();
for (final Maneuver maneuver : trackedRace.getManeuvers(competitor, /* waitForLatest */ false)) {
if (maneuver.getType() == ManeuverType.TACK || maneuver.getType() == ManeuverType.JIBE || maneuver.getType() == ManeuverType.PENALTY_CIRCLE) {
timepointUniqueManeuvers.put(maneuver.getTimePoint(), maneuver);
insertRaceResults.executeBatch();
for (final Fleet fleet : raceColumn.getFleets()) {
final TrackedRace trackedRace = raceColumn.getTrackedRace(fleet);
if (trackedRace != null) {
final RankingInfo rankingInfo = trackedRace.getRankingMetric().getRankingInfo(now);
final WindLegTypeAndLegBearingAndORCPerformanceCurveCache cache = new LeaderboardDTOCalculationReuseCache(now);
insertRaces.insertBatch(new InsertRaceStatement.TrackedRaceWithRaceColumnAndFleet(trackedRace, raceColumn, fleet));
for (final TrackedLeg trackedLeg : trackedRace.getTrackedLegs()) {
insertLegs.insertBatch(new InsertLegStatement.TrackedLegAndNow(now, trackedLeg));
for (final Competitor competitor : trackedRace.getRace().getCompetitors()) {
insertLegStats.insertBatch(new InsertLegStatsStatement.TrackedLegOfCompetitorRankingInfoCacheAndNow(now, rankingInfo, cache, trackedLeg.getTrackedLeg(competitor)));
}
}
for (final Maneuver maneuver : timepointUniqueManeuvers.values()) {
parameterizeInsertManeuvers(insertManeuvers, competitor, maneuver, trackedRace);
insertManeuvers.addBatch();
}
final Waypoint startWaypoint = trackedRace == null ? null : trackedRace.getRace().getCourse().getFirstWaypoint();
if (trackedRace != null) {
for (final Competitor competitor : trackedRace.getRace().getCompetitors()) {
insertRaceStats.insertBatch(new InsertRaceStatsStatement.TrackedRaceWithCompetitorAndStartWaypoint(now, startWaypoint, competitor, trackedRace));
final LinkedHashMap<TimePoint, Maneuver> timepointUniqueManeuvers = new LinkedHashMap<>();
for (final Maneuver maneuver : trackedRace.getManeuvers(competitor, /* waitForLatest */ false)) {
if (maneuver.getType() == ManeuverType.TACK || maneuver.getType() == ManeuverType.JIBE || maneuver.getType() == ManeuverType.PENALTY_CIRCLE) {
timepointUniqueManeuvers.put(maneuver.getTimePoint(), maneuver);
}
}
for (final Maneuver maneuver : timepointUniqueManeuvers.values()) {
insertManeuvers.insertBatch(new InsertManeuverStatement.ManeuverTrackedRaceAndCompetitor(maneuver, trackedRace, competitor));
}
}
}
}
insertRaces.executeBatch();
insertLegs.executeBatch();
insertLegStats.executeBatch();
insertRaceStats.executeBatch();
insertManeuvers.executeBatch();
}
insertRaces.executeBatch();
insertLegs.executeBatch();
insertLegStats.executeBatch();
insertRaceStats.executeBatch();
insertManeuvers.executeBatch();
}
}
}
}
}
private void parameterizeInsertManeuvers(PreparedStatement insertManeuvers, Competitor competitor, Maneuver maneuver, TrackedRace trackedRace) throws SQLException {
insertManeuvers.setString(1, trackedRace.getRace().getName());
insertManeuvers.setString(2, trackedRace.getTrackedRegatta().getRegatta().getName());
insertManeuvers.setString(3, competitor.getId().toString());
insertManeuvers.setDate(4, new Date(maneuver.getTimePoint().asMillis()));
insertManeuvers.setString(5, maneuver.getType().name());
insertManeuvers.setString(6, maneuver.getNewTack().name());
if (maneuver.getManeuverLoss() != null) {
setDouble(insertManeuvers, 7,
maneuver.getManeuverLoss().getDistanceSailedIfNotManeuveringProjectedOnMiddleManeuverAngle().getMeters()
-maneuver.getManeuverLoss().getDistanceSailedProjectedOnMiddleManeuverAngle().getMeters());
} else {
setDouble(insertManeuvers, 7, 0);
}
setDouble(insertManeuvers, 8, maneuver.getSpeedWithBearingBefore().getKnots());
setDouble(insertManeuvers, 9, maneuver.getSpeedWithBearingAfter().getKnots());
setDouble(insertManeuvers, 10, maneuver.getSpeedWithBearingBefore().getBearing().getDegrees());
setDouble(insertManeuvers, 11, maneuver.getSpeedWithBearingAfter().getBearing().getDegrees());
setDouble(insertManeuvers, 12, maneuver.getDirectionChangeInDegrees());
setDouble(insertManeuvers, 13, maneuver.getMaxTurningRateInDegreesPerSecond());
setDouble(insertManeuvers, 14, maneuver.getLowestSpeed().getKnots());
insertManeuvers.setString(15, maneuver.getToSide().name());
}
private void parameterizeInsertLegStatsStatement(PreparedStatement insertLegStats, TimePoint now,
TrackedLegOfCompetitor trackedLegOfCompetitor, RankingInfo rankingInfo, WindLegTypeAndLegBearingAndORCPerformanceCurveCache cache) throws SQLException {
insertLegStats.setString(1, trackedLegOfCompetitor.getTrackedLeg().getTrackedRace().getRace().getName());
insertLegStats.setString(2, trackedLegOfCompetitor.getTrackedLeg().getTrackedRace().getTrackedRegatta().getRegatta().getName());
insertLegStats.setInt(3, trackedLegOfCompetitor.getTrackedLeg().getLeg().getZeroBasedIndexOfStartWaypoint());
insertLegStats.setString(4, trackedLegOfCompetitor.getCompetitor().getId().toString());
insertLegStats.setInt(5, trackedLegOfCompetitor.getRank(now));
setDouble(insertLegStats, 6, metersOr0ForNull(trackedLegOfCompetitor.getDistanceTraveled(now)));
setDouble(insertLegStats, 7, secondsOr0ForNull(trackedLegOfCompetitor.getTime(now)));
setDouble(insertLegStats, 8, metersOr0ForNull(trackedLegOfCompetitor.getAverageSignedCrossTrackError(now, /* waitForLatest */ false)));
setDouble(insertLegStats, 9, metersOr0ForNull(trackedLegOfCompetitor.getAverageAbsoluteCrossTrackError(now, /* waitForLatest */ false)));
try {
insertLegStats.setInt(10, intOr0ForNull(trackedLegOfCompetitor.getNumberOfTacks(now, /* waitForLatest */ false)));
insertLegStats.setInt(11, intOr0ForNull(trackedLegOfCompetitor.getNumberOfJibes(now, /* waitForLatest */ false)));
insertLegStats.setInt(12, intOr0ForNull(trackedLegOfCompetitor.getNumberOfPenaltyCircles(now, /* waitForLatest */ false)));
} catch (NoWindException nwe) {
insertLegStats.setInt(10, 0);
insertLegStats.setInt(11, 0);
insertLegStats.setInt(12, 0);
}
final Speed vmg = trackedLegOfCompetitor.getAverageVelocityMadeGood(now);
setDouble(insertLegStats, 13, vmg==null?0:vmg.getKnots());
setDouble(insertLegStats, 14, secondsOr0ForNull(trackedLegOfCompetitor.getGapToLeader(now, WindPositionMode.LEG_MIDDLE, rankingInfo, cache)));
}
private int intOr0ForNull(Integer i) {
return i==null?0:i;
}
private void parameterizeInsertLegsStatement(PreparedStatement insertLegs, TimePoint now, Regatta regatta, TrackedRace trackedRace, TrackedLeg trackedLeg) throws SQLException {
insertLegs.setString(1, trackedRace.getRace().getName());
insertLegs.setString(2, trackedRace.getTrackedRegatta().getRegatta().getName());
insertLegs.setInt(3, trackedLeg.getLeg().getZeroBasedIndexOfStartWaypoint());
final LegType legType;
try {
legType = trackedLeg.getLegType(now);
insertLegs.setString(4, legType.name());
} catch (NoWindException nwe) {
insertLegs.setString(4, null);
}
}
private void parameterizeInsertRaceStats(PreparedStatement insertRaceStats, TimePoint now, Waypoint startWaypoint,
Competitor competitor, TrackedRace trackedRace) throws SQLException {
insertRaceStats.setString(1, trackedRace.getRace().getName());
insertRaceStats.setString(2, trackedRace.getTrackedRegatta().getRegatta().getName());
insertRaceStats.setString(3, competitor.getId().toString());
insertRaceStats.setInt(4, trackedRace.getRank(competitor, now));
setDouble(insertRaceStats, 5, metersOr0ForNull(trackedRace.getDistanceTraveled(competitor, now)));
setDouble(insertRaceStats, 6, secondsOr0ForNull(trackedRace.getTimeSailedSinceRaceStart(competitor, now)));
setDouble(insertRaceStats, 7, metersOr0ForNull(trackedRace.getAverageSignedCrossTrackError(competitor, now, /* waitForLatest */ false)));
setDouble(insertRaceStats, 8, metersOr0ForNull(trackedRace.getAverageAbsoluteCrossTrackError(competitor, now, /* waitForLatest */ false)));
final Iterable<Maneuver> maneuvers = trackedRace.getManeuvers(competitor, /* waitForLatest */ false);
insertRaceStats.setInt(9, Util.size(Util.filter(maneuvers, m->m.getType() == ManeuverType.TACK)));
insertRaceStats.setInt(10, Util.size(Util.filter(maneuvers, m->m.getType() == ManeuverType.JIBE)));
insertRaceStats.setInt(11, Util.size(Util.filter(maneuvers, m->m.getType() == ManeuverType.PENALTY_CIRCLE)));
final TimePoint startOfRace = trackedRace.getStartOfRace();
final double startDelay;
Tack startTack;
if (startWaypoint != null && startOfRace != null) {
NavigableSet<MarkPassing> competitorMarkPassings = trackedRace.getMarkPassings(competitor);
trackedRace.lockForRead(competitorMarkPassings);
try {
if (!Util.isEmpty(competitorMarkPassings)) {
final MarkPassing competitorStartMarkPassing = competitorMarkPassings.iterator().next();
final TimePoint competitorStartTime = competitorStartMarkPassing.getTimePoint();
startDelay = secondsOr0ForNull(startOfRace.until(competitorStartTime));
try {
startTack = trackedRace.getTack(competitor, competitorStartTime);
} catch (NoWindException e) {
startTack = null;
}
} else {
startDelay = 0;
startTack = null;
}
} finally {
trackedRace.unlockAfterRead(competitorMarkPassings);
}
} else {
startDelay = 0;
startTack = null;
}
setDouble(insertRaceStats, 12, startDelay);
if (startOfRace != null) {
setDouble(insertRaceStats, 13, metersOr0ForNull(trackedRace.getDistanceToStartLine(competitor, startOfRace)));
final Speed speedWhenCrossingStartLine = trackedRace.getSpeedWhenCrossingStartLine(competitor);
setDouble(insertRaceStats, 14, speedWhenCrossingStartLine==null?0:speedWhenCrossingStartLine.getKnots());
insertRaceStats.setString(15, startTack==null?null:startTack.name());
} else {
setDouble(insertRaceStats, 13, 0);
setDouble(insertRaceStats, 14, 0);
}
}
private double metersOr0ForNull(final Distance distance) {
return distance == null ? 0 : distance.getMeters();
}
private double secondsOr0ForNull(final Duration duration) {
return duration == null ? 0 : duration.asSeconds();
}
private void parameterizeInsertRaceResult(PreparedStatement insertRaceResults, TimePoint now,
Competitor competitor, Leaderboard leaderboard, RaceColumn raceColumn, Regatta regatta) throws SQLException {
insertRaceResults.setString(1, regatta.getName());
insertRaceResults.setString(2, raceColumn.getName());
insertRaceResults.setString(3, competitor.getId().toString());
final Double totalPoints = leaderboard.getTotalPoints(competitor, raceColumn, now);
setDouble(insertRaceResults, 4, totalPoints == null ? 0 : totalPoints);
insertRaceResults.setBoolean(5, leaderboard.isDiscarded(competitor, raceColumn, now));
final MaxPointsReason maxPointsReason = leaderboard.getMaxPointsReason(competitor, raceColumn, now);
insertRaceResults.setString(6, (maxPointsReason == null ? MaxPointsReason.NONE : maxPointsReason).name());
}
private void parameterizeInsertRacesStatement(final PreparedStatement insertRaces, final Regatta regatta,
final RaceColumn raceColumn, final Fleet fleet, final TrackedRace trackedRace) throws SQLException {
insertRaces.setString(1, trackedRace.getRace().getName());
assert trackedRace.getTrackedRegatta().getRegatta() == regatta;
insertRaces.setString(2, trackedRace.getTrackedRegatta().getRegatta().getName());
insertRaces.setString(3, raceColumn.getName());
insertRaces.setString(4, fleet.getName());
if (trackedRace.getStartOfTracking() != null) {
insertRaces.setDate(5, new Date(trackedRace.getStartOfTracking().asMillis()));
} else {
insertRaces.setDate(5, null);
}
if (trackedRace.getStartOfRace() != null) {
insertRaces.setDate(6, new Date(trackedRace.getStartOfRace().asMillis()));
} else {
insertRaces.setDate(6, null);
}
if (trackedRace.getEndOfTracking() != null) {
insertRaces.setDate(7, new Date(trackedRace.getEndOfTracking().asMillis()));
} else {
insertRaces.setDate(7, null);
}
if (trackedRace.getEndOfRace() != null) {
insertRaces.setDate(8, new Date(trackedRace.getEndOfRace().asMillis()));
} else {
insertRaces.setDate(8, null);
}
final SpeedWithConfidence<TimePoint> averageWind = trackedRace.getAverageWindSpeedWithConfidenceWithNumberOfSamples(/* number of samples */ 5);
if (averageWind != null) {
setDouble(insertRaces, 9, averageWind.getObject().getKnots());
} else {
setDouble(insertRaces, 9, 0.0);
}
}
@POST
@Produces("application/json;charset=UTF-8")
@Path("createtables")
public Response createTables(@QueryParam("drop") boolean drop) throws SQLException, IOException {
public Response createTables(@QueryParam("drop") boolean drop,
@FormParam("dbendpoint") String dbEndpoint,
@FormParam("dbuser") String dbUser,
@FormParam("dbpassword") String dbPassword) throws SQLException, IOException {
SecurityUtils.getSubject().checkPermission(SecuredSecurityTypes.SERVER.getStringPermissionForTypeRelativeIdentifier(
SecuredSecurityTypes.ServerActions.CAN_EXPORT_MASTERDATA,
new TypeRelativeObjectIdentifier(ServerInfo.getName())));
final Connection connection = HanaConnectionFactory.INSTANCE.getConnection();
final Connection connection = HanaConnectionFactory.INSTANCE.getConnection(Optional.ofNullable(dbEndpoint),
Optional.ofNullable(dbUser), Optional.ofNullable(dbPassword));
if (drop) {
logger.info("Dropping HANA Cloud SAILING DB tables on behalf of user "+SecurityUtils.getSubject().getPrincipal());
tryExecutingQueriesFromSqlResource("/droptables.sql", connection);
@@ -489,12 +310,4 @@ public class HanaCloudSacExportResource extends SharedAbstractSailingServerResou
connection.createStatement().execute(statementAsString);
}
}
private void setDouble(PreparedStatement statement, int parameterIndex, double value) throws SQLException {
if (Double.isNaN(value) || Double.isInfinite(value)) {
setDouble(statement, parameterIndex, 0.0);
} else {
statement.setDouble(parameterIndex, value);
}
}
}
@@ -0,0 +1,27 @@
package com.sap.sailing.hanaexport.jaxrs.api;
import java.sql.Connection;
import java.sql.SQLException;
import com.sap.sailing.domain.base.BoatClass;
public class InsertBoatClassStatement extends AbstractPreparedInsertStatement<BoatClass> {
protected InsertBoatClassStatement(Connection connection) throws SQLException {
super(connection.prepareStatement(
"INSERT INTO SAILING.\"BoatClass\" (\"id\", \"description\", \"hullLengthInMeters\", \"hullBeamInMeters\", \"hullType\") VALUES (?, ?, ?, ?, ?);"));
}
@Override
public void parameterizeStatement(BoatClass boatClass) throws SQLException {
if (boatClass.getName() == null) {
getPreparedStatement().setString(1, "<null>");
} else {
getPreparedStatement().setString(1, boatClass.getName().substring(0, Math.min(boatClass.getName().length(), 255)));
}
getPreparedStatement().setString(2, "Type "+boatClass.getHullType().name()+", length "+
boatClass.getHullLength().getMeters()+"m, beam "+boatClass.getHullBeam().getMeters()+"m");
setDouble(3, boatClass.getHullLength().getMeters());
setDouble(4, boatClass.getHullBeam().getMeters());
getPreparedStatement().setString(5, boatClass.getHullType().name());
}
}
@@ -0,0 +1,23 @@
package com.sap.sailing.hanaexport.jaxrs.api;
import java.sql.Connection;
import java.sql.SQLException;
import com.sap.sailing.domain.base.Competitor;
import com.sap.sailing.domain.base.CompetitorWithBoat;
public class InsertCompetitorStatement extends AbstractPreparedInsertStatement<Competitor> {
protected InsertCompetitorStatement(Connection connection) throws SQLException {
super(connection.prepareStatement(
"INSERT INTO SAILING.\"Competitor\" (\"id\", \"name\", \"shortName\", \"nationality\", \"sailNumber\") VALUES (?, ?, ?, ?, ?);"));
}
@Override
public void parameterizeStatement(Competitor competitor) throws SQLException {
getPreparedStatement().setString(1, competitor.getId().toString());
getPreparedStatement().setString(2, competitor.getName());
getPreparedStatement().setString(3, competitor.getShortName());
getPreparedStatement().setString(4, competitor.getNationality() == null ? " " : competitor.getNationality().getThreeLetterIOCAcronym());
getPreparedStatement().setString(5, competitor.hasBoat() ? ((CompetitorWithBoat) competitor).getBoat().getSailID() : null);
}
}
@@ -0,0 +1,30 @@
package com.sap.sailing.hanaexport.jaxrs.api;
import java.sql.Connection;
import java.sql.Date;
import java.sql.SQLException;
import com.sap.sailing.domain.base.Event;
import com.sap.sailing.domain.common.Position;
public class InsertEventStatement extends AbstractPreparedInsertStatement<Event> {
protected InsertEventStatement(Connection connection) throws SQLException {
super(connection.prepareStatement(
"INSERT INTO SAILING.\"Event\" (\"id\", \"name\", \"startDate\", \"endDate\", \"venue\", \"isListed\", \"description\", \"location\") "+
"VALUES (?, ?, ?, ?, ?, ?, ?, new ST_GEOMETRY('POINT('|| ? || ' ' || ? ||')', 4326).ST_Transform(3857));"));
}
@Override
public void parameterizeStatement(Event event) throws SQLException {
getPreparedStatement().setString(1, event.getId().toString());
getPreparedStatement().setString(2, event.getName());
getPreparedStatement().setDate(3, event.getStartDate()==null?null:new Date(event.getStartDate().asMillis()));
getPreparedStatement().setDate(4, event.getEndDate()==null?null:new Date(event.getEndDate().asMillis()));
getPreparedStatement().setString(5, event.getVenue().getName());
getPreparedStatement().setBoolean(6, event.isPublic());
getPreparedStatement().setString(7, event.getDescription());
final Position location = event.getLocation();
getPreparedStatement().setString(8, location != null ? String.format("%1.8f", location.getLngDeg()) : null);
getPreparedStatement().setString(9, location != null ? String.format("%1.8f", location.getLatDeg()) : null);
}
}
@@ -0,0 +1,21 @@
package com.sap.sailing.hanaexport.jaxrs.api;
import java.sql.Connection;
import java.sql.SQLException;
import com.sap.sailing.domain.common.MaxPointsReason;
public class InsertIrmStatement extends AbstractPreparedInsertStatement<MaxPointsReason> {
protected InsertIrmStatement(Connection connection) throws SQLException {
super(connection.prepareStatement(
"INSERT INTO SAILING.\"IRM\" (\"name\", \"discardable\", \"advanceCompetitorsTrackedWorse\", \"appliesAtStartOfRace\") VALUES (?, ?, ?, ?);"));
}
@Override
public void parameterizeStatement(MaxPointsReason irm) throws SQLException {
getPreparedStatement().setString(1, irm.name());
getPreparedStatement().setBoolean(2, irm.isDiscardable());
getPreparedStatement().setBoolean(3, irm.isAdvanceCompetitorsTrackedWorse());
getPreparedStatement().setBoolean(4, irm.isAppliesAtStartOfRace());
}
}
@@ -0,0 +1,49 @@
package com.sap.sailing.hanaexport.jaxrs.api;
import java.sql.Connection;
import java.sql.SQLException;
import com.sap.sailing.domain.common.LegType;
import com.sap.sailing.domain.common.NoWindException;
import com.sap.sailing.domain.tracking.TrackedLeg;
import com.sap.sailing.hanaexport.jaxrs.api.InsertLegStatement.TrackedLegAndNow;
import com.sap.sse.common.TimePoint;
public class InsertLegStatement extends AbstractPreparedInsertStatement<TrackedLegAndNow> {
static class TrackedLegAndNow {
private final TimePoint now;
private final TrackedLeg trackedLeg;
public TrackedLegAndNow(TimePoint now, TrackedLeg trackedLeg) {
super();
this.now = now;
this.trackedLeg = trackedLeg;
}
public TimePoint getNow() {
return now;
}
public TrackedLeg getTrackedLeg() {
return trackedLeg;
}
}
protected InsertLegStatement(Connection connection) throws SQLException {
super(connection.prepareStatement(
"INSERT INTO SAILING.\"Leg\" (\"race\", \"regatta\", \"number\", \"type\") "+
"VALUES (?, ?, ?, ?);"));
}
@Override
public void parameterizeStatement(TrackedLegAndNow trackedLegAndNow) throws SQLException {
getPreparedStatement().setString(1, trackedLegAndNow.getTrackedLeg().getTrackedRace().getRace().getName());
getPreparedStatement().setString(2, trackedLegAndNow.getTrackedLeg().getTrackedRace().getTrackedRegatta().getRegatta().getName());
getPreparedStatement().setInt(3, trackedLegAndNow.getTrackedLeg().getLeg().getZeroBasedIndexOfStartWaypoint());
final LegType legType;
try {
legType = trackedLegAndNow.getTrackedLeg().getLegType(trackedLegAndNow.getNow());
getPreparedStatement().setString(4, legType.name());
} catch (NoWindException nwe) {
getPreparedStatement().setString(4, null);
}
}
}
@@ -0,0 +1,77 @@
package com.sap.sailing.hanaexport.jaxrs.api;
import java.sql.Connection;
import java.sql.SQLException;
import com.sap.sailing.domain.common.NoWindException;
import com.sap.sailing.domain.ranking.RankingMetric.RankingInfo;
import com.sap.sailing.domain.tracking.TrackedLegOfCompetitor;
import com.sap.sailing.domain.tracking.WindLegTypeAndLegBearingAndORCPerformanceCurveCache;
import com.sap.sailing.domain.tracking.WindPositionMode;
import com.sap.sailing.hanaexport.jaxrs.api.InsertLegStatsStatement.TrackedLegOfCompetitorRankingInfoCacheAndNow;
import com.sap.sse.common.Speed;
import com.sap.sse.common.TimePoint;
public class InsertLegStatsStatement extends AbstractPreparedInsertStatement<TrackedLegOfCompetitorRankingInfoCacheAndNow> {
static class TrackedLegOfCompetitorRankingInfoCacheAndNow {
private final TimePoint now;
private final RankingInfo rankingInfo;
private final WindLegTypeAndLegBearingAndORCPerformanceCurveCache cache;
private final TrackedLegOfCompetitor trackedLegOfCompetitor;
public TrackedLegOfCompetitorRankingInfoCacheAndNow(TimePoint now, RankingInfo rankingInfo,
WindLegTypeAndLegBearingAndORCPerformanceCurveCache cache,
TrackedLegOfCompetitor trackedLegOfCompetitor) {
super();
this.now = now;
this.rankingInfo = rankingInfo;
this.cache = cache;
this.trackedLegOfCompetitor = trackedLegOfCompetitor;
}
public TimePoint getNow() {
return now;
}
public RankingInfo getRankingInfo() {
return rankingInfo;
}
public WindLegTypeAndLegBearingAndORCPerformanceCurveCache getCache() {
return cache;
}
public TrackedLegOfCompetitor getTrackedLegOfCompetitor() {
return trackedLegOfCompetitor;
}
}
protected InsertLegStatsStatement(Connection connection) throws SQLException {
super(connection.prepareStatement(
"INSERT INTO SAILING.\"LegStats\" (\"race\", \"regatta\", \"number\", \"competitorId\", \"rankOneBased\", \"distanceSailedInMeters\", \"elapsedTimeInSeconds\", "+
"\"avgCrossTrackErrorInMeters\", \"absoluteAvgCrossTrackErrorInMeters\", \"numberOfTacks\", "+
"\"numberOfGybes\", \"numberOfPenaltyCircles\", \"avgVelocityMadeGoodInKnots\", \"gapToLeaderInSeconds\") "+
"VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?);"));
}
@Override
public void parameterizeStatement(TrackedLegOfCompetitorRankingInfoCacheAndNow trackedLegOfCompetitorAndNow) throws SQLException {
getPreparedStatement().setString(1, trackedLegOfCompetitorAndNow.getTrackedLegOfCompetitor().getTrackedLeg().getTrackedRace().getRace().getName());
getPreparedStatement().setString(2, trackedLegOfCompetitorAndNow.getTrackedLegOfCompetitor().getTrackedLeg().getTrackedRace().getTrackedRegatta().getRegatta().getName());
getPreparedStatement().setInt(3, trackedLegOfCompetitorAndNow.getTrackedLegOfCompetitor().getTrackedLeg().getLeg().getZeroBasedIndexOfStartWaypoint());
getPreparedStatement().setString(4, trackedLegOfCompetitorAndNow.getTrackedLegOfCompetitor().getCompetitor().getId().toString());
getPreparedStatement().setInt(5, trackedLegOfCompetitorAndNow.getTrackedLegOfCompetitor().getRank(trackedLegOfCompetitorAndNow.getNow()));
setDouble(6, metersOr0ForNull(trackedLegOfCompetitorAndNow.getTrackedLegOfCompetitor().getDistanceTraveled(trackedLegOfCompetitorAndNow.getNow())));
setDouble(7, secondsOr0ForNull(trackedLegOfCompetitorAndNow.getTrackedLegOfCompetitor().getTime(trackedLegOfCompetitorAndNow.getNow())));
setDouble(8, metersOr0ForNull(trackedLegOfCompetitorAndNow.getTrackedLegOfCompetitor().getAverageSignedCrossTrackError(trackedLegOfCompetitorAndNow.getNow(), /* waitForLatest */ false)));
setDouble(9, metersOr0ForNull(trackedLegOfCompetitorAndNow.getTrackedLegOfCompetitor().getAverageAbsoluteCrossTrackError(trackedLegOfCompetitorAndNow.getNow(), /* waitForLatest */ false)));
try {
getPreparedStatement().setInt(10, intOr0ForNull(trackedLegOfCompetitorAndNow.getTrackedLegOfCompetitor().getNumberOfTacks(trackedLegOfCompetitorAndNow.getNow(), /* waitForLatest */ false)));
getPreparedStatement().setInt(11, intOr0ForNull(trackedLegOfCompetitorAndNow.getTrackedLegOfCompetitor().getNumberOfJibes(trackedLegOfCompetitorAndNow.getNow(), /* waitForLatest */ false)));
getPreparedStatement().setInt(12, intOr0ForNull(trackedLegOfCompetitorAndNow.getTrackedLegOfCompetitor().getNumberOfPenaltyCircles(trackedLegOfCompetitorAndNow.getNow(), /* waitForLatest */ false)));
} catch (NoWindException nwe) {
getPreparedStatement().setInt(10, 0);
getPreparedStatement().setInt(11, 0);
getPreparedStatement().setInt(12, 0);
}
final Speed vmg = trackedLegOfCompetitorAndNow.getTrackedLegOfCompetitor().getAverageVelocityMadeGood(trackedLegOfCompetitorAndNow.getNow());
setDouble(13, vmg==null?0:vmg.getKnots());
setDouble(14, secondsOr0ForNull(trackedLegOfCompetitorAndNow.getTrackedLegOfCompetitor().getGapToLeader(trackedLegOfCompetitorAndNow.getNow(), WindPositionMode.LEG_MIDDLE,
trackedLegOfCompetitorAndNow.getRankingInfo(), trackedLegOfCompetitorAndNow.getCache())));
}
}
@@ -0,0 +1,67 @@
package com.sap.sailing.hanaexport.jaxrs.api;
import java.sql.Connection;
import java.sql.Date;
import java.sql.SQLException;
import com.sap.sailing.domain.base.Competitor;
import com.sap.sailing.domain.tracking.Maneuver;
import com.sap.sailing.domain.tracking.TrackedRace;
import com.sap.sailing.hanaexport.jaxrs.api.InsertManeuverStatement.ManeuverTrackedRaceAndCompetitor;
public class InsertManeuverStatement extends AbstractPreparedInsertStatement<ManeuverTrackedRaceAndCompetitor> {
static class ManeuverTrackedRaceAndCompetitor {
private final Maneuver maneuver;
private final TrackedRace trackedRace;
private final Competitor competitor;
public ManeuverTrackedRaceAndCompetitor(Maneuver maneuver, TrackedRace trackedRace, Competitor competitor) {
super();
this.maneuver = maneuver;
this.trackedRace = trackedRace;
this.competitor = competitor;
}
public Maneuver getManeuver() {
return maneuver;
}
public TrackedRace getTrackedRace() {
return trackedRace;
}
public Competitor getCompetitor() {
return competitor;
}
}
protected InsertManeuverStatement(Connection connection) throws SQLException {
super(connection.prepareStatement(
"INSERT INTO SAILING.\"Maneuver\" (\"race\", \"regatta\", \"competitorId\", \"timepoint\", \"type\", \"newTack\", "+
"\"lossInMeters\", \"speedBeforeInKnots\", \"speedAfterInKnots\", "+
"\"courseBeforeInTrueDegrees\", \"courseAfterInTrueDegrees\", \"directionChangeInDegrees\", \"maximumTurningRateInDegreesPerSecond\", "+
"\"lowestSpeedInKnots\", \"toSide\") "+
"VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?);"));
}
@Override
public void parameterizeStatement(ManeuverTrackedRaceAndCompetitor maneuverTrackedRaceAndCompetitor) throws SQLException {
getPreparedStatement().setString(1, maneuverTrackedRaceAndCompetitor.getTrackedRace().getRace().getName());
getPreparedStatement().setString(2, maneuverTrackedRaceAndCompetitor.getTrackedRace().getTrackedRegatta().getRegatta().getName());
getPreparedStatement().setString(3, maneuverTrackedRaceAndCompetitor.getCompetitor().getId().toString());
getPreparedStatement().setDate(4, new Date(maneuverTrackedRaceAndCompetitor.getManeuver().getTimePoint().asMillis()));
getPreparedStatement().setString(5, maneuverTrackedRaceAndCompetitor.getManeuver().getType().name());
getPreparedStatement().setString(6, maneuverTrackedRaceAndCompetitor.getManeuver().getNewTack().name());
if (maneuverTrackedRaceAndCompetitor.getManeuver().getManeuverLoss() != null) {
setDouble(7,
maneuverTrackedRaceAndCompetitor.getManeuver().getManeuverLoss().getDistanceSailedIfNotManeuveringProjectedOnMiddleManeuverAngle().getMeters()
-maneuverTrackedRaceAndCompetitor.getManeuver().getManeuverLoss().getDistanceSailedProjectedOnMiddleManeuverAngle().getMeters());
} else {
setDouble(7, 0);
}
setDouble(8, maneuverTrackedRaceAndCompetitor.getManeuver().getSpeedWithBearingBefore().getKnots());
setDouble(9, maneuverTrackedRaceAndCompetitor.getManeuver().getSpeedWithBearingAfter().getKnots());
setDouble(10, maneuverTrackedRaceAndCompetitor.getManeuver().getSpeedWithBearingBefore().getBearing().getDegrees());
setDouble(11, maneuverTrackedRaceAndCompetitor.getManeuver().getSpeedWithBearingAfter().getBearing().getDegrees());
setDouble(12, maneuverTrackedRaceAndCompetitor.getManeuver().getDirectionChangeInDegrees());
setDouble(13, maneuverTrackedRaceAndCompetitor.getManeuver().getMaxTurningRateInDegreesPerSecond());
setDouble(14, maneuverTrackedRaceAndCompetitor.getManeuver().getLowestSpeed().getKnots());
getPreparedStatement().setString(15, maneuverTrackedRaceAndCompetitor.getManeuver().getToSide().name());
}
}
@@ -0,0 +1,65 @@
package com.sap.sailing.hanaexport.jaxrs.api;
import java.sql.Connection;
import java.sql.SQLException;
import com.sap.sailing.domain.base.Competitor;
import com.sap.sailing.domain.base.RaceColumn;
import com.sap.sailing.domain.base.Regatta;
import com.sap.sailing.domain.common.MaxPointsReason;
import com.sap.sailing.domain.leaderboard.Leaderboard;
import com.sap.sailing.hanaexport.jaxrs.api.InsertRaceResultStatement.RaceResult;
import com.sap.sse.common.TimePoint;
public class InsertRaceResultStatement extends AbstractPreparedInsertStatement<RaceResult> {
static class RaceResult {
private final Regatta regatta;
private final Leaderboard leaderboard;
private final Competitor competitor;
private final RaceColumn raceColumn;
private final TimePoint now;
public RaceResult(Regatta regatta, Leaderboard leaderboard, Competitor competitor, RaceColumn raceColumn,
TimePoint now) {
super();
this.regatta = regatta;
this.leaderboard = leaderboard;
this.competitor = competitor;
this.raceColumn = raceColumn;
this.now = now;
}
public Regatta getRegatta() {
return regatta;
}
public Leaderboard getLeaderboard() {
return leaderboard;
}
public Competitor getCompetitor() {
return competitor;
}
public RaceColumn getRaceColumn() {
return raceColumn;
}
public TimePoint getNow() {
return now;
}
}
protected InsertRaceResultStatement(Connection connection) throws SQLException {
super(connection.prepareStatement(
"INSERT INTO SAILING.\"RaceResult\" (\"regatta\", \"raceColumn\", \"competitorId\", \"points\", "+
"\"discarded\", \"irm\") "+
"VALUES (?, ?, ?, ?, ?, ?);"));
}
@Override
public void parameterizeStatement(RaceResult raceResult) throws SQLException {
getPreparedStatement().setString(1, raceResult.getRegatta().getName());
getPreparedStatement().setString(2, raceResult.getRaceColumn().getName());
getPreparedStatement().setString(3, raceResult.getCompetitor().getId().toString());
final Double totalPoints = raceResult.getLeaderboard().getTotalPoints(raceResult.getCompetitor(), raceResult.getRaceColumn(), raceResult.getNow());
setDouble(4, totalPoints == null ? 0 : totalPoints);
getPreparedStatement().setBoolean(5, raceResult.getLeaderboard().isDiscarded(raceResult.getCompetitor(), raceResult.getRaceColumn(), raceResult.getNow()));
final MaxPointsReason maxPointsReason = raceResult.getLeaderboard().getMaxPointsReason(raceResult.getCompetitor(), raceResult.getRaceColumn(), raceResult.getNow());
getPreparedStatement().setString(6, (maxPointsReason == null ? MaxPointsReason.NONE : maxPointsReason).name());
}
}
@@ -0,0 +1,77 @@
package com.sap.sailing.hanaexport.jaxrs.api;
import java.sql.Connection;
import java.sql.Date;
import java.sql.SQLException;
import com.sap.sailing.domain.base.Fleet;
import com.sap.sailing.domain.base.RaceColumn;
import com.sap.sailing.domain.base.SpeedWithConfidence;
import com.sap.sailing.domain.tracking.TrackedRace;
import com.sap.sailing.hanaexport.jaxrs.api.InsertRaceStatement.TrackedRaceWithRaceColumnAndFleet;
import com.sap.sse.common.TimePoint;
public class InsertRaceStatement extends AbstractPreparedInsertStatement<TrackedRaceWithRaceColumnAndFleet> {
static class TrackedRaceWithRaceColumnAndFleet {
private final TrackedRace trackedRace;
private final RaceColumn raceColumn;
private final Fleet fleet;
public TrackedRaceWithRaceColumnAndFleet(TrackedRace trackedRace, RaceColumn raceColumn, Fleet fleet) {
super();
this.trackedRace = trackedRace;
this.raceColumn = raceColumn;
this.fleet = fleet;
}
public TrackedRace getTrackedRace() {
return trackedRace;
}
public RaceColumn getRaceColumn() {
return raceColumn;
}
public Fleet getFleet() {
return fleet;
}
}
protected InsertRaceStatement(Connection connection) throws SQLException {
super(connection.prepareStatement(
"INSERT INTO SAILING.\"Race\" (\"name\", \"regatta\", \"raceColumn\", \"fleet\", \"startOfTracking\", "+
"\"startOfRace\", \"endOfTracking\", \"endOfRace\", \"avgWindSpeedInKnots\") "+
"VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?);"));
}
@Override
public void parameterizeStatement(TrackedRaceWithRaceColumnAndFleet raceColumnFleetAndTrackedRace) throws SQLException {
final TrackedRace trackedRace = raceColumnFleetAndTrackedRace.getTrackedRace();
getPreparedStatement().setString(1, trackedRace.getRace().getName());
getPreparedStatement().setString(2, trackedRace.getTrackedRegatta().getRegatta().getName());
getPreparedStatement().setString(3, raceColumnFleetAndTrackedRace.getRaceColumn().getName());
getPreparedStatement().setString(4, raceColumnFleetAndTrackedRace.getFleet().getName());
if (trackedRace.getStartOfTracking() != null) {
getPreparedStatement().setDate(5, new Date(trackedRace.getStartOfTracking().asMillis()));
} else {
getPreparedStatement().setDate(5, null);
}
if (trackedRace.getStartOfRace() != null) {
getPreparedStatement().setDate(6, new Date(trackedRace.getStartOfRace().asMillis()));
} else {
getPreparedStatement().setDate(6, null);
}
if (trackedRace.getEndOfTracking() != null) {
getPreparedStatement().setDate(7, new Date(trackedRace.getEndOfTracking().asMillis()));
} else {
getPreparedStatement().setDate(7, null);
}
if (trackedRace.getEndOfRace() != null) {
getPreparedStatement().setDate(8, new Date(trackedRace.getEndOfRace().asMillis()));
} else {
getPreparedStatement().setDate(8, null);
}
final SpeedWithConfidence<TimePoint> averageWind = trackedRace.getAverageWindSpeedWithConfidenceWithNumberOfSamples(/* number of samples */ 5);
if (averageWind != null) {
setDouble(9, averageWind.getObject().getKnots());
} else {
setDouble(9, 0.0);
}
}
}
@@ -0,0 +1,112 @@
package com.sap.sailing.hanaexport.jaxrs.api;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.NavigableSet;
import com.sap.sailing.domain.base.Competitor;
import com.sap.sailing.domain.base.Waypoint;
import com.sap.sailing.domain.common.ManeuverType;
import com.sap.sailing.domain.common.NoWindException;
import com.sap.sailing.domain.common.Tack;
import com.sap.sailing.domain.tracking.Maneuver;
import com.sap.sailing.domain.tracking.MarkPassing;
import com.sap.sailing.domain.tracking.TrackedRace;
import com.sap.sailing.hanaexport.jaxrs.api.InsertRaceStatsStatement.TrackedRaceWithCompetitorAndStartWaypoint;
import com.sap.sse.common.Speed;
import com.sap.sse.common.TimePoint;
import com.sap.sse.common.Util;
public class InsertRaceStatsStatement extends AbstractPreparedInsertStatement<TrackedRaceWithCompetitorAndStartWaypoint> {
static class TrackedRaceWithCompetitorAndStartWaypoint {
private final TimePoint now;
private final Waypoint startWaypoint;
private final Competitor competitor;
private final TrackedRace trackedRace;
public TrackedRaceWithCompetitorAndStartWaypoint(TimePoint now, Waypoint startWaypoint, Competitor competitor,
TrackedRace trackedRace) {
super();
this.now = now;
this.startWaypoint = startWaypoint;
this.competitor = competitor;
this.trackedRace = trackedRace;
}
public TimePoint getNow() {
return now;
}
public Waypoint getStartWaypoint() {
return startWaypoint;
}
public Competitor getCompetitor() {
return competitor;
}
public TrackedRace getTrackedRace() {
return trackedRace;
}
}
protected InsertRaceStatsStatement(Connection connection) throws SQLException {
super(connection.prepareStatement(
"INSERT INTO SAILING.\"RaceStats\" (\"race\", \"regatta\", \"competitorId\", \"rankOneBased\", \"distanceSailedInMeters\", \"elapsedTimeInSeconds\", "+
"\"avgCrossTrackErrorInMeters\", \"absoluteAvgCrossTrackErrorInMeters\", \"numberOfTacks\", "+
"\"numberOfGybes\", \"numberOfPenaltyCircles\", \"startDelayInSeconds\", \"distanceFromStartLineInMetersAtStart\", "+
"\"speedWhenCrossingStartLineInKnots\", \"startTack\") "+
"VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?);"));
}
@Override
public void parameterizeStatement(TrackedRaceWithCompetitorAndStartWaypoint raceColumnFleetAndTrackedRace) throws SQLException {
final TrackedRace trackedRace = raceColumnFleetAndTrackedRace.getTrackedRace();
final Competitor competitor = raceColumnFleetAndTrackedRace.getCompetitor();
final TimePoint now = raceColumnFleetAndTrackedRace.getNow();
getPreparedStatement().setString(1, trackedRace.getRace().getName());
getPreparedStatement().setString(2, trackedRace.getTrackedRegatta().getRegatta().getName());
getPreparedStatement().setString(3, competitor.getId().toString());
getPreparedStatement().setInt(4, trackedRace.getRank(competitor, now));
setDouble(5, metersOr0ForNull(trackedRace.getDistanceTraveled(competitor, now)));
setDouble(6, secondsOr0ForNull(trackedRace.getTimeSailedSinceRaceStart(competitor, now)));
setDouble(7, metersOr0ForNull(trackedRace.getAverageSignedCrossTrackError(competitor, now, /* waitForLatest */ false)));
setDouble(8, metersOr0ForNull(trackedRace.getAverageAbsoluteCrossTrackError(competitor, now, /* waitForLatest */ false)));
final Iterable<Maneuver> maneuvers = trackedRace.getManeuvers(competitor, /* waitForLatest */ false);
getPreparedStatement().setInt(9, Util.size(Util.filter(maneuvers, m->m.getType() == ManeuverType.TACK)));
getPreparedStatement().setInt(10, Util.size(Util.filter(maneuvers, m->m.getType() == ManeuverType.JIBE)));
getPreparedStatement().setInt(11, Util.size(Util.filter(maneuvers, m->m.getType() == ManeuverType.PENALTY_CIRCLE)));
final TimePoint startOfRace = trackedRace.getStartOfRace();
final double startDelay;
Tack startTack;
if (raceColumnFleetAndTrackedRace.getStartWaypoint() != null && startOfRace != null) {
NavigableSet<MarkPassing> competitorMarkPassings = trackedRace.getMarkPassings(competitor);
trackedRace.lockForRead(competitorMarkPassings);
try {
if (!Util.isEmpty(competitorMarkPassings)) {
final MarkPassing competitorStartMarkPassing = competitorMarkPassings.iterator().next();
final TimePoint competitorStartTime = competitorStartMarkPassing.getTimePoint();
startDelay = secondsOr0ForNull(startOfRace.until(competitorStartTime));
try {
startTack = trackedRace.getTack(competitor, competitorStartTime);
} catch (NoWindException e) {
startTack = null;
}
} else {
startDelay = 0;
startTack = null;
}
} finally {
trackedRace.unlockAfterRead(competitorMarkPassings);
}
} else {
startDelay = 0;
startTack = null;
}
setDouble(12, startDelay);
if (startOfRace != null) {
setDouble(13, metersOr0ForNull(trackedRace.getDistanceToStartLine(competitor, startOfRace)));
final Speed speedWhenCrossingStartLine = trackedRace.getSpeedWhenCrossingStartLine(competitor);
setDouble(14, speedWhenCrossingStartLine==null?0:speedWhenCrossingStartLine.getKnots());
getPreparedStatement().setString(15, startTack==null?null:startTack.name());
} else {
setDouble(13, 0);
setDouble(14, 0);
}
}
}
@@ -0,0 +1,43 @@
package com.sap.sailing.hanaexport.jaxrs.api;
import java.sql.Connection;
import java.sql.SQLException;
import com.sap.sailing.domain.base.Event;
import com.sap.sailing.domain.base.Regatta;
import com.sap.sailing.hanaexport.jaxrs.api.InsertRegattaStatement.RegattaAndEvent;
public class InsertRegattaStatement extends AbstractPreparedInsertStatement<RegattaAndEvent> {
static class RegattaAndEvent {
private final Regatta regatta;
private final Event event;
public RegattaAndEvent(Regatta regatta, Event event) {
super();
this.regatta = regatta;
this.event = event;
}
public Regatta getRegatta() {
return regatta;
}
public Event getEvent() {
return event;
}
}
protected InsertRegattaStatement(Connection connection) throws SQLException {
super(connection.prepareStatement(
"INSERT INTO SAILING.\"Regatta\" (\"name\", \"boatClass\", \"scoringScheme\", \"rankingMetric\", \"eventId\") "+
"VALUES (?, ?, ?, ?, ?);"));
}
@Override
public void parameterizeStatement(RegattaAndEvent regattaAndEvent) throws SQLException {
final Regatta regatta = regattaAndEvent.getRegatta();
final Event event = regattaAndEvent.getEvent();
getPreparedStatement().setString(1, regatta.getName());
getPreparedStatement().setString(2, regatta.getBoatClass().getName());
getPreparedStatement().setString(3, regatta.getScoringScheme().getType().name());
getPreparedStatement().setString(4, regatta.getRankingMetricType().name());
getPreparedStatement().setString(5, event == null ? null : event.getId().toString());
}
}
@@ -0,0 +1,19 @@
package com.sap.sailing.hanaexport.jaxrs.api;
import java.sql.Connection;
import java.sql.SQLException;
import com.sap.sailing.domain.leaderboard.ScoringScheme;
public class InsertScoringSchemeStatement extends AbstractPreparedInsertStatement<ScoringScheme> {
protected InsertScoringSchemeStatement(Connection connection) throws SQLException {
super(connection.prepareStatement(
"INSERT INTO SAILING.\"ScoringScheme\" (\"id\", \"higherIsBetter\") VALUES (?, ?);"));
}
@Override
public void parameterizeStatement(ScoringScheme scoringScheme) throws SQLException {
getPreparedStatement().setString(1, scoringScheme.getType().name());
getPreparedStatement().setBoolean(2, scoringScheme.isHigherBetter());
}
}
@@ -0,0 +1,37 @@
package com.sap.sailing.hanaexport.jaxrs.api;
import java.sql.PreparedStatement;
import java.sql.SQLException;
/**
* Can insert objects of type {@code T} using a prepared statement, in batch mode.
*
* @author Axel Uhl (D043530)
*
* @param <T>
*/
public interface PreparedInsertStatement<T> {
PreparedStatement getPreparedStatement();
void parameterizeStatement(T objectToInsert) throws SQLException;
default void insert(T objectToInsert) throws SQLException {
parameterizeStatement(objectToInsert);
getPreparedStatement().execute();
}
default void insertBatch(Iterable<T> objectsToInsert) throws SQLException {
for (final T objectToInsert : objectsToInsert) {
insertBatch(objectToInsert);
}
}
default void insertBatch(final T objectToInsert) throws SQLException {
parameterizeStatement(objectToInsert);
getPreparedStatement().addBatch();
}
default int[] executeBatch() throws SQLException {
return getPreparedStatement().executeBatch();
}
}
@@ -141,7 +141,7 @@ public class LandscapeManagementWriteServiceImpl extends ResultCachingProxiedRem
/**
* The timeout for a host to come up
*/
private static final Optional<Duration> WAIT_FOR_HOST_TIMEOUT = Optional.of(Duration.ONE_MINUTE.times(10));
private static final Optional<Duration> WAIT_FOR_HOST_TIMEOUT = Optional.of(Duration.ONE_MINUTE.times(30));
private static final String SAILING_TARGET_GROUP_NAME_PREFIX = "S-";
@@ -8,6 +8,8 @@ import com.sap.sse.landscape.DefaultProcessConfigurationVariables;
import com.sap.sse.landscape.InboundReplicationConfiguration;
import com.sap.sse.landscape.OutboundReplicationConfiguration;
import com.sap.sse.landscape.ProcessConfigurationVariable;
import com.sap.sse.landscape.mongodb.Database;
import com.sap.sse.landscape.mongodb.MongoEndpoint;
public class SailingAnalyticsReplicaConfiguration<ShardingKey>
extends SailingAnalyticsApplicationConfiguration<ShardingKey> {
@@ -24,6 +26,8 @@ extends SailingAnalyticsApplicationConfiguration<ShardingKey> {
* {@code "live-replica-server"}.</li>
* <li>If no {@link #setDatabaseName(String) database name is set} explicitly, it defaults to the
* {@link #getServerName() server name} with the suffix {@code -replica} appended to it.</li>
* <li>If no {@link #setDatabaseConfiguration(Database) database configuration is set} explicitly, it defaults
* to the "replica" replica set on "localhost:27017" on the replica node.</li>
* </ul>
*
* TODO we could default the set of replicables to replicate, competing with the live-replica-server environment
@@ -40,6 +44,8 @@ extends SailingAnalyticsApplicationConfiguration<ShardingKey> {
protected static class BuilderImpl<BuilderT extends Builder<BuilderT, ShardingKey>, ShardingKey>
extends SailingAnalyticsApplicationConfiguration.BuilderImpl<BuilderT, SailingAnalyticsReplicaConfiguration<ShardingKey>, ShardingKey>
implements Builder<BuilderT, ShardingKey> {
private static final String DEFAULT_MONGO_REPLICA_SET_NAME_FOR_REPLICA = "replica";
@Override
public OutboundReplicationConfiguration getOutboundReplicationConfiguration() {
final OutboundReplicationConfiguration.Builder resultBuilder;
@@ -56,6 +62,12 @@ extends SailingAnalyticsApplicationConfiguration<ShardingKey> {
}
return resultBuilder.build();
}
@Override
protected Database getDatabaseConfiguration() {
return isDatabaseConfigurationSet() ? super.getDatabaseConfiguration() :
Database.of(MongoEndpoint.of("localhost", 27017, DEFAULT_MONGO_REPLICA_SET_NAME_FOR_REPLICA), getDatabaseName());
}
@Override
public Optional<InboundReplicationConfiguration> getInboundReplicationConfiguration() {
@@ -43,6 +43,7 @@ import org.mockito.Matchers;
import org.mockito.Mockito;
import com.mongodb.MongoException;
import com.mongodb.ReadConcern;
import com.mongodb.WriteConcern;
import com.sap.sailing.domain.abstractlog.AbstractLogEventAuthor;
import com.sap.sailing.domain.abstractlog.impl.LogEventAuthorImpl;
@@ -264,7 +265,7 @@ public class MasterDataImportTest {
.spy(new RacingEventServiceImpl(null, MongoSensorFixStoreFactory.INSTANCE.getMongoGPSFixStore(
PersistenceFactory.INSTANCE
.getDefaultMongoObjectFactory(serviceFinderFactory), PersistenceFactory.INSTANCE
.getDefaultDomainObjectFactory(), serviceFinderFactory, WriteConcern.MAJORITY), serviceFinderFactory));
.getDefaultDomainObjectFactory(), serviceFinderFactory, ReadConcern.MAJORITY, WriteConcern.MAJORITY), serviceFinderFactory));
Mockito.doReturn(securityService).when(sourceService).getSecurityService();
Event event = sourceService.addEvent(TEST_EVENT_NAME, /* eventDescription */null, eventStartDate, eventEndDate,
"testVenue", false, eventUUID);
@@ -5,6 +5,7 @@ import java.util.Map;
import java.util.Set;
import com.mongodb.MongoException;
import com.mongodb.ReadConcern;
import com.mongodb.WriteConcern;
import com.sap.sailing.domain.base.Regatta;
import com.sap.sailing.domain.common.impl.DataImportProgressImpl;
@@ -36,7 +37,7 @@ public abstract class RacingEventServiceImplMock extends RacingEventServiceImpl
super(null, MongoSensorFixStoreFactory.INSTANCE.getMongoGPSFixStore(
PersistenceFactory.INSTANCE
.getDefaultMongoObjectFactory(serviceFinderFactory), PersistenceFactory.INSTANCE
.getDefaultDomainObjectFactory(), serviceFinderFactory, WriteConcern.MAJORITY), serviceFinderFactory);
.getDefaultDomainObjectFactory(), serviceFinderFactory, ReadConcern.MAJORITY, WriteConcern.MAJORITY), serviceFinderFactory);
lock = new DataImportLockWithProgress();
lock.addProgress(dataImportProgressImpl.getOperationId(), dataImportProgressImpl);
}
+5
View File
@@ -0,0 +1,5 @@
Contact: https://www.sap.com/report-a-vulnerability
Encryption: https://www.sap.com/pgp-keyblock
Policy: https://wiki.scn.sap.com/wiki/x/1s-iGg
Acknowledgments: https://wiki.scn.sap.com/wiki/x/rc-iGg
Expires: Mon, 31 Jan 2022 12:00 +0100
@@ -3,6 +3,7 @@ source.. = src/,\
output.. = bin/
bin.includes = META-INF/,\
.,\
./.well-known/,\
WEB-INF/web.xml,\
index.html,\
release_notes.css,\
@@ -23,6 +23,10 @@
<div class="mainContent">
<h2 class="releaseHeadline">Release Notes - Administration Console</h2>
<div class="innerContent">
<h2 class="articleSubheadline">August 2021</h2>
<ul class="bulletList">
<li>Added boat classes iQFOil Men/Women/Youth</li>
</ul>
<h2 class="articleSubheadline">July 2021</h2>
<ul class="bulletList">
<li>Creating and editing a Regatta object now uses the already loaded Events with their course areas
@@ -789,16 +789,20 @@ public class Util {
}
public static <T extends Named> List<T> sortNamedCollection(Collection<T> collection) {
return sortNamedCollection(collection, /* caseSensitive */ true);
}
public static <T extends Named> List<T> sortNamedCollection(Collection<T> collection, boolean caseSensitive) {
List<T> sortedCollection = new ArrayList<>(collection);
Collections.sort(sortedCollection, naturalNamedComparator());
Collections.sort(sortedCollection, naturalNamedComparator(caseSensitive));
return sortedCollection;
}
public static <T extends Named> Comparator<T> naturalNamedComparator() {
public static <T extends Named> Comparator<T> naturalNamedComparator(boolean caseSensitive) {
return new Comparator<T>() {
@Override
public int compare(T o1, T o2) {
return new NaturalComparator().compare(o1.getName(), o2.getName());
return new NaturalComparator(caseSensitive).compare(o1.getName(), o2.getName());
}
};
}
@@ -190,7 +190,11 @@ implements UserDataProvider {
}
protected Database getDatabaseConfiguration() {
return databaseConfiguration == null ? getLandscape().getDatabase(getRegion(), getDatabaseName()) : databaseConfiguration;
return isDatabaseConfigurationSet() ? databaseConfiguration : getLandscape().getDatabase(getRegion(), getDatabaseName());
}
protected boolean isDatabaseConfigurationSet() {
return databaseConfiguration != null;
}
@Override
@@ -5,14 +5,18 @@ import java.net.URISyntaxException;
import java.util.HashMap;
import java.util.Map;
import java.util.Optional;
import java.util.logging.Logger;
import com.mongodb.client.MongoDatabase;
import com.sap.sse.common.Named;
import com.sap.sse.landscape.DefaultProcessConfigurationVariables;
import com.sap.sse.landscape.ProcessConfigurationVariable;
import com.sap.sse.landscape.UserDataProvider;
import com.sap.sse.landscape.mongodb.impl.DatabaseImpl;
public interface Database extends UserDataProvider, Named {
static final Logger logger = Logger.getLogger(Database.class.getName());
/**
* Obtains the database-specific connection URI that clients can use to connect to the replica set hosting this
* database. See also {@link MongoReplicaSet#getConnectionURI()}.
@@ -48,5 +52,12 @@ public interface Database extends UserDataProvider, Named {
/**
* Drops the database.
*/
void drop() throws URISyntaxException;
default void drop() throws URISyntaxException {
logger.info("Dropping database "+this);
getMongoDatabase().drop();
}
static Database of(MongoEndpoint mongoEndpoint, String databaseName) {
return new DatabaseImpl(mongoEndpoint, databaseName);
}
}
@@ -9,6 +9,7 @@ import com.mongodb.MongoClientURI;
import com.mongodb.client.MongoDatabase;
import com.mongodb.session.ClientSession;
import com.sap.sse.common.Duration;
import com.sap.sse.landscape.mongodb.impl.SimpleMongoEndpointImpl;
/**
* A MongoDB endpoint that an application can connect to. It can produce a {@link URI} the client can use to connect to,
@@ -19,6 +20,14 @@ import com.sap.sse.common.Duration;
*
*/
public interface MongoEndpoint {
static MongoEndpoint of(String hostname, int port) {
return new SimpleMongoEndpointImpl(hostname, port);
}
static MongoEndpoint of(String hostname, int port, String replicaSetName) {
return new SimpleMongoEndpointImpl(hostname, port, replicaSetName);
}
/**
* When invoked on a {@link MongoProcess} that is not currently equipped with a public IP address, a
* {@link NullPointerException} will result. Consider using {@link #getURI(Optional, Optional)} to wait for
@@ -28,6 +37,24 @@ public interface MongoEndpoint {
URI getURI(Optional<Database> optionalDb, Optional<Duration> timeoutEmptyMeaningForever) throws URISyntaxException;
default URI getURI(Optional<Database> optionalDb, String hostname, int port, Optional<String> replicaSetName) throws URISyntaxException {
final StringBuilder sb = new StringBuilder();
sb.append("mongodb://");
sb.append(hostname);
sb.append(":");
sb.append(port);
sb.append("/");
optionalDb.ifPresent(db->sb.append(db.getName()));
replicaSetName.ifPresent(rsName->appendReplicaSetParametersToURI(rsName, sb));
return new URI(sb.toString());
}
default void appendReplicaSetParametersToURI(String replicaSetName, StringBuilder uriStringBuilder) {
uriStringBuilder.append("?replicaSet=");
uriStringBuilder.append(replicaSetName);
uriStringBuilder.append("&retryWrites=true&readPreference=nearest");
}
/**
* Lists all MongoDB databases available in this end point
*/
@@ -11,25 +11,14 @@ import com.sap.sse.landscape.RotatingFileBasedLog;
public interface MongoProcess extends Process<RotatingFileBasedLog, MongoMetrics>, MongoEndpoint {
@Override
default URI getURI(Optional<Database> optionalDb) throws URISyntaxException {
return getURI(optionalDb, getHostname());
return getURI(optionalDb, getHostname(), getPort(), /* no replica set name */ Optional.empty());
}
@Override
default URI getURI(Optional<Database> optionalDb, Optional<Duration> timeoutEmptyMeaningForever) throws URISyntaxException {
return getURI(optionalDb, getHostname(timeoutEmptyMeaningForever));
return getURI(optionalDb, getHostname(timeoutEmptyMeaningForever), getPort(), /* no replica set name */ Optional.empty());
}
default URI getURI(Optional<Database> optionalDb, String hostname) throws URISyntaxException {
final StringBuilder sb = new StringBuilder();
sb.append("mongodb://");
sb.append(hostname);
sb.append(":");
sb.append(getPort());
sb.append("/");
optionalDb.ifPresent(db->sb.append(db.getName()));
return new URI(sb.toString());
}
boolean isInReplicaSet() throws URISyntaxException;
/**
@@ -49,9 +49,7 @@ public interface MongoReplicaSet extends Named, MongoEndpoint {
result.append(String.join(",", hostSpecs));
result.append("/");
optionalDb.ifPresent(db->result.append(db.getName()));
result.append("?replicaSet=");
result.append(getName());
result.append("&retryWrites=true&readPreference=nearest");
appendReplicaSetParametersToURI(getName(), result);
return new URI(result.toString());
}
@@ -1,14 +1,10 @@
package com.sap.sse.landscape.mongodb.impl;
import java.net.URISyntaxException;
import java.util.logging.Logger;
import com.sap.sse.common.impl.NamedImpl;
import com.sap.sse.landscape.mongodb.Database;
import com.sap.sse.landscape.mongodb.MongoEndpoint;
public class DatabaseImpl extends NamedImpl implements Database {
private static final Logger logger = Logger.getLogger(DatabaseImpl.class.getName());
private static final long serialVersionUID = -3816220771822620058L;
private final MongoEndpoint endpoint;
@@ -22,12 +18,6 @@ public class DatabaseImpl extends NamedImpl implements Database {
return endpoint;
}
@Override
public void drop() throws URISyntaxException {
logger.info("Dropping database "+this);
getMongoDatabase().drop();
}
@Override
public String toString() {
return "DatabaseImpl [endpoint=" + endpoint + "]";
@@ -0,0 +1,35 @@
package com.sap.sse.landscape.mongodb.impl;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.Optional;
import com.sap.sse.common.Duration;
import com.sap.sse.landscape.mongodb.Database;
public class SimpleMongoEndpointImpl extends MongoEndpointImpl {
private final String hostname;
private final int port;
private final Optional<String> replicaSetName;
public SimpleMongoEndpointImpl(String hostname, int port) {
this(hostname, port, /* no replica set name */ null);
}
public SimpleMongoEndpointImpl(String hostname, int port, String replicaSetName) {
super();
this.hostname = hostname;
this.port = port;
this.replicaSetName = Optional.ofNullable(replicaSetName);
}
@Override
public URI getURI(Optional<Database> optionalDb) throws URISyntaxException {
return getURI(optionalDb, hostname, port, replicaSetName);
}
@Override
public URI getURI(Optional<Database> optionalDb, Optional<Duration> timeoutEmptyMeaningForever) throws URISyntaxException {
return getURI(optionalDb);
}
}
@@ -26,6 +26,7 @@ import com.google.gwt.user.cellview.client.TextColumn;
import com.google.gwt.user.client.Window;
import com.google.gwt.user.client.rpc.AsyncCallback;
import com.google.gwt.user.client.ui.Label;
import com.sap.sse.common.Util;
import com.sap.sse.common.util.NaturalComparator;
import com.sap.sse.gwt.client.ErrorReporter;
import com.sap.sse.gwt.client.celltable.AbstractSortableTextColumn;
@@ -200,7 +201,7 @@ extends TableWrapper<UserDTO, S, StringMessages, TR> {
string.add(t.getFullName());
string.add(t.getEmail());
string.add(t.getCompany());
string.add(t.getUserGroups().toString());
Util.addAll(Util.map(t.getUserGroups(), StrippedUserGroupDTO::getName), string);
return string;
}
@@ -91,7 +91,8 @@ public class AbstractUserDetails extends Composite implements UserDetailsView {
StrippedUserGroupDTO defaultTennant = currentUser.getDefaultTenant();
defaultTenantUi.clear();
int i = 0;
for (StrippedUserGroupDTO group : Util.sortNamedCollection(currentUser.getUserGroups())) {
for (StrippedUserGroupDTO group : Util.sortNamedCollection(currentUser.getUserGroups(),
/* caseSensitive */ false)) {
defaultTenantUi.addItem(group.getName(), group.getId().toString());
if (Util.equalsWithNull(group, defaultTennant)) {
defaultTenantUi.setSelectedIndex(i);
+1 -1
View File
@@ -536,7 +536,7 @@
<!-- GWT version detected from dependencyManagement -->
<execution>
<configuration>
<extraJvmArgs>-Dgwt.persistentunitcache=false -Xmx2560m -Djava.io.tmpdir=${env.TMP} -Dgwt.watchFileChanges=false</extraJvmArgs>
<extraJvmArgs>-Dgwt.persistentunitcache=false -Xmx4g -Djava.io.tmpdir=${env.TMP} -Dgwt.watchFileChanges=false</extraJvmArgs>
<fragmentCount>4</fragmentCount>
<!--
<userAgents>chrome</userAgents>
+1 -1
View File
@@ -72,7 +72,7 @@ fi
JAVA_BINARY="$JAVA_HOME/bin/java"
JAVA_VERSION_OUTPUT=$("$JAVA_BINARY" -version 2>&1)
JAVA_VERSION=$(echo "$JAVA_VERSION_OUTPUT" | sed 's/^.* version "\(.*\)\.\(.*\)\..*".*$/\1.\2/; 1q')
export JAVA_11_LOGGING_ARGS="-Xlog:gc+ergo*=trace:file=logs/gc_ergo.log:time:filecount=10,filesize=100000 -Xlog:gc*:file=logs/gc.log:time:filecount=10,filesize=100000"
export JAVA_11_LOGGING_ARGS="-Xlog:gc+ergo*=trace:file=logs/gc_ergo.log:time:filecount=10,filesize=10000000 -Xlog:gc*:file=logs/gc.log:time:filecount=10,filesize=100000"
export JAVA_11_ARGS="-Dosgi.java.profile=file://`pwd`/JavaSE-11.profile --add-modules=ALL-SYSTEM -Djavax.xml.bind.JAXBContextFactory=com.sun.xml.bind.v2.ContextFactory -XX:ThreadPriorityPolicy=1 -XX:+UnlockExperimentalVMOptions -XX:+UseZGC ${JAVA_11_LOGGING_ARGS}"
export JAVA_8_LOGGING_ARGS="-XX:+PrintAdaptiveSizePolicy -XX:+PrintGCTimeStamps -XX:+PrintGCDetails -Xloggc:logs/gc.log -XX:+UseGCLogFileRotation -XX:NumberOfGCLogFiles=10 -XX:GCLogFileSize=100M"
echo JAVA_VERSION detected: $JAVA_VERSION >&2