diff --git a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/RaceTracker.java b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/RaceTracker.java
index 983f46386e1..1b4294b5070 100755
--- a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/RaceTracker.java
+++ b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/RaceTracker.java
@@ -42,7 +42,11 @@ public interface RaceTracker {
/**
* Stops tracking the races.
- * @param preemptive TODO
+ *
+ * @param preemptive
+ * if false, the tracker will continue to process data already received but will stop
+ * receiving new data. If true, the tracker will stop processing data immediately, ignoring
+ * (dropping) all data already received but not yet processed.
*/
void stop(boolean preemptive) throws MalformedURLException, IOException, InterruptedException;
diff --git a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/impl/TrackedRaceImpl.java b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/impl/TrackedRaceImpl.java
index c003915d2eb..2474c6c2297 100755
--- a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/impl/TrackedRaceImpl.java
+++ b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/impl/TrackedRaceImpl.java
@@ -260,7 +260,7 @@ public abstract class TrackedRaceImpl extends TrackedRaceWithWindEssentials impl
* these race states can be garbage-collected when the race log is no longer attached. The race states are created
* lazily, synchronizing on this weak hash map.
*/
- protected final transient WeakHashMap raceStates;
+ protected transient WeakHashMap raceStates;
protected transient ConcurrentHashMap attachedRegattaLogs;
@@ -497,6 +497,7 @@ public abstract class TrackedRaceImpl extends TrackedRaceWithWindEssentials impl
*/
private void readObject(ObjectInputStream ois) throws ClassNotFoundException, IOException, PatchFailedException {
ois.defaultReadObject();
+ raceStates = new WeakHashMap<>();
attachedRaceLogs = new ConcurrentHashMap<>();
markPassingsTimes = new ArrayList>>();
// The short time wind cache needs to be there before operations such as maneuver recalculation try to access it
@@ -3158,26 +3159,30 @@ public abstract class TrackedRaceImpl extends TrackedRaceWithWindEssentials impl
if (!legs.isEmpty()) {
if (allMarksHavePositions && numberOfMarks == 2) {
final TrackedLeg legDeterminingDirection = getLegDeterminingDirectionInWhichToPassWaypoint(waypoint);
- Distance crossTrackErrorOfMark0OnLineFromMark1ToNextWaypoint = markPositions.get(0)
- .crossTrackError(markPositions.get(1), legDeterminingDirection.getLegBearing(timePoint));
- final Position portMarkPositionWhileApproachingLine;
- final Position starboardMarkPositionWhileApproachingLine;
- final Mark starboardMarkWhileApproachingLine;
- final Mark portMarkWhileApproachingLine;
- if (crossTrackErrorOfMark0OnLineFromMark1ToNextWaypoint.getMeters() < 0) {
- portMarkWhileApproachingLine = Util.get(waypoint.getMarks(), 0);
- portMarkPositionWhileApproachingLine = markPositions.get(0);
- starboardMarkWhileApproachingLine = Util.get(waypoint.getMarks(), 1);
- starboardMarkPositionWhileApproachingLine = markPositions.get(1);
+ if (legDeterminingDirection == null) {
+ result = null;
} else {
- portMarkWhileApproachingLine = Util.get(waypoint.getMarks(), 1);
- portMarkPositionWhileApproachingLine = markPositions.get(1);
- starboardMarkWhileApproachingLine = Util.get(waypoint.getMarks(), 0);
- starboardMarkPositionWhileApproachingLine = markPositions.get(0);
+ Distance crossTrackErrorOfMark0OnLineFromMark1ToNextWaypoint = markPositions.get(0)
+ .crossTrackError(markPositions.get(1), legDeterminingDirection.getLegBearing(timePoint));
+ final Position portMarkPositionWhileApproachingLine;
+ final Position starboardMarkPositionWhileApproachingLine;
+ final Mark starboardMarkWhileApproachingLine;
+ final Mark portMarkWhileApproachingLine;
+ if (crossTrackErrorOfMark0OnLineFromMark1ToNextWaypoint.getMeters() < 0) {
+ portMarkWhileApproachingLine = Util.get(waypoint.getMarks(), 0);
+ portMarkPositionWhileApproachingLine = markPositions.get(0);
+ starboardMarkWhileApproachingLine = Util.get(waypoint.getMarks(), 1);
+ starboardMarkPositionWhileApproachingLine = markPositions.get(1);
+ } else {
+ portMarkWhileApproachingLine = Util.get(waypoint.getMarks(), 1);
+ portMarkPositionWhileApproachingLine = markPositions.get(1);
+ starboardMarkWhileApproachingLine = Util.get(waypoint.getMarks(), 0);
+ starboardMarkPositionWhileApproachingLine = markPositions.get(0);
+ }
+ result = new LineMarksWithPositions(portMarkPositionWhileApproachingLine,
+ starboardMarkPositionWhileApproachingLine, starboardMarkWhileApproachingLine,
+ portMarkWhileApproachingLine);
}
- result = new LineMarksWithPositions(portMarkPositionWhileApproachingLine,
- starboardMarkPositionWhileApproachingLine, starboardMarkWhileApproachingLine,
- portMarkWhileApproachingLine);
} else {
result = null; // either the position(s) or one or more marks is/are unknown, or the waypoint is not a two-mark waypoint
}
diff --git a/java/com.sap.sailing.feature/feature.xml b/java/com.sap.sailing.feature/feature.xml
index 94b606ebe74..2aad440fdba 100755
--- a/java/com.sap.sailing.feature/feature.xml
+++ b/java/com.sap.sailing.feature/feature.xml
@@ -1,454 +1,447 @@
-
-
-
-
+
+
+
+
The SAP Sailing Server.
Provides connectivity to a TracTrac live GPS feed as well as a live feed from an Expedition system.
-Computes leaderboard information for sailing races and offers RESTful APIs to all of this.
-
-
-
- [Enter Copyright Description here.]
-
-
-
- [Enter License Description here.]
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+Computes leaderboard information for sailing races and offers RESTful APIs to all of this.
+
+
+
+ [Enter Copyright Description here.]
+
+
+
+ [Enter License Description here.]
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/SailingService.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/SailingService.java
index 9dadbd5328d..98df542aab3 100755
--- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/SailingService.java
+++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/SailingService.java
@@ -140,7 +140,7 @@ public interface SailingService extends RemoteService, FileStorageManagementGwtS
WindInfoForRaceDTO getAveragedWindInfo(RegattaAndRaceIdentifier raceIdentifier, Date from, long millisecondsStepWidth,
int numberOfFixes, double latDeg, double lngDeg, Collection windSources) throws NoWindException;
- Boolean getPolarResults(RegattaAndRaceIdentifier raceIdentifier);
+ boolean getPolarResults(RegattaAndRaceIdentifier raceIdentifier);
SimulatorResultsDTO getSimulatorResults(RegattaAndRaceIdentifier raceIdentifier, Date from, Date prevStartTime);
diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/server/SailingServiceImpl.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/server/SailingServiceImpl.java
index 1b23ce39c06..0f886bb2f75 100755
--- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/server/SailingServiceImpl.java
+++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/server/SailingServiceImpl.java
@@ -1423,13 +1423,19 @@ public class SailingServiceImpl extends ProxiedRemoteServiceServlet implements S
}
@Override
- public Boolean getPolarResults(RegattaAndRaceIdentifier raceIdentifier) {
+ public boolean getPolarResults(RegattaAndRaceIdentifier raceIdentifier) {
+ final boolean result;
TrackedRace trackedRace = getExistingTrackedRace(raceIdentifier);
- BoatClass boatClass = trackedRace.getRace().getBoatClass();
- PolarDataService polarData = getService().getPolarDataService();
- PolarDiagram polarDiagram = new PolarDiagramGPS(boatClass, polarData);
- return new Boolean(polarDiagram != null);
- };
+ if (trackedRace == null) {
+ result = false;
+ } else {
+ BoatClass boatClass = trackedRace.getRace().getBoatClass();
+ PolarDataService polarData = getService().getPolarDataService();
+ PolarDiagram polarDiagram = new PolarDiagramGPS(boatClass, polarData);
+ result = polarDiagram != null;
+ }
+ return result;
+ }
@Override
public SimulatorResultsDTO getSimulatorResults(RegattaAndRaceIdentifier raceIdentifier, Date from, Date prevStartTime) {
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 a2b082373bd..d7c330e03df 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
@@ -190,7 +190,7 @@ public class InitialLoadReplicationObjectIdentityTest extends AbstractServerRepl
replicationDescriptorPair.getA().initialLoad();
replicator.setSuspended(false);
synchronized (replicator) {
- while (!replicator.isQueueEmpty()) {
+ while (!replicator.isQueueEmptyOrStopped()) {
replicator.wait();
}
}
diff --git a/java/com.sap.sailing.server.replication.test/src/com/sap/sailing/server/replication/test/PrematureOperationReceiptTest.java b/java/com.sap.sailing.server.replication.test/src/com/sap/sailing/server/replication/test/PrematureOperationReceiptTest.java
index 18d90dc0e82..5b34ef7f79a 100755
--- a/java/com.sap.sailing.server.replication.test/src/com/sap/sailing/server/replication/test/PrematureOperationReceiptTest.java
+++ b/java/com.sap.sailing.server.replication.test/src/com/sap/sailing/server/replication/test/PrematureOperationReceiptTest.java
@@ -60,7 +60,7 @@ public class PrematureOperationReceiptTest extends AbstractServerReplicationTest
}
replicator.setSuspended(false);
synchronized (replicator) {
- while (!replicator.isQueueEmpty()) {
+ while (!replicator.isQueueEmptyOrStopped()) {
replicator.wait();
}
}
diff --git a/java/com.sap.sailing.server.replication.test/src/com/sap/sailing/server/replication/test/TrackRaceReplicationTest.java b/java/com.sap.sailing.server.replication.test/src/com/sap/sailing/server/replication/test/TrackRaceReplicationTest.java
index f5b3eb811e8..970b2f27d40 100755
--- a/java/com.sap.sailing.server.replication.test/src/com/sap/sailing/server/replication/test/TrackRaceReplicationTest.java
+++ b/java/com.sap.sailing.server.replication.test/src/com/sap/sailing/server/replication/test/TrackRaceReplicationTest.java
@@ -129,6 +129,7 @@ public class TrackRaceReplicationTest extends AbstractServerReplicationTest {
@Test
public void testReassignmentToLeaderboardReplication() throws Exception {
+ logger.info("Running testReassignmentToLeaderboardReplication()");
final String leaderboardName = "Test Leaderboard";
Leaderboard masterLeaderboard = master.apply(new CreateFlexibleLeaderboard(leaderboardName, null, new int[0], new LowPoint(), null));
final String columnName = "R1";
@@ -153,10 +154,12 @@ public class TrackRaceReplicationTest extends AbstractServerReplicationTest {
RaceColumn column = replicaLeaderboard.getRaceColumnByName(columnName);
assertNotNull(column);
assertSame(replicaTrackedRace, column.getTrackedRace(defaultFleet));
+ logger.info("Done running testReassignmentToLeaderboardReplication()");
}
@Test
public void testRaceTimeReplication() throws InterruptedException, Exception {
+ logger.info("Running testRaceTimeReplication()");
startTracking();
// now wait at least until the start of tracking time has been received on the master copy
boolean receivedStartAndEndOfTracking = master.getTrackedRace(raceIdentifier).getStartOfTracking() != null &&
@@ -176,21 +179,27 @@ public class TrackRaceReplicationTest extends AbstractServerReplicationTest {
((DynamicTrackedRace) masterTrackedRace).setStartTimeReceived(now);
Thread.sleep(1000);
assertEquals(now, replicaTrackedRace.getStartOfRace());
+ logger.info("Done running testRaceTimeReplication()");
}
@Test
public void testWindSourcesToExcludeReplication() throws InterruptedException, Exception {
- startTracking();
- Thread.sleep(1000);
- TrackedRace replicaTrackedRace = replica.getTrackedRace(raceIdentifier);
- assertTrue(Util.isEmpty(masterTrackedRace.getWindSourcesToExclude()));
- assertTrue(Util.isEmpty(replicaTrackedRace.getWindSourcesToExclude()));
- masterTrackedRace.setWindSourcesToExclude(Collections.singleton(new WindSourceImpl(WindSourceType.WEB)));
- assertEquals(1, Util.size(masterTrackedRace.getWindSourcesToExclude()));
- assertEquals(WindSourceType.WEB, masterTrackedRace.getWindSourcesToExclude().iterator().next().getType());
- Thread.sleep(1000);
- assertEquals(1, Util.size(replicaTrackedRace.getWindSourcesToExclude()));
- assertEquals(WindSourceType.WEB, replicaTrackedRace.getWindSourcesToExclude().iterator().next().getType());
+ try {
+ logger.info("Running testWindSourcesToExcludeReplication()");
+ startTracking();
+ Thread.sleep(1000);
+ TrackedRace replicaTrackedRace = replica.getTrackedRace(raceIdentifier);
+ assertTrue(Util.isEmpty(masterTrackedRace.getWindSourcesToExclude()));
+ assertTrue(Util.isEmpty(replicaTrackedRace.getWindSourcesToExclude()));
+ masterTrackedRace.setWindSourcesToExclude(Collections.singleton(new WindSourceImpl(WindSourceType.WEB)));
+ assertEquals(1, Util.size(masterTrackedRace.getWindSourcesToExclude()));
+ assertEquals(WindSourceType.WEB, masterTrackedRace.getWindSourcesToExclude().iterator().next().getType());
+ Thread.sleep(1000);
+ assertEquals(1, Util.size(replicaTrackedRace.getWindSourcesToExclude()));
+ assertEquals(WindSourceType.WEB, replicaTrackedRace.getWindSourcesToExclude().iterator().next().getType());
+ } finally {
+ logger.info("Done running testWindSourcesToExcludeReplication()");
+ }
}
@After
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 7f343217b74..3e31806aea2 100755
--- 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
@@ -379,6 +379,8 @@ public class RacingEventServiceImpl implements RacingEventService, ClearStateTes
.withInitial(() -> false);
private final Set masterDataClassLoaders = new HashSet();
+
+ private final JoinedClassLoader joinedClassLoader;
/**
* Constructs a {@link DomainFactory base domain factory} that uses this object's {@link #competitorStore competitor
@@ -457,6 +459,7 @@ public class RacingEventServiceImpl implements RacingEventService, ClearStateTes
TypeBasedServiceFinderFactory serviceFinderFactory) {
logger.info("Created " + this);
this.masterDataClassLoaders.add(this.getClass().getClassLoader());
+ joinedClassLoader = new JoinedClassLoader(masterDataClassLoaders);
this.operationsSentToMasterForReplication = new HashSet<>();
if (windStore == null) {
try {
@@ -2291,7 +2294,7 @@ public class RacingEventServiceImpl implements RacingEventService, ClearStateTes
@Override
public ClassLoader getDeserializationClassLoader() {
- return getCombinedMasterDataClassLoader();
+ return joinedClassLoader;
}
@Override
diff --git a/java/com.sap.sse.replication.testsupport/src/com/sap/sse/replication/testsupport/AbstractServerReplicationTestSetUp.java b/java/com.sap.sse.replication.testsupport/src/com/sap/sse/replication/testsupport/AbstractServerReplicationTestSetUp.java
index 935a0058734..137a383d16d 100644
--- a/java/com.sap.sse.replication.testsupport/src/com/sap/sse/replication/testsupport/AbstractServerReplicationTestSetUp.java
+++ b/java/com.sap.sse.replication.testsupport/src/com/sap/sse/replication/testsupport/AbstractServerReplicationTestSetUp.java
@@ -179,6 +179,16 @@ public abstract class AbstractServerReplicationTestSetUp replicable = replicableProvider.getReplicable(replicableIdAsString, /* wait */ false);
if (replicable != null) {
- Thread.currentThread().setContextClassLoader(replicable.getClass().getClassLoader());
ObjectInputStream ois = new ObjectInputStream(uncompressedInputStream); // no special stream required; only reading a generic byte[]
int operationsInMessage = 0;
try {
@@ -248,11 +251,13 @@ public class ReplicationReceiver implements Runnable {
} catch (Exception e) {
logger.info("Exception while processing replica: "+e.getMessage());
logger.log(Level.SEVERE, "run", e);
- } finally {
- Thread.currentThread().setContextClassLoader(oldClassLoader);
}
}
logger.info("Stopped replicator thread. This server will no longer receive events from a master.");
+ synchronized (this) {
+ stopped = true;
+ notifyAll();
+ }
}
/**
@@ -313,9 +318,6 @@ public class ReplicationReceiver implements Runnable {
queue = new ArrayList<>();
queueByReplicableIdAsString.put(replicableIdAsString, queue);
}
- if (queue.isEmpty()) {
- notifyAll();
- }
queue.add(new Pair>(replicable.getId().toString(), operation));
assert !queue.isEmpty();
}
@@ -359,6 +361,7 @@ public class ReplicationReceiver implements Runnable {
logger.info("Signaled Replicator thread to stop asap.");
stopped = true;
master.stopConnection();
+ notifyAll(); // notify those waiting for stopped
}
public synchronized boolean isBeingStopped() {
@@ -374,8 +377,9 @@ public class ReplicationReceiver implements Runnable {
/**
* @return true if all queues for all replicables are empty
*/
- public boolean isQueueEmpty() throws IllegalAccessException {
- return (_queue == null || getInboundMessageQueue().isEmpty()) && !queueByReplicableIdAsString.values().stream().anyMatch(q->!q.isEmpty());
+ public boolean isQueueEmptyOrStopped() throws IllegalAccessException {
+ return isBeingStopped() ||
+ (_queue == null || getInboundMessageQueue().isEmpty()) && !queueByReplicableIdAsString.values().stream().anyMatch(q->!q.isEmpty());
}
}
diff --git a/java/com.sap.sse.replication/src/com/sap/sse/replication/impl/ReplicationServiceImpl.java b/java/com.sap.sse.replication/src/com/sap/sse/replication/impl/ReplicationServiceImpl.java
index c47c5677ade..15f00691519 100755
--- a/java/com.sap.sse.replication/src/com/sap/sse/replication/impl/ReplicationServiceImpl.java
+++ b/java/com.sap.sse.replication/src/com/sap/sse/replication/impl/ReplicationServiceImpl.java
@@ -246,7 +246,12 @@ public class ReplicationServiceImpl implements ReplicationService {
replicator = null;
serverUUID = UUID.randomUUID();
logger.info("Setting " + serverUUID.toString() + " as unique replication identifier.");
-
+ }
+
+ @Override
+ protected void finalize() {
+ logger.info("terminating timer "+timer);
+ timer.cancel();
}
protected ServiceTracker, Replicable, ?>> getReplicableTracker() {