58d9b23603efb15d55d66ec054d916295c83e139
java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/tracking/WithEstimatedSpeedCache.java
| ... | ... | @@ -12,6 +12,6 @@ public interface WithEstimatedSpeedCache { |
| 12 | 12 | |
| 13 | 13 | void invalidateEstimatedSpeedCache(); |
| 14 | 14 | |
| 15 | - void cacheEstimatedSpeed(SpeedWithBearing estimatedSpeed); |
|
| 15 | + SpeedWithBearing cacheEstimatedSpeed(SpeedWithBearing estimatedSpeed); |
|
| 16 | 16 | |
| 17 | 17 | } |
java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/tracking/impl/AbstractCompactGPSFixImpl.java
| ... | ... | @@ -84,7 +84,7 @@ public abstract class AbstractCompactGPSFixImpl extends AbstractGPSFixImpl { |
| 84 | 84 | } |
| 85 | 85 | |
| 86 | 86 | @Override |
| 87 | - public void invalidateCache() { |
|
| 87 | + public synchronized void invalidateCache() { |
|
| 88 | 88 | whatIsCached &= ~IS_VALIDITY_CACHED; |
| 89 | 89 | } |
| 90 | 90 | |
| ... | ... | @@ -104,12 +104,13 @@ public abstract class AbstractCompactGPSFixImpl extends AbstractGPSFixImpl { |
| 104 | 104 | } |
| 105 | 105 | |
| 106 | 106 | @Override |
| 107 | - public void invalidateEstimatedSpeedCache() { |
|
| 107 | + public synchronized void invalidateEstimatedSpeedCache() { |
|
| 108 | 108 | whatIsCached &= ~IS_ESTIMATED_SPEED_CACHED; |
| 109 | 109 | } |
| 110 | 110 | |
| 111 | 111 | @Override |
| 112 | - public void cacheEstimatedSpeed(SpeedWithBearing estimatedSpeed) { |
|
| 112 | + public synchronized SpeedWithBearing cacheEstimatedSpeed(SpeedWithBearing estimatedSpeed) { |
|
| 113 | 113 | whatIsCached |= IS_ESTIMATED_SPEED_CACHED; |
| 114 | + return super.cacheEstimatedSpeed(estimatedSpeed); |
|
| 114 | 115 | } |
| 115 | 116 | } |
java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/tracking/impl/AbstractGPSFixImpl.java
| ... | ... | @@ -96,6 +96,7 @@ public abstract class AbstractGPSFixImpl implements GPSFix { |
| 96 | 96 | } |
| 97 | 97 | |
| 98 | 98 | @Override |
| 99 | - public void cacheEstimatedSpeed(SpeedWithBearing estimatedSpeed) { |
|
| 99 | + public SpeedWithBearing cacheEstimatedSpeed(SpeedWithBearing estimatedSpeed) { |
|
| 100 | + return estimatedSpeed; |
|
| 100 | 101 | } |
| 101 | 102 | } |
java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/tracking/impl/PreciseCompactGPSFixImpl.java
| ... | ... | @@ -97,9 +97,9 @@ public class PreciseCompactGPSFixImpl extends AbstractCompactGPSFixImpl { |
| 97 | 97 | } |
| 98 | 98 | |
| 99 | 99 | @Override |
| 100 | - public void cacheEstimatedSpeed(SpeedWithBearing estimatedSpeed) { |
|
| 100 | + public SpeedWithBearing cacheEstimatedSpeed(SpeedWithBearing estimatedSpeed) { |
|
| 101 | 101 | cachedEstimatedSpeedBearingInDegrees = estimatedSpeed.getBearing().getDegrees(); |
| 102 | 102 | cachedEstimatedSpeedInKnots = estimatedSpeed.getKnots(); |
| 103 | - super.cacheEstimatedSpeed(estimatedSpeed); |
|
| 103 | + return super.cacheEstimatedSpeed(estimatedSpeed); |
|
| 104 | 104 | } |
| 105 | 105 | } |
java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/tracking/impl/PreciseCompactGPSFixMovingImpl.java
| ... | ... | @@ -154,9 +154,9 @@ public class PreciseCompactGPSFixMovingImpl extends AbstractCompactGPSFixMovingI |
| 154 | 154 | } |
| 155 | 155 | |
| 156 | 156 | @Override |
| 157 | - public void cacheEstimatedSpeed(SpeedWithBearing estimatedSpeed) { |
|
| 157 | + public SpeedWithBearing cacheEstimatedSpeed(SpeedWithBearing estimatedSpeed) { |
|
| 158 | 158 | cachedEstimatedSpeedBearingInDegrees = estimatedSpeed.getBearing().getDegrees(); |
| 159 | 159 | cachedEstimatedSpeedInKnots = estimatedSpeed.getKnots(); |
| 160 | - super.cacheEstimatedSpeed(estimatedSpeed); |
|
| 160 | + return super.cacheEstimatedSpeed(estimatedSpeed); |
|
| 161 | 161 | } |
| 162 | 162 | } |
java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/tracking/impl/VeryCompactGPSFixImpl.java
| ... | ... | @@ -7,10 +7,12 @@ import com.sap.sailing.domain.common.AbstractPosition; |
| 7 | 7 | import com.sap.sailing.domain.common.Position; |
| 8 | 8 | import com.sap.sailing.domain.common.SpeedWithBearing; |
| 9 | 9 | import com.sap.sailing.domain.common.impl.AbstractSpeedWithAbstractBearingImpl; |
| 10 | +import com.sap.sailing.domain.common.impl.KnotSpeedWithBearingImpl; |
|
| 10 | 11 | import com.sap.sailing.domain.common.tracking.GPSFix; |
| 11 | 12 | import com.sap.sse.common.AbstractBearing; |
| 12 | 13 | import com.sap.sse.common.Bearing; |
| 13 | 14 | import com.sap.sse.common.TimePoint; |
| 15 | +import com.sap.sse.common.impl.DegreeBearingImpl; |
|
| 14 | 16 | |
| 15 | 17 | /** |
| 16 | 18 | * A compact representation of a GPS fix which collects all primitive-typed attributes in one object to avoid |
| ... | ... | @@ -116,13 +118,17 @@ public class VeryCompactGPSFixImpl extends AbstractCompactGPSFixImpl { |
| 116 | 118 | * uncached. |
| 117 | 119 | */ |
| 118 | 120 | @Override |
| 119 | - public void cacheEstimatedSpeed(SpeedWithBearing estimatedSpeed) { |
|
| 121 | + public synchronized SpeedWithBearing cacheEstimatedSpeed(SpeedWithBearing estimatedSpeed) { |
|
| 120 | 122 | try { |
| 121 | 123 | cachedEstimatedSpeedInKnotsScaled = CompactPositionHelper.getKnotSpeedScaled(estimatedSpeed); |
| 122 | 124 | cachedEstimatedSpeedBearingInDegreesScaled = CompactPositionHelper.getDegreeBearingScaled(estimatedSpeed.getBearing()); |
| 123 | 125 | super.cacheEstimatedSpeed(estimatedSpeed); |
| 126 | + final SpeedWithBearing veryCompactEstimatedSpeed = getCachedEstimatedSpeed(); |
|
| 127 | + return new KnotSpeedWithBearingImpl(veryCompactEstimatedSpeed.getKnots(), |
|
| 128 | + new DegreeBearingImpl(veryCompactEstimatedSpeed.getBearing().getDegrees())); |
|
| 124 | 129 | } catch (CompactionNotPossibleException e) { |
| 125 | 130 | logger.log(Level.FINER, "Cannot cache estimated speed "+estimatedSpeed+" in compact fix:", e); |
| 131 | + return estimatedSpeed; |
|
| 126 | 132 | } |
| 127 | 133 | } |
| 128 | 134 | } |
java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/tracking/impl/VeryCompactGPSFixMovingImpl.java
| ... | ... | @@ -7,10 +7,12 @@ import com.sap.sailing.domain.common.AbstractPosition; |
| 7 | 7 | import com.sap.sailing.domain.common.Position; |
| 8 | 8 | import com.sap.sailing.domain.common.SpeedWithBearing; |
| 9 | 9 | import com.sap.sailing.domain.common.impl.AbstractSpeedWithAbstractBearingImpl; |
| 10 | +import com.sap.sailing.domain.common.impl.KnotSpeedWithBearingImpl; |
|
| 10 | 11 | import com.sap.sailing.domain.common.tracking.GPSFixMoving; |
| 11 | 12 | import com.sap.sse.common.AbstractBearing; |
| 12 | 13 | import com.sap.sse.common.Bearing; |
| 13 | 14 | import com.sap.sse.common.TimePoint; |
| 15 | +import com.sap.sse.common.impl.DegreeBearingImpl; |
|
| 14 | 16 | |
| 15 | 17 | /** |
| 16 | 18 | * A memory-conserving representation of a {@link GPSFixMoving} object that produces the fine-grained |
| ... | ... | @@ -187,13 +189,17 @@ public class VeryCompactGPSFixMovingImpl extends AbstractCompactGPSFixMovingImpl |
| 187 | 189 | * uncached. |
| 188 | 190 | */ |
| 189 | 191 | @Override |
| 190 | - public void cacheEstimatedSpeed(SpeedWithBearing estimatedSpeed) { |
|
| 192 | + public synchronized SpeedWithBearing cacheEstimatedSpeed(SpeedWithBearing estimatedSpeed) { |
|
| 191 | 193 | try { |
| 192 | 194 | cachedEstimatedSpeedInKnotsScaled = CompactPositionHelper.getKnotSpeedScaled(estimatedSpeed); |
| 193 | 195 | cachedEstimatedSpeedBearingInDegreesScaled = CompactPositionHelper.getDegreeBearingScaled(estimatedSpeed.getBearing()); |
| 194 | 196 | super.cacheEstimatedSpeed(estimatedSpeed); |
| 197 | + final SpeedWithBearing veryCompactEstimatedSpeed = getCachedEstimatedSpeed(); |
|
| 198 | + return new KnotSpeedWithBearingImpl(veryCompactEstimatedSpeed.getKnots(), |
|
| 199 | + new DegreeBearingImpl(veryCompactEstimatedSpeed.getBearing().getDegrees())); |
|
| 195 | 200 | } catch (CompactionNotPossibleException e) { |
| 196 | 201 | logger.log(Level.FINER, "Cannot cache estimated speed "+estimatedSpeed+" in compact fix:", e); |
| 202 | + return estimatedSpeed; |
|
| 197 | 203 | } |
| 198 | 204 | } |
| 199 | 205 | } |
java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/common/test/LeaderboardDTODiffingTest.java
| ... | ... | @@ -50,7 +50,7 @@ import com.sap.sse.util.ClonerImpl; |
| 50 | 50 | * <p> |
| 51 | 51 | * |
| 52 | 52 | * The data of a meaningful and non-trivial {@link LeaderboardDTO} is obtained by using an instrumented version of |
| 53 | - * <code>SailingServiceImpl.getLeaderboardByName(...)</code> which serializes the leaderboard at the end of the method |
|
| 53 | + * <code>SailingServiceImpl.getLeaderBoardByNameInternal(...)</code> which serializes the leaderboard at the end of the method |
|
| 54 | 54 | * to a file used by this test. The leaderboard that this test wants to use is that of the 505 Worlds 2013, obtained for |
| 55 | 55 | * an expanded Race R9 at time 2013-05-03T19:17:09Z after the last competitor tracked has finished the last leg. The |
| 56 | 56 | * total distance traveled in meters has to be expanded for this test to work. |
java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/impl/GPSFixTrackImpl.java
| ... | ... | @@ -275,7 +275,8 @@ public abstract class GPSFixTrackImpl<ItemType, FixType extends GPSFix> extends |
| 275 | 275 | } |
| 276 | 276 | |
| 277 | 277 | @Override |
| 278 | - public void cacheEstimatedSpeed(SpeedWithBearing estimatedSpeed) { |
|
| 278 | + public SpeedWithBearing cacheEstimatedSpeed(SpeedWithBearing estimatedSpeed) { |
|
| 279 | + return estimatedSpeed; |
|
| 279 | 280 | } |
| 280 | 281 | } |
| 281 | 282 | |
| ... | ... | @@ -633,8 +634,7 @@ public abstract class GPSFixTrackImpl<ItemType, FixType extends GPSFix> extends |
| 633 | 634 | getMillisecondsOverWhichToAverageSpeed() / 2, /* minimumConfidence */ 0.00000001)); // half confidence if half averaging interval apart |
| 634 | 635 | if (estimatedSpeed != null) { |
| 635 | 636 | if (ceil != null && ceil.getTimePoint().equals(at)) { |
| 636 | - ceil.cacheEstimatedSpeed(estimatedSpeed.getObject()); |
|
| 637 | - result = ceil.getCachedEstimatedSpeed(); // this way, should the fix apply compaction, we will still return consistent (compacted) results |
|
| 637 | + result = ceil.cacheEstimatedSpeed(estimatedSpeed.getObject()); // this way, should the fix apply compaction, we will still return consistent (compacted) results |
|
| 638 | 638 | } else { |
| 639 | 639 | result = estimatedSpeed.getObject(); |
| 640 | 640 | } |
java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/server/SailingServiceImpl.java
| ... | ... | @@ -896,7 +896,7 @@ public class SailingServiceImpl extends ResultCachingProxiedRemoteServiceServlet |
| 896 | 896 | // total distance traveled in meters has to be expanded for the test to work. |
| 897 | 897 | final boolean storeLeaderboardForTesting = false; |
| 898 | 898 | if (storeLeaderboardForTesting) { |
| 899 | - ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(new File("C:/data/SAP/sailing/workspace/java/com.sap.sailing.domain.test/resources/IncrementalLeaderboardDTO.ser"))); |
|
| 899 | + ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(new File("../com.sap.sailing.domain.test/resources/IncrementalLeaderboardDTO.ser"))); |
|
| 900 | 900 | oos.writeObject(leaderboardDTO); |
| 901 | 901 | oos.close(); |
| 902 | 902 | } |
java/com.sap.sailing.server.test/src/com/sap/sailing/server/test/MasterDataImportTest.java
| ... | ... | @@ -35,6 +35,7 @@ import javax.ws.rs.core.StreamingOutput; |
| 35 | 35 | import org.apache.shiro.SecurityUtils; |
| 36 | 36 | import org.apache.shiro.mgt.SecurityManager; |
| 37 | 37 | import org.apache.shiro.subject.Subject; |
| 38 | +import org.apache.shiro.util.ThreadContext; |
|
| 38 | 39 | import org.junit.jupiter.api.AfterEach; |
| 39 | 40 | import org.junit.jupiter.api.Assertions; |
| 40 | 41 | import org.junit.jupiter.api.BeforeEach; |
| ... | ... | @@ -194,6 +195,8 @@ public class MasterDataImportTest { |
| 194 | 195 | |
| 195 | 196 | @AfterEach |
| 196 | 197 | public void tearDown() { |
| 198 | + ThreadContext.unbindSecurityManager(); |
|
| 199 | + ThreadContext.unbindSubject(); |
|
| 197 | 200 | deleteAllDataFromDatabase(); |
| 198 | 201 | } |
| 199 | 202 | |
| ... | ... | @@ -205,8 +208,16 @@ public class MasterDataImportTest { |
| 205 | 208 | securityService = Mockito.mock(SecurityService.class); |
| 206 | 209 | SecurityManager securityManager = Mockito.mock(org.apache.shiro.mgt.SecurityManager.class); |
| 207 | 210 | Subject fakeSubject = Mockito.mock(Subject.class); |
| 208 | - SecurityUtils.setSecurityManager(securityManager); |
|
| 211 | + // Stub the mock BEFORE installing it as the global SecurityManager to avoid a race |
|
| 212 | + // condition: SecurityUtils.setSecurityManager() sets a JVM-wide static singleton. |
|
| 213 | + // Any thread that calls SecurityUtils.getSubject() (when no Subject is bound to its |
|
| 214 | + // ThreadContext) will trigger securityManager.createSubject(). If that happens between |
|
| 215 | + // the .when(securityManager) call (which sets pending doAnswer-style answers on the |
|
| 216 | + // mock's InvocationContainer) and the .createSubject() call (which completes the |
|
| 217 | + // stubbing), the other thread's call consumes the pending answers first, causing an |
|
| 218 | + // AssertionError in InvocationContainerImpl.setMethodForStubbing (line 123). |
|
| 209 | 219 | Mockito.doReturn(fakeSubject).when(securityManager).createSubject(Mockito.any()); |
| 220 | + SecurityUtils.setSecurityManager(securityManager); |
|
| 210 | 221 | Mockito.doReturn(defaultTenant).when(securityService).getServerGroup(); |
| 211 | 222 | Mockito.doReturn(currentUser).when(securityService).getCurrentUser(); |
| 212 | 223 | Mockito.doReturn(true).when(securityService).hasCurrentUserReadPermission(Mockito.any()); |
java/com.sap.sailing.server.test/src/com/sap/sailing/server/test/SearchServiceTest.java
| ... | ... | @@ -20,6 +20,8 @@ import java.util.UUID; |
| 20 | 20 | import org.apache.shiro.SecurityUtils; |
| 21 | 21 | import org.apache.shiro.mgt.SecurityManager; |
| 22 | 22 | import org.apache.shiro.subject.Subject; |
| 23 | +import org.apache.shiro.util.ThreadContext; |
|
| 24 | +import org.junit.jupiter.api.AfterEach; |
|
| 23 | 25 | import org.junit.jupiter.api.BeforeEach; |
| 24 | 26 | import org.junit.jupiter.api.Test; |
| 25 | 27 | import org.mockito.Mockito; |
| ... | ... | @@ -114,6 +116,12 @@ public class SearchServiceTest { |
| 114 | 116 | private DynamicTrackedRace aalOrcTrackedR2; |
| 115 | 117 | private SecurityService securityService; |
| 116 | 118 | |
| 119 | + @AfterEach |
|
| 120 | + public void tearDown() { |
|
| 121 | + ThreadContext.unbindSecurityManager(); |
|
| 122 | + ThreadContext.unbindSubject(); |
|
| 123 | + } |
|
| 124 | + |
|
| 117 | 125 | @BeforeEach |
| 118 | 126 | public void setUp() { |
| 119 | 127 | UserGroupImpl defaultTenant = new UserGroupImpl(new UUID(0, 1), "defaultTenant"); |
| ... | ... | @@ -121,8 +129,16 @@ public class SearchServiceTest { |
| 121 | 129 | securityService = Mockito.mock(SecurityService.class); |
| 122 | 130 | SecurityManager securityManager = Mockito.mock(org.apache.shiro.mgt.SecurityManager.class); |
| 123 | 131 | Subject fakeSubject = Mockito.mock(Subject.class); |
| 124 | - SecurityUtils.setSecurityManager(securityManager); |
|
| 132 | + // Stub the mock BEFORE installing it as the global SecurityManager to avoid a race |
|
| 133 | + // condition: SecurityUtils.setSecurityManager() sets a JVM-wide static singleton. |
|
| 134 | + // Any thread that calls SecurityUtils.getSubject() (when no Subject is bound to its |
|
| 135 | + // ThreadContext) will trigger securityManager.createSubject(). If that happens between |
|
| 136 | + // the .when(securityManager) call (which sets pending doAnswer-style answers on the |
|
| 137 | + // mock's InvocationContainer) and the .createSubject() call (which completes the |
|
| 138 | + // stubbing), the other thread's call consumes the pending answers first, causing an |
|
| 139 | + // AssertionError in InvocationContainerImpl.setMethodForStubbing (line 123). |
|
| 125 | 140 | Mockito.doReturn(fakeSubject).when(securityManager).createSubject(Mockito.any()); |
| 141 | + SecurityUtils.setSecurityManager(securityManager); |
|
| 126 | 142 | Mockito.doReturn(defaultTenant).when(securityService).getServerGroup(); |
| 127 | 143 | Mockito.doReturn(currentUser).when(securityService).getCurrentUser(); |
| 128 | 144 | Mockito.doReturn(true).when(securityService).hasCurrentUserReadPermission(Mockito.any()); |
java/com.sap.sse.common/src/com/sap/sse/common/scalablevalue/KadaneExtremeSubsequenceFinderLinkedNodesImpl.java
| ... | ... | @@ -7,6 +7,7 @@ import java.io.Serializable; |
| 7 | 7 | import java.util.Collections; |
| 8 | 8 | import java.util.Iterator; |
| 9 | 9 | import java.util.TreeSet; |
| 10 | +import java.util.concurrent.atomic.AtomicInteger; |
|
| 10 | 11 | import java.util.function.BiFunction; |
| 11 | 12 | import java.util.function.Consumer; |
| 12 | 13 | import java.util.function.Function; |
| ... | ... | @@ -63,7 +64,7 @@ public class KadaneExtremeSubsequenceFinderLinkedNodesImpl<ValueType, AveragesTo |
| 63 | 64 | */ |
| 64 | 65 | private static class Node<ValueType, AveragesTo extends Comparable<AveragesTo>, T extends ComparableScalableValueWithDistance<ValueType, AveragesTo>> implements Serializable { |
| 65 | 66 | private static final long serialVersionUID = -2547142048423135013L; |
| 66 | - private static int idCounter = 0; |
|
| 67 | + private static final AtomicInteger idCounter = new AtomicInteger(0); |
|
| 67 | 68 | private final T value; |
| 68 | 69 | private final int id; |
| 69 | 70 | private transient Node<ValueType, AveragesTo, T> previous; |
| ... | ... | @@ -75,7 +76,7 @@ public class KadaneExtremeSubsequenceFinderLinkedNodesImpl<ValueType, AveragesTo |
| 75 | 76 | |
| 76 | 77 | private Node(Node<ValueType, AveragesTo, T> previous, Node<ValueType, AveragesTo, T> next, T value) { |
| 77 | 78 | super(); |
| 78 | - id = idCounter++; |
|
| 79 | + id = idCounter.getAndIncrement(); |
|
| 79 | 80 | this.previous = previous; |
| 80 | 81 | this.next = next; |
| 81 | 82 | this.value = value; |