diff --git a/java/com.sap.sailing.gwt.ui/DataMining.css b/java/com.sap.sailing.gwt.ui/DataMining.css
index 9ef6e46c92d..1818050740f 100644
--- a/java/com.sap.sailing.gwt.ui/DataMining.css
+++ b/java/com.sap.sailing.gwt.ui/DataMining.css
@@ -220,6 +220,11 @@ input.magnifier {
top: 7.5px;
}
+.orientationAnchor {
+ position: relative;
+ top: 7.5px;
+}
+
.groupingProvider {
padding: 3px 0px;
overflow-y: auto;
diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages.java
index 9cc9f2add98..2c7b5c1cd03 100755
--- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages.java
+++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages.java
@@ -962,6 +962,7 @@ public interface StringMessages extends com.sap.sse.gwt.client.StringMessages,
String raceTimeReachingTooltip();
String raceTimeUpwindTooltip();
String dataMining();
+ String changeOrientation();
String hideToolbar();
String showSeriesLeaderboards();
String showOverallLeaderboard();
diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages.properties b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages.properties
index 5d2b596d3f7..7755f0f354c 100755
--- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages.properties
+++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages.properties
@@ -954,6 +954,7 @@ raceTimeUpwindTooltip=Total time traveled upwind in this race
noCustomGrouperScriptTextError=The grouper script is empty
noGrouperSelectedError=No grouper type is selected
dataMining=Data Mining
+changeOrientation=Change Orientation
hideToolbar=Hide toolbar
showSeriesLeaderboards=Show series leaderboards
showOverallLeaderboard=Show overall leaderboard
diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages_de.properties b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages_de.properties
index 81e2722509f..493831ede52 100644
--- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages_de.properties
+++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages_de.properties
@@ -940,6 +940,7 @@ raceTimeUpwindTooltip=Die in diesem Rennen auf der Kreuz gesegelte Zeit
noCustomGrouperScriptTextError=Das Grouper-Skript leer ist
noGrouperSelectedError=Kein Gruppierungs-Typ ausgewählt ist
dataMining=Data Mining
+changeOrientation=Ausrichtung ändern
hideToolbar=Toolbar ausblenden
showSeriesLeaderboards=Ranglisten der Serie anzeigen
showOverallLeaderboard=Gesamtrangliste anzeigen
diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/datamining/DataMiningEntryPoint.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/datamining/DataMiningEntryPoint.java
index 4ef1f0133b2..b5a60161e28 100644
--- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/datamining/DataMiningEntryPoint.java
+++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/datamining/DataMiningEntryPoint.java
@@ -6,6 +6,8 @@ import java.util.logging.Logger;
import com.google.gwt.core.client.GWT;
import com.google.gwt.dom.client.Style.Unit;
+import com.google.gwt.event.dom.client.ClickEvent;
+import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.http.client.UrlBuilder;
import com.google.gwt.json.client.JSONArray;
import com.google.gwt.json.client.JSONObject;
@@ -13,6 +15,8 @@ import com.google.gwt.json.client.JSONParser;
import com.google.gwt.user.client.Window;
import com.google.gwt.user.client.rpc.AsyncCallback;
import com.google.gwt.user.client.rpc.ServiceDefTarget;
+import com.google.gwt.user.client.ui.AbstractImagePrototype;
+import com.google.gwt.user.client.ui.Anchor;
import com.google.gwt.user.client.ui.DockLayoutPanel;
import com.google.gwt.user.client.ui.RootLayoutPanel;
import com.google.gwt.user.client.ui.SplitLayoutPanel;
@@ -55,9 +59,19 @@ public class DataMiningEntryPoint extends AbstractSailingEntryPoint {
public static final ComponentResources resources = GWT.create(ComponentResources.class);
private static final Logger LOG = Logger.getLogger(DataMiningEntryPoint.class.getName());
+ private static final DataMiningResources dataMiningResources = GWT.create(DataMiningResources.class);
+
private final DataMiningServiceAsync dataMiningService = GWT.create(DataMiningService.class);
private DataMiningSession session;
+ private QueryDefinitionProviderWithControls queryDefinitionProvider;
+ private CompositeResultsPresenter> resultsPresenter;
+ private Integer resultsPresenterSouthHeight = 350;
+ private Integer resultsPresenterEastWidth = 750;
+
+ private SplitLayoutPanel queryAndResultSplitPanel;
+ private boolean queryAndResultAreVertical = true;
+
@Override
protected void doOnModuleLoad() {
Highcharts.ensureInjectedWithMore();
@@ -78,7 +92,6 @@ public class DataMiningEntryPoint extends AbstractSailingEntryPoint {
authorizedContentDecorator.setPermissionToCheck(serverInfo, ServerActions.DATA_MINING);
authorizedContentDecorator.setContentWidgetFactory(new WidgetFactory() {
- private QueryDefinitionProviderWithControls queryDefinitionProvider;
private SimpleQueryRunner queryRunner;
private final DataMiningSettingsInfoManager settingsManager = new DataMiningSettingsInfoManagerImpl(
getStringMessages());
@@ -86,7 +99,7 @@ public class DataMiningEntryPoint extends AbstractSailingEntryPoint {
@Override
public Widget get() {
DataMiningSettingsControl settingsControl = new AnchorDataMiningSettingsControl(null, null);
- CompositeResultsPresenter> resultsPresenter = new TabbedSailingResultsPresenter(/* parent */ null,
+ resultsPresenter = new TabbedSailingResultsPresenter(/* parent */ null,
/* context */ null, /* drillDownCallback */ groupKey -> {
queryDefinitionProvider.drillDown(groupKey, () -> {
queryRunner.run(queryDefinitionProvider.getQueryDefinition());
@@ -111,6 +124,18 @@ public class DataMiningEntryPoint extends AbstractSailingEntryPoint {
queryDefinitionProvider, dataMiningService, queryRunner);
queryDefinitionProvider.addControl(new StoredDataMiningQueryPanel(dataProvider));
}
+
+ Anchor orientationAnchor = new Anchor(AbstractImagePrototype.create(
+ dataMiningResources.orientationIcon()).getSafeHtml());
+ orientationAnchor.addStyleName("orientationAnchor");
+ orientationAnchor.setTitle(getStringMessages().changeOrientation());
+ orientationAnchor.addClickHandler(new ClickHandler() {
+ @Override
+ public void onClick(ClickEvent event) {
+ setQueryAndResultOrientation();
+ }
+ });
+ queryDefinitionProvider.addControl(orientationAnchor);
/*
* Running queries automatically when they've been changed is currently unnecessary, if not even
* counterproductive. This removes the query runner settings to prevent that the user can enable the
@@ -118,9 +143,8 @@ public class DataMiningEntryPoint extends AbstractSailingEntryPoint {
*/
// settingsControl.addSettingsComponent(queryRunner);
- SplitLayoutPanel splitPanel = new SplitLayoutPanel(10);
- splitPanel.addSouth(resultsPresenter.getEntryWidget(), 350);
- splitPanel.add(queryDefinitionProvider.getEntryWidget());
+ queryAndResultSplitPanel = new SplitLayoutPanel(10);
+ addDefinitionProviderAndResultPresenter();
if (queryIdentifier != null) {
if (Storage.isLocalStorageSupported()) {
@@ -153,7 +177,7 @@ public class DataMiningEntryPoint extends AbstractSailingEntryPoint {
NotificationType.ERROR);
}
}
- return splitPanel;
+ return queryAndResultSplitPanel;
}
});
@@ -165,6 +189,49 @@ public class DataMiningEntryPoint extends AbstractSailingEntryPoint {
rootPanel.add(panel);
}
+ /**
+ * Toggles the position of the {@link #resultsPresenter} from south to east and vice versa.
+ */
+ public void setQueryAndResultOrientation() {
+ setQueryAndResultOrientation(!queryAndResultAreVertical);
+ }
+ /**
+ * Sets the position of the {@link #resultsPresenter}.
+ * @param vertical {@code boolean} {@code true} places it in the south position
+ * and {@code false} in the east position.
+ */
+ public void setQueryAndResultOrientation(boolean vertical) {
+ if (vertical != queryAndResultAreVertical) {
+ // Store current size for the next orientation change
+ Double size = queryAndResultSplitPanel.getWidgetSize(resultsPresenter.getEntryWidget());
+ if (size != null) {
+ if (queryAndResultAreVertical) {
+ resultsPresenterSouthHeight = size.intValue();
+ } else {
+ resultsPresenterEastWidth = size.intValue();
+ }
+ }
+
+ queryAndResultAreVertical = vertical;
+
+ queryAndResultSplitPanel.remove(resultsPresenter.getEntryWidget());
+ // You can't add panels as long as there is a center panel so temporarily remove it
+ queryAndResultSplitPanel.remove(queryDefinitionProvider.getEntryWidget());
+
+ // Add the center panel back once the changes are made
+ addDefinitionProviderAndResultPresenter();
+ }
+ }
+
+ private void addDefinitionProviderAndResultPresenter() {
+ if (queryAndResultAreVertical) {
+ queryAndResultSplitPanel.addSouth(resultsPresenter.getEntryWidget(), resultsPresenterSouthHeight);
+ } else {
+ queryAndResultSplitPanel.addEast(resultsPresenter.getEntryWidget(), resultsPresenterEastWidth);
+ }
+ queryAndResultSplitPanel.add(queryDefinitionProvider.getEntryWidget());
+ }
+
private void removeUrlParameter() {
try {
UrlBuilder builder = Window.Location.createUrlBuilder().setHost(Window.Location.getHost())
diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/datamining/DataMiningResources.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/datamining/DataMiningResources.java
new file mode 100644
index 00000000000..40f4ab6d6f3
--- /dev/null
+++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/datamining/DataMiningResources.java
@@ -0,0 +1,9 @@
+package com.sap.sailing.gwt.ui.datamining;
+
+import com.google.gwt.resources.client.ClientBundle;
+import com.google.gwt.resources.client.ImageResource;
+
+interface DataMiningResources extends ClientBundle {
+ @Source("com/sap/sailing/gwt/ui/datamining/images/change_orientation.png")
+ ImageResource orientationIcon();
+}
diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/raceboard/tagging/TaggingPanel.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/raceboard/tagging/TaggingPanel.java
index 8d07383dd79..49ca4e32f26 100644
--- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/raceboard/tagging/TaggingPanel.java
+++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/raceboard/tagging/TaggingPanel.java
@@ -10,6 +10,7 @@ import com.google.gwt.core.shared.GWT;
import com.google.gwt.dom.client.BrowserEvents;
import com.google.gwt.user.cellview.client.CellList;
import com.google.gwt.user.cellview.client.HasKeyboardSelectionPolicy.KeyboardSelectionPolicy;
+import com.google.gwt.user.client.Random;
import com.google.gwt.user.client.rpc.AsyncCallback;
import com.google.gwt.user.client.ui.Button;
import com.google.gwt.user.client.ui.FlowPanel;
@@ -38,6 +39,7 @@ import com.sap.sse.common.impl.MillisecondsTimePoint;
import com.sap.sse.common.media.MediaTagConstants;
import com.sap.sse.gwt.client.Notification;
import com.sap.sse.gwt.client.Notification.NotificationType;
+import com.sap.sse.gwt.client.Storage;
import com.sap.sse.gwt.client.media.ImageDTO;
import com.sap.sse.gwt.client.media.ImageResizingTaskDTO;
import com.sap.sse.gwt.client.player.TimeListener;
@@ -71,6 +73,9 @@ public class TaggingPanel extends ComponentWithoutSettings
CREATE_TAG, EDIT_TAG
}
+ // HTML5 Storage for notifying other instances of tag changes
+ private static final String LOCAL_STORAGE_UPDATE_KEY = "private-tags-changed";
+
// styling
private final TagPanelStyle style;
@@ -109,6 +114,9 @@ public class TaggingPanel extends ComponentWithoutSettings
protected final TimePoint timePointToHighlight;
protected final String tagToHighlight;
+ // ID for inter-instance communication
+ private String id;
+
/**
* This boolean prevents the timer from jumping when other users create or delete tags. The timer change event is
* called by the selection change event and the other way around. When:
@@ -162,6 +170,9 @@ public class TaggingPanel extends ComponentWithoutSettings
userService.addUserStatusEventHandler(this);
raceTimesInfoProvider.addRaceTimesInfoProviderListener(this);
+ generateRandomId();
+ registerStorageEventHandler();
+
setCurrentState(State.VIEW);
initializePanel();
}
@@ -225,6 +236,38 @@ public class TaggingPanel extends ComponentWithoutSettings
updateContent();
}
+ /**
+ * Registers a storage event handler that reloads the private tags if another instance has updated them.
+ */
+ private void registerStorageEventHandler() {
+ Storage.addStorageEventHandler(event -> {
+ if (LOCAL_STORAGE_UPDATE_KEY.equals(event.getKey()) && event.getNewValue() != null
+ && !event.getNewValue().isEmpty() && !event.getNewValue().equals(id.toString())) {
+ reloadPrivateTags();
+ }
+ });
+ }
+
+ /**
+ * Notifies other instances that the private tags have changed.
+ */
+ private void firePrivateTagUpdateEvent() {
+ if (Storage.isSupported()) {
+ if (Storage.getLocalStorageIfSupported().getItem(LOCAL_STORAGE_UPDATE_KEY).equals(id)) {
+ // This instance fired the last update. To fire another one we have to change our id
+ generateRandomId();
+ }
+ Storage.getLocalStorageIfSupported().setItem(LOCAL_STORAGE_UPDATE_KEY, id);
+ }
+ }
+
+ /**
+ * Generates a new random ID
+ */
+ private void generateRandomId() {
+ id = Long.toString(System.currentTimeMillis() * Random.nextInt());
+ }
+
/**
* Updates parameters required to save/revoke {@link com.sap.sailing.domain.abstractlog.race.RaceLogEvent events}
* to/from {@link com.sap.sailing.domain.abstractlog.race.RaceLog RaceLog}.
@@ -374,6 +417,7 @@ public class TaggingPanel extends ComponentWithoutSettings
// reload private tags if added tag is private
if (!visibleForPublic) {
reloadPrivateTags();
+ firePrivateTagUpdateEvent();
}
} else {
Notification.notify(stringMessages.tagNotSavedReason(result.getMessage()),
@@ -421,6 +465,7 @@ public class TaggingPanel extends ComponentWithoutSettings
if (!silent) {
Notification.notify(stringMessages.tagRemovedSuccessfully(), NotificationType.SUCCESS);
}
+ firePrivateTagUpdateEvent();
} else {
Notification.notify(stringMessages.tagNotRemoved() + " " + result.getMessage(),
NotificationType.ERROR);
@@ -464,6 +509,7 @@ public class TaggingPanel extends ComponentWithoutSettings
// refresh UI.
if (!tagToUpdate.isVisibleForPublic() || !visibleForPublic) {
reloadPrivateTags();
+ firePrivateTagUpdateEvent();
} else {
updateContent();
}
diff --git a/java/com.sap.sailing.gwt.ui/src/main/resources/com/sap/sailing/gwt/ui/datamining/images/change_orientation.png b/java/com.sap.sailing.gwt.ui/src/main/resources/com/sap/sailing/gwt/ui/datamining/images/change_orientation.png
new file mode 100644
index 00000000000..b6b6b665ffe
Binary files /dev/null and b/java/com.sap.sailing.gwt.ui/src/main/resources/com/sap/sailing/gwt/ui/datamining/images/change_orientation.png differ
diff --git a/java/com.sap.sailing.mongodb.test/META-INF/MANIFEST.MF b/java/com.sap.sailing.mongodb.test/META-INF/MANIFEST.MF
index 2aa62a6ba5a..2ea264c5696 100644
--- a/java/com.sap.sailing.mongodb.test/META-INF/MANIFEST.MF
+++ b/java/com.sap.sailing.mongodb.test/META-INF/MANIFEST.MF
@@ -35,7 +35,8 @@ Require-Bundle: com.sap.sailing.domain,
com.sap.sailing.domain.racelogtrackingadapter,
com.sap.sailing.domain.swisstimingreplayadapter,
com.sap.sse.security,
- com.sap.sse.security.common;bundle-version="1.0.0"
+ com.sap.sse.security.common;bundle-version="1.0.0",
+ com.sap.sse.security.testsupport
Import-Package: com.sap.sailing.domain.common,
com.sap.sailing.domain.common.impl,
com.sap.sailing.domain.common.racelog,
diff --git a/java/com.sap.sailing.mongodb.test/src/com/sap/sailing/mongodb/test/TestStoringAndRetrievingLeaderboardGroups.java b/java/com.sap.sailing.mongodb.test/src/com/sap/sailing/mongodb/test/TestStoringAndRetrievingLeaderboardGroups.java
index 58da6e553f7..60545577ed4 100755
--- a/java/com.sap.sailing.mongodb.test/src/com/sap/sailing/mongodb/test/TestStoringAndRetrievingLeaderboardGroups.java
+++ b/java/com.sap.sailing.mongodb.test/src/com/sap/sailing/mongodb/test/TestStoringAndRetrievingLeaderboardGroups.java
@@ -60,6 +60,8 @@ import com.sap.sse.common.Color;
import com.sap.sse.common.Util;
import com.sap.sse.common.impl.MillisecondsTimePoint;
import com.sap.sse.mongodb.MongoDBService;
+import com.sap.sse.security.SecurityService;
+import com.sap.sse.security.testsupport.SecurityServiceMockFactory;
public class TestStoringAndRetrievingLeaderboardGroups extends AbstractMongoDBTest {
private MongoObjectFactory mongoObjectFactory = null;
@@ -115,7 +117,14 @@ public class TestStoringAndRetrievingLeaderboardGroups extends AbstractMongoDBTe
@Test
public void testStoringAndRetrievingLeaderboardGroupWithOverallLeaderboardWithScoreCorrection() throws NoWindException {
- RacingEventService racingEventService = new RacingEventServiceImpl();
+
+ final SecurityService securityService = SecurityServiceMockFactory.mockSecurityService();
+ final RacingEventService racingEventService = new RacingEventServiceImpl() {
+ @Override
+ public SecurityService getSecurityService() {
+ return securityService;
+ }
+ };
Competitor wolfgangWithoutBoat = new CompetitorImpl(123, "$$$Dr. Wolfgang+Hunger$$$", "KYC", Color.RED, null, null, new TeamImpl("STG", Collections.singleton(
new PersonImpl("$$$Dr. Wolfgang+Hunger$$$", new NationalityImpl("GER"),
/* dateOfBirth */ null, "This is famous Dr. Wolfgang Hunger")), new PersonImpl("Rigo van Maas", new NationalityImpl("NED"),
diff --git a/java/com.sap.sailing.server.replication.test/META-INF/MANIFEST.MF b/java/com.sap.sailing.server.replication.test/META-INF/MANIFEST.MF
index bf82f4c7820..abc223329dc 100644
--- a/java/com.sap.sailing.server.replication.test/META-INF/MANIFEST.MF
+++ b/java/com.sap.sailing.server.replication.test/META-INF/MANIFEST.MF
@@ -34,5 +34,6 @@ Require-Bundle: com.sap.sailing.server,
org.mongodb.mongo-java-driver;bundle-version="3.6.4",
com.sap.sse.security,
com.sap.sse.security.common,
- com.sun.jersey;bundle-version="1.17.0"
+ com.sun.jersey;bundle-version="1.17.0",
+ com.sap.sse.security.testsupport
Automatic-Module-Name: com.sap.sailing.server.replication.test
diff --git a/java/com.sap.sailing.server.replication.test/src/com/sap/sailing/server/replication/test/InitialLoadReplicationObjectIdentityTest.java b/java/com.sap.sailing.server.replication.test/src/com/sap/sailing/server/replication/test/InitialLoadReplicationObjectIdentityTest.java
index 00c3efede88..aa951b1ad21 100755
--- a/java/com.sap.sailing.server.replication.test/src/com/sap/sailing/server/replication/test/InitialLoadReplicationObjectIdentityTest.java
+++ b/java/com.sap.sailing.server.replication.test/src/com/sap/sailing/server/replication/test/InitialLoadReplicationObjectIdentityTest.java
@@ -17,9 +17,11 @@ import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.UUID;
+import java.util.concurrent.Callable;
import org.junit.Before;
import org.junit.Test;
+import org.mockito.Mockito;
import com.sap.sailing.domain.abstractlog.impl.LogEventAuthorImpl;
import com.sap.sailing.domain.abstractlog.race.RaceLog;
@@ -56,14 +58,19 @@ import com.sap.sailing.domain.leaderboard.FlexibleLeaderboard;
import com.sap.sailing.domain.leaderboard.Leaderboard;
import com.sap.sailing.domain.leaderboard.LeaderboardGroup;
import com.sap.sailing.domain.leaderboard.impl.LowPoint;
+import com.sap.sailing.domain.persistence.DomainObjectFactory;
+import com.sap.sailing.domain.persistence.MongoObjectFactory;
import com.sap.sailing.domain.persistence.PersistenceFactory;
+import com.sap.sailing.domain.persistence.media.MediaDB;
import com.sap.sailing.domain.persistence.media.MediaDBFactory;
import com.sap.sailing.domain.racelog.tracking.EmptySensorFixStore;
+import com.sap.sailing.domain.racelog.tracking.SensorFixStore;
import com.sap.sailing.domain.ranking.OneDesignRankingMetric;
import com.sap.sailing.domain.test.PositionAssert;
import com.sap.sailing.domain.test.TrackBasedTest;
import com.sap.sailing.domain.tracking.DynamicTrackedRace;
import com.sap.sailing.domain.tracking.TrackedRace;
+import com.sap.sailing.domain.tracking.WindStore;
import com.sap.sailing.domain.tracking.WindTrack;
import com.sap.sailing.domain.tracking.impl.EmptyWindStore;
import com.sap.sailing.server.impl.RacingEventServiceImpl;
@@ -81,21 +88,47 @@ import com.sap.sse.common.media.MimeType;
import com.sap.sse.replication.ReplicationMasterDescriptor;
import com.sap.sse.replication.impl.ReplicationReceiverImpl;
import com.sap.sse.replication.testsupport.AbstractServerReplicationTestSetUp.ReplicationServiceTestImpl;
+import com.sap.sse.security.SecurityService;
+import com.sap.sse.security.testsupport.SecurityServiceMockFactory;
public class InitialLoadReplicationObjectIdentityTest extends AbstractServerReplicationTest {
private Pair, ReplicationMasterDescriptor> replicationDescriptorPair;
+ private static class RacingEventServiceWithSecurityService extends RacingEventServiceImpl {
+ private final SecurityService securityService;
+
+ private RacingEventServiceWithSecurityService(final DomainObjectFactory domainObjectFactory, MongoObjectFactory mongoObjectFactory,
+ MediaDB mediaDB, WindStore windStore, SensorFixStore sensorFixStore, boolean restoreTrackedRaces, SecurityService securityService) {
+ super(domainObjectFactory, mongoObjectFactory, mediaDB, windStore, sensorFixStore, restoreTrackedRaces);
+ this.securityService = securityService;
+ }
+
+ @Override
+ public SecurityService getSecurityService() {
+ return securityService;
+ }
+ }
+
/**
* Drops the test DB. Sets up master and replica, starts the JMS message broker and registers the replica with the master.
*/
+ @SuppressWarnings("unchecked")
@Before
@Override
public void setUp() throws Exception {
persistenceSetUp(/* dropDB */ true);
- this.master = new RacingEventServiceImpl(PersistenceFactory.INSTANCE.getDomainObjectFactory(testSetUp.mongoDBService, DomainFactory.INSTANCE), PersistenceFactory.INSTANCE
- .getMongoObjectFactory(testSetUp.mongoDBService), MediaDBFactory.INSTANCE.getMediaDB(testSetUp.mongoDBService), EmptyWindStore.INSTANCE, EmptySensorFixStore.INSTANCE, /* restoreTrackedRaces */ false);
- this.replica = new RacingEventServiceImpl(PersistenceFactory.INSTANCE.getDomainObjectFactory(testSetUp.mongoDBService, DomainFactory.INSTANCE), PersistenceFactory.INSTANCE
- .getMongoObjectFactory(testSetUp.mongoDBService), MediaDBFactory.INSTANCE.getMediaDB(testSetUp.mongoDBService), EmptyWindStore.INSTANCE, EmptySensorFixStore.INSTANCE, /* restoreTrackedRaces */ false);
+ final SecurityService securityService = SecurityServiceMockFactory.mockSecurityService();
+ Mockito.when(securityService.setOwnershipCheckPermissionForObjectCreationAndRevertOnError(Mockito.any(),
+ Mockito.any(), Mockito.any(), Mockito.any(Callable.class)))
+ .thenAnswer(i -> i.getArgumentAt(3, Callable.class).call());
+ this.master = new RacingEventServiceWithSecurityService(PersistenceFactory.INSTANCE.getDomainObjectFactory(testSetUp.mongoDBService, DomainFactory.INSTANCE), PersistenceFactory.INSTANCE
+ .getMongoObjectFactory(testSetUp.mongoDBService),
+ MediaDBFactory.INSTANCE.getMediaDB(testSetUp.mongoDBService), EmptyWindStore.INSTANCE,
+ EmptySensorFixStore.INSTANCE, /* restoreTrackedRaces */ false, securityService);
+ this.replica = new RacingEventServiceWithSecurityService(PersistenceFactory.INSTANCE.getDomainObjectFactory(testSetUp.mongoDBService, DomainFactory.INSTANCE), PersistenceFactory.INSTANCE
+ .getMongoObjectFactory(testSetUp.mongoDBService),
+ MediaDBFactory.INSTANCE.getMediaDB(testSetUp.mongoDBService), EmptyWindStore.INSTANCE,
+ EmptySensorFixStore.INSTANCE, /* restoreTrackedRaces */ false, securityService);
}
private void performReplicationSetup() throws Exception {
diff --git a/java/com.sap.sailing.server.test/META-INF/MANIFEST.MF b/java/com.sap.sailing.server.test/META-INF/MANIFEST.MF
index 895f3906de2..cffcd3c6c76 100644
--- a/java/com.sap.sailing.server.test/META-INF/MANIFEST.MF
+++ b/java/com.sap.sailing.server.test/META-INF/MANIFEST.MF
@@ -24,7 +24,8 @@ Require-Bundle: com.sap.sailing.domain,
com.sap.sailing.domain.shared.android,
com.sap.sailing.domain.racelogtrackingadapter.testsupport,
com.sap.sailing.server.testsupport,
- com.sun.jersey;bundle-version="1.17.0"
+ com.sun.jersey;bundle-version="1.17.0",
+ com.sap.sse.security.testsupport
Import-Package: com.sap.sailing.server.gateway.jaxrs,
com.sap.sailing.server.gateway.jaxrs.spi,
com.sap.sse.security.userstore.mongodb,
diff --git a/java/com.sap.sailing.server.test/src/com/sap/sailing/server/test/MasterDataImportTest.java b/java/com.sap.sailing.server.test/src/com/sap/sailing/server/test/MasterDataImportTest.java
index 0679e3a175b..718a33704f8 100644
--- a/java/com.sap.sailing.server.test/src/com/sap/sailing/server/test/MasterDataImportTest.java
+++ b/java/com.sap.sailing.server.test/src/com/sap/sailing/server/test/MasterDataImportTest.java
@@ -25,6 +25,7 @@ import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.UUID;
+import java.util.concurrent.Callable;
import java.util.concurrent.ConcurrentHashMap;
import javax.ws.rs.core.Response;
@@ -190,6 +191,7 @@ public class MasterDataImportTest {
deleteAllDataFromDatabase();
}
+ @SuppressWarnings("unchecked")
@Before
public void setUp() {
UserGroupImpl defaultTenant = new UserGroupImpl(new UUID(0, 1), "defaultTenant");
@@ -213,6 +215,9 @@ public class MasterDataImportTest {
Mockito.doReturn(true).when(securityService).hasCurrentUserOneOfExplicitPermissions(
Mockito.any(WithQualifiedObjectIdentifier.class), Matchers. anyVararg());
+ Mockito.when(securityService.setOwnershipCheckPermissionForObjectCreationAndRevertOnError(Mockito.any(),
+ Mockito.any(), Mockito.any(), Mockito.any(Callable.class)))
+ .thenAnswer(i -> i.getArgumentAt(3, Callable.class).call());
Mockito.doReturn(true).when(fakeSubject).isAuthenticated();
@@ -227,7 +232,7 @@ public class MasterDataImportTest {
sourceService = Mockito
.spy(new RacingEventServiceImpl(dbFactory, mongoObjectFactory,
MediaDBFactory.INSTANCE.getDefaultMediaDB(), EmptyWindStore.INSTANCE, EmptySensorFixStore.INSTANCE,
- false));
+ false));
masterDataResource = spyResource(new DummyMasterDataRessource(), sourceService);
@@ -1879,7 +1884,13 @@ public class MasterDataImportTest {
public void testMasterDataImportForMediaTracks() throws MalformedURLException, IOException, InterruptedException,
ClassNotFoundException {
// Setup source service
- RacingEventService sourceService = new RacingEventServiceImpl();
+ RacingEventService sourceService = new RacingEventServiceImpl() {
+ @Override
+ public SecurityService getSecurityService() {
+ return securityService;
+ }
+ };
+ ;
Set assignedRaces = new HashSet();
String regattaName1 = "49er";
String regattaName2 = "49er FX";
diff --git a/java/com.sap.sailing.server.test/src/com/sap/sailing/server/test/RemoveLeaderboardGroupTest.java b/java/com.sap.sailing.server.test/src/com/sap/sailing/server/test/RemoveLeaderboardGroupTest.java
index 3e10b5d23ae..10cc1678c93 100644
--- a/java/com.sap.sailing.server.test/src/com/sap/sailing/server/test/RemoveLeaderboardGroupTest.java
+++ b/java/com.sap.sailing.server.test/src/com/sap/sailing/server/test/RemoveLeaderboardGroupTest.java
@@ -36,16 +36,25 @@ import com.sap.sailing.server.operationaltransformation.UpdateLeaderboardGroup;
import com.sap.sse.common.TimePoint;
import com.sap.sse.common.Util;
import com.sap.sse.common.impl.MillisecondsTimePoint;
+import com.sap.sse.security.SecurityService;
+import com.sap.sse.security.testsupport.SecurityServiceMockFactory;
import com.sap.sse.shared.media.ImageDescriptor;
import com.sap.sse.shared.media.VideoDescriptor;
public class RemoveLeaderboardGroupTest {
private RacingEventService server;
private Event pfingstbusch;
-
+
@Before
public void setUp() {
- server = new RacingEventServiceImpl();
+
+ final SecurityService securityService = SecurityServiceMockFactory.mockSecurityService();
+ server = new RacingEventServiceImpl() {
+ @Override
+ public SecurityService getSecurityService() {
+ return securityService;
+ }
+ };
List allEvents = new ArrayList<>();
Util.addAll(server.getAllEvents(), allEvents);
for (final Event e : allEvents) {
diff --git a/java/com.sap.sailing.server/src/com/sap/sailing/server/impl/RacingEventServiceImpl.java b/java/com.sap.sailing.server/src/com/sap/sailing/server/impl/RacingEventServiceImpl.java
index 9f7a80751f0..6c943953479 100644
--- a/java/com.sap.sailing.server/src/com/sap/sailing/server/impl/RacingEventServiceImpl.java
+++ b/java/com.sap.sailing.server/src/com/sap/sailing/server/impl/RacingEventServiceImpl.java
@@ -28,6 +28,7 @@ import java.util.Map.Entry;
import java.util.Optional;
import java.util.Set;
import java.util.UUID;
+import java.util.concurrent.Callable;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledFuture;
@@ -3025,11 +3026,21 @@ public class RacingEventServiceImpl implements RacingEventService, ClearStateTes
private void addOverallLeaderboardToLeaderboardGroup(LeaderboardGroup leaderboardGroup,
ScoringScheme scoringScheme, int[] discardThresholds) {
- Leaderboard overallLeaderboard = new LeaderboardGroupMetaLeaderboard(leaderboardGroup, scoringScheme,
+ final Leaderboard overallLeaderboard = new LeaderboardGroupMetaLeaderboard(leaderboardGroup, scoringScheme,
new ThresholdBasedResultDiscardingRuleImpl(discardThresholds));
- leaderboardGroup.setOverallLeaderboard(overallLeaderboard);
- addLeaderboard(overallLeaderboard);
- updateStoredLeaderboard(overallLeaderboard);
+ // FIXME bug5081 ownership?
+ getSecurityService().setOwnershipCheckPermissionForObjectCreationAndRevertOnError(
+ SecuredDomainType.LEADERBOARD, Leaderboard.getTypeRelativeObjectIdentifier(overallLeaderboard.getName()),
+ overallLeaderboard.getDisplayName(),
+ new Callable() {
+ @Override
+ public Void call() throws Exception {
+ leaderboardGroup.setOverallLeaderboard(overallLeaderboard);
+ addLeaderboard(overallLeaderboard);
+ updateStoredLeaderboard(overallLeaderboard);
+ return null;
+ }
+ });
}
@Override
diff --git a/java/com.sap.sse.datamining.ui/src/main/java/com/sap/sse/datamining/ui/client/selection/QueryDefinitionProviderWithControls.java b/java/com.sap.sse.datamining.ui/src/main/java/com/sap/sse/datamining/ui/client/selection/QueryDefinitionProviderWithControls.java
index f6cf540a18c..112f78ed4cb 100644
--- a/java/com.sap.sse.datamining.ui/src/main/java/com/sap/sse/datamining/ui/client/selection/QueryDefinitionProviderWithControls.java
+++ b/java/com.sap.sse.datamining.ui/src/main/java/com/sap/sse/datamining/ui/client/selection/QueryDefinitionProviderWithControls.java
@@ -11,7 +11,9 @@ import java.util.function.Consumer;
import com.google.gwt.dom.builder.shared.HtmlBuilderFactory;
import com.google.gwt.dom.builder.shared.HtmlUListBuilder;
+import com.google.gwt.dom.client.Style.Overflow;
import com.google.gwt.dom.client.Style.Unit;
+import com.google.gwt.dom.client.Style.WhiteSpace;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.i18n.client.LocaleInfo;
@@ -72,7 +74,7 @@ public class QueryDefinitionProviderWithControls extends AbstractQueryDefinition
private static final double HeaderPanelHeight = 41;
private static final double InitialQueryDefinitionViewerWidth = 600;
- private static final double InitialStatisticProviderWidth = 800;
+ private static final double InitialStatisticProviderWidth = 500;
private static final double FooterPanelHeight = 60;
private static final int SplitterSize = 10;
@@ -108,6 +110,10 @@ public class QueryDefinitionProviderWithControls extends AbstractQueryDefinition
// Creating the header panel, that contains the retriever chain provider and the controls
controlsPanel = new FlowPanel();
controlsPanel.addStyleName("dataMiningMarginBase");
+ // The following 2 lines restrict controlsPanel to using one line
+ // instead of pushing its content into the next line when there is not enough space.
+ controlsPanel.getElement().getStyle().setOverflow(Overflow.HIDDEN);
+ controlsPanel.getElement().getStyle().setWhiteSpace(WhiteSpace.NOWRAP);
this.settingsControl = settingsControl;
addControl(this.settingsControl.getEntryWidget());
diff --git a/java/com.sap.sse.gwt/src/com/sap/sse/gwt/client/celltable/TableWrapper.java b/java/com.sap.sse.gwt/src/com/sap/sse/gwt/client/celltable/TableWrapper.java
index 7fcfc3d08ae..7b5c0106046 100755
--- a/java/com.sap.sse.gwt/src/com/sap/sse/gwt/client/celltable/TableWrapper.java
+++ b/java/com.sap.sse.gwt/src/com/sap/sse/gwt/client/celltable/TableWrapper.java
@@ -110,6 +110,7 @@ public abstract class TableWrapper, SM
public void refresh(Iterable newItems) {
dataProvider.getList().clear();
Util.addAll(newItems, dataProvider.getList());
+ dataProvider.refresh();
dataProvider.flush();
}