mirror of
https://github.com/eclipse-sailing-analytics/sailing-analytics.git
synced 2026-11-04 10:09:42 +00:00
Merge branch 'master' into ubilabs--rcapp--develop
This commit is contained in:
commit
e03cae1d39
28 files changed
+358
-92
No files matched your search
+9
-1
@@ -47,10 +47,18 @@ public interface ReadonlyRaceState extends RaceStateEventProcessor {
|
|||||||
RaceLog getRaceLog();
|
RaceLog getRaceLog();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the currently attached {@link ReadonlyRacingProcedure}.
|
* Gets the currently attached {@link ReadonlyRacingProcedure}, providing a default in case there is none provided
|
||||||
|
* in the race log nor the regatta configuration.
|
||||||
*/
|
*/
|
||||||
ReadonlyRacingProcedure getRacingProcedure();
|
ReadonlyRacingProcedure getRacingProcedure();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If no racing procedure is defined in the underlying race log, <code>null</code> is returned; otherwise
|
||||||
|
* the racing procedure as it would be returned by {@link #getRacingProcedure()}.
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
ReadonlyRacingProcedure getRacingProcedureNoFallback();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the currently attached {@link ReadonlyRacingProcedure}. Use this method to avoid casting in cases you are
|
* Gets the currently attached {@link ReadonlyRacingProcedure}. Use this method to avoid casting in cases you are
|
||||||
* sure about the {@link ReadonlyRacingProcedure}'s type.
|
* sure about the {@link ReadonlyRacingProcedure}'s type.
|
||||||
|
|||||||
+29
-5
@@ -92,7 +92,18 @@ public class ReadonlyRaceStateImpl implements ReadonlyRaceState, RaceLogChangedL
|
|||||||
private final LastPublishedCourseDesignFinder courseDesignerAnalyzer;
|
private final LastPublishedCourseDesignFinder courseDesignerAnalyzer;
|
||||||
private final LastWindFixFinder lastWindFixAnalyzer;
|
private final LastWindFixFinder lastWindFixAnalyzer;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The cached racing procedure type. If no racing procedure type specification is found in the underlying race log,
|
||||||
|
* a default is taken from {@link #fallbackInitialProcedureType}.
|
||||||
|
*/
|
||||||
private RacingProcedureType cachedRacingProcedureType;
|
private RacingProcedureType cachedRacingProcedureType;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The result of {@link #determineInitialProcedureType()}; may be {@link RacingProcedureType#UNKNOWN} in case no
|
||||||
|
* specification is found in the underlying race log.
|
||||||
|
*/
|
||||||
|
private RacingProcedureType cachedRacingProcedureTypeNoFallback;
|
||||||
|
|
||||||
private RaceLogRaceStatus cachedRaceStatus;
|
private RaceLogRaceStatus cachedRaceStatus;
|
||||||
private int cachedPassId;
|
private int cachedPassId;
|
||||||
private TimePoint cachedStartTime;
|
private TimePoint cachedStartTime;
|
||||||
@@ -130,7 +141,12 @@ public class ReadonlyRaceStateImpl implements ReadonlyRaceState, RaceLogChangedL
|
|||||||
this.courseDesignerAnalyzer = new LastPublishedCourseDesignFinder(raceLog);
|
this.courseDesignerAnalyzer = new LastPublishedCourseDesignFinder(raceLog);
|
||||||
this.lastWindFixAnalyzer = new LastWindFixFinder(raceLog);
|
this.lastWindFixAnalyzer = new LastWindFixFinder(raceLog);
|
||||||
|
|
||||||
this.cachedRacingProcedureType = determineInitialProcedureType();
|
this.cachedRacingProcedureTypeNoFallback = determineInitialProcedureType();
|
||||||
|
if (this.cachedRacingProcedureTypeNoFallback == null || this.cachedRacingProcedureTypeNoFallback == RacingProcedureType.UNKNOWN) {
|
||||||
|
this.cachedRacingProcedureType = fallbackInitialProcedureType;
|
||||||
|
} else {
|
||||||
|
cachedRacingProcedureType = cachedRacingProcedureTypeNoFallback;
|
||||||
|
}
|
||||||
this.cachedRaceStatus = RaceLogRaceStatus.UNKNOWN;
|
this.cachedRaceStatus = RaceLogRaceStatus.UNKNOWN;
|
||||||
this.cachedPassId = raceLog.getCurrentPassId();
|
this.cachedPassId = raceLog.getCurrentPassId();
|
||||||
// see resolved bug 2083: make sure the listener registration is "weak" in the sense that it is removed when
|
// see resolved bug 2083: make sure the listener registration is "weak" in the sense that it is removed when
|
||||||
@@ -148,11 +164,8 @@ public class ReadonlyRaceStateImpl implements ReadonlyRaceState, RaceLogChangedL
|
|||||||
RacingProcedureType inRaceLogType = racingProcedureAnalyzer.analyze();
|
RacingProcedureType inRaceLogType = racingProcedureAnalyzer.analyze();
|
||||||
if (inRaceLogType != RacingProcedureType.UNKNOWN) {
|
if (inRaceLogType != RacingProcedureType.UNKNOWN) {
|
||||||
return inRaceLogType;
|
return inRaceLogType;
|
||||||
} else if (configuration.getDefaultRacingProcedureType() != null
|
|
||||||
&& configuration.getDefaultRacingProcedureType() != RacingProcedureType.UNKNOWN) {
|
|
||||||
return configuration.getDefaultRacingProcedureType();
|
|
||||||
} else {
|
} else {
|
||||||
return fallbackInitialProcedureType;
|
return configuration.getDefaultRacingProcedureType();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -166,6 +179,17 @@ public class ReadonlyRaceStateImpl implements ReadonlyRaceState, RaceLogChangedL
|
|||||||
return racingProcedure;
|
return racingProcedure;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ReadonlyRacingProcedure getRacingProcedureNoFallback() {
|
||||||
|
final ReadonlyRacingProcedure result;
|
||||||
|
if (cachedRacingProcedureTypeNoFallback == null || cachedRacingProcedureTypeNoFallback == RacingProcedureType.UNKNOWN) {
|
||||||
|
result = null;
|
||||||
|
} else {
|
||||||
|
result = getRacingProcedure();
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
@Override
|
@Override
|
||||||
public <T extends ReadonlyRacingProcedure> T getTypedReadonlyRacingProcedure() {
|
public <T extends ReadonlyRacingProcedure> T getTypedReadonlyRacingProcedure() {
|
||||||
|
|||||||
+5
@@ -11,6 +11,7 @@ import org.junit.Test;
|
|||||||
|
|
||||||
import com.sap.sailing.domain.common.Position;
|
import com.sap.sailing.domain.common.Position;
|
||||||
import com.sap.sailing.domain.tractracadapter.DomainFactory;
|
import com.sap.sailing.domain.tractracadapter.DomainFactory;
|
||||||
|
import com.sap.sailing.domain.tractracadapter.LoadingQueueDoneCallBack;
|
||||||
import com.sap.sailing.domain.tractracadapter.Receiver;
|
import com.sap.sailing.domain.tractracadapter.Receiver;
|
||||||
import com.tractrac.model.lib.api.data.IPosition;
|
import com.tractrac.model.lib.api.data.IPosition;
|
||||||
import com.tractrac.model.lib.api.route.IControl;
|
import com.tractrac.model.lib.api.route.IControl;
|
||||||
@@ -73,6 +74,10 @@ public class PositionConversionTest extends AbstractTracTracLiveTest {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void callBackWhenLoadingQueueIsDone(LoadingQueueDoneCallBack callback) {
|
||||||
|
}
|
||||||
};
|
};
|
||||||
addListenersForStoredDataAndStartController(Collections.singleton(receiver));
|
addListenersForStoredDataAndStartController(Collections.singleton(receiver));
|
||||||
synchronized (semaphor) {
|
synchronized (semaphor) {
|
||||||
|
|||||||
+5
@@ -21,6 +21,7 @@ import com.sap.sailing.domain.tracking.impl.DynamicTrackedRegattaImpl;
|
|||||||
import com.sap.sailing.domain.tracking.impl.EmptyWindStore;
|
import com.sap.sailing.domain.tracking.impl.EmptyWindStore;
|
||||||
import com.sap.sailing.domain.tracking.impl.GPSFixMovingImpl;
|
import com.sap.sailing.domain.tracking.impl.GPSFixMovingImpl;
|
||||||
import com.sap.sailing.domain.tractracadapter.DomainFactory;
|
import com.sap.sailing.domain.tractracadapter.DomainFactory;
|
||||||
|
import com.sap.sailing.domain.tractracadapter.LoadingQueueDoneCallBack;
|
||||||
import com.sap.sailing.domain.tractracadapter.Receiver;
|
import com.sap.sailing.domain.tractracadapter.Receiver;
|
||||||
import com.sap.sailing.domain.tractracadapter.ReceiverType;
|
import com.sap.sailing.domain.tractracadapter.ReceiverType;
|
||||||
import com.sap.sailing.domain.tractracadapter.impl.ControlPointAdapter;
|
import com.sap.sailing.domain.tractracadapter.impl.ControlPointAdapter;
|
||||||
@@ -88,6 +89,10 @@ public class ReceiveMarkPassingDataTest extends AbstractTracTracLiveTest {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void callBackWhenLoadingQueueIsDone(LoadingQueueDoneCallBack callback) {
|
||||||
|
}
|
||||||
};
|
};
|
||||||
List<Receiver> receivers = new ArrayList<Receiver>();
|
List<Receiver> receivers = new ArrayList<Receiver>();
|
||||||
receivers.add(receiver);
|
receivers.add(receiver);
|
||||||
|
|||||||
+5
@@ -11,6 +11,7 @@ import org.junit.Test;
|
|||||||
|
|
||||||
import com.sap.sailing.domain.base.Course;
|
import com.sap.sailing.domain.base.Course;
|
||||||
import com.sap.sailing.domain.tractracadapter.DomainFactory;
|
import com.sap.sailing.domain.tractracadapter.DomainFactory;
|
||||||
|
import com.sap.sailing.domain.tractracadapter.LoadingQueueDoneCallBack;
|
||||||
import com.sap.sailing.domain.tractracadapter.Receiver;
|
import com.sap.sailing.domain.tractracadapter.Receiver;
|
||||||
import com.sap.sse.common.Util;
|
import com.sap.sse.common.Util;
|
||||||
import com.tractrac.model.lib.api.route.IControlRoute;
|
import com.tractrac.model.lib.api.route.IControlRoute;
|
||||||
@@ -67,6 +68,10 @@ public class RouteAssemblyTest extends AbstractTracTracLiveTest {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void callBackWhenLoadingQueueIsDone(LoadingQueueDoneCallBack callback) {
|
||||||
|
}
|
||||||
};
|
};
|
||||||
addListenersForStoredDataAndStartController(Collections.singleton(receiver));
|
addListenersForStoredDataAndStartController(Collections.singleton(receiver));
|
||||||
synchronized (semaphor) {
|
synchronized (semaphor) {
|
||||||
|
|||||||
+28
@@ -0,0 +1,28 @@
|
|||||||
|
package com.sap.sailing.domain.tractracadapter;
|
||||||
|
|
||||||
|
import com.sap.sailing.domain.tracking.TrackedRace;
|
||||||
|
import com.sap.sailing.domain.tractracadapter.impl.AbstractReceiverWithQueue;
|
||||||
|
import com.sap.sailing.domain.tractracadapter.impl.TracTracRaceTrackerImpl;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Callback interface which is currently used, so that {@link Receiver}s can be told to callback when current queue
|
||||||
|
* content is worked through.
|
||||||
|
*
|
||||||
|
* When loading -> tracking or loading -> finished would happen, we want to wait for all the current events in the queue
|
||||||
|
* to be handled before notifying the {@link TrackedRace}. This will ensure that caches, polar miner, etc. will not be
|
||||||
|
* resumed/started, as long as loading events are handled.
|
||||||
|
*
|
||||||
|
* @author Frederik Petersen
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public interface LoadingQueueDoneCallBack {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Callback method
|
||||||
|
* See {@link AbstractReceiverWithQueue} and {@link TracTracRaceTrackerImpl} for example usage.
|
||||||
|
*
|
||||||
|
* @param receiver Receiver that handled the marked event.
|
||||||
|
*/
|
||||||
|
void loadingQueueDone(Receiver receiver);
|
||||||
|
|
||||||
|
}
|
||||||
+19
@@ -1,5 +1,9 @@
|
|||||||
package com.sap.sailing.domain.tractracadapter;
|
package com.sap.sailing.domain.tractracadapter;
|
||||||
|
|
||||||
|
import com.sap.sailing.domain.tracking.TrackedRace;
|
||||||
|
import com.sap.sailing.domain.tracking.TrackedRaceStatus;
|
||||||
|
import com.sap.sailing.domain.tractracadapter.impl.TracTracRaceTrackerImpl;
|
||||||
|
|
||||||
|
|
||||||
public interface Receiver {
|
public interface Receiver {
|
||||||
/**
|
/**
|
||||||
@@ -34,4 +38,19 @@ public interface Receiver {
|
|||||||
* Waits until this received has stopped, but no longer than <code>timeout</code> milliseconds
|
* Waits until this received has stopped, but no longer than <code>timeout</code> milliseconds
|
||||||
*/
|
*/
|
||||||
void join(long timeoutInMilliseconds) throws InterruptedException;
|
void join(long timeoutInMilliseconds) throws InterruptedException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Allows to "mark" the currently last event in the queue and provides callback as soon as this event has been
|
||||||
|
* handled.
|
||||||
|
* <p>
|
||||||
|
*
|
||||||
|
* This is used in {@link TracTracRaceTrackerImpl} to ensure that events queued during loading phase will be
|
||||||
|
* processed before the new {@link TrackedRaceStatus} is propagated to the {@link TrackedRace}.
|
||||||
|
*
|
||||||
|
* @param callback
|
||||||
|
* {@link LoadingQueueDoneCallBack#loadingQueueDone(Receiver)} Will be called as soon as the event that
|
||||||
|
* was last in the queue at the time of calling
|
||||||
|
* {@link #callBackWhenLoadingQueueIsDone(LoadingQueueDoneCallBack)} has been handled.
|
||||||
|
*/
|
||||||
|
void callBackWhenLoadingQueueIsDone(LoadingQueueDoneCallBack callback);
|
||||||
}
|
}
|
||||||
+49
@@ -0,0 +1,49 @@
|
|||||||
|
package com.sap.sailing.domain.tractracadapter.impl;
|
||||||
|
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
import com.sap.sailing.domain.tractracadapter.LoadingQueueDoneCallBack;
|
||||||
|
import com.sap.sailing.domain.tractracadapter.Receiver;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Performs {@link #executeWhenAllReceiversAreDoneLoading()}, when all Receivers have called back.
|
||||||
|
*
|
||||||
|
* @author Frederik Petersen
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public abstract class AbstractLoadingQueueDoneCallBack implements LoadingQueueDoneCallBack {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set keeping track of all receivers that still need to callback. When it's empty, desired
|
||||||
|
* action should be performed.
|
||||||
|
*/
|
||||||
|
private final Set<Receiver> receiversToCallback;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param receivers
|
||||||
|
* All of these receivers will be queried to call back when they are done handling currently queued
|
||||||
|
* events
|
||||||
|
*/
|
||||||
|
public AbstractLoadingQueueDoneCallBack(Collection<Receiver> receivers) {
|
||||||
|
this.receiversToCallback = new HashSet<>(receivers);
|
||||||
|
for (Receiver receiver : receivers) {
|
||||||
|
receiver.callBackWhenLoadingQueueIsDone(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void loadingQueueDone(Receiver receiver) {
|
||||||
|
synchronized (this.receiversToCallback) {
|
||||||
|
receiversToCallback.remove(receiver);
|
||||||
|
if (this.receiversToCallback.isEmpty()) {
|
||||||
|
executeWhenAllReceiversAreDoneLoading();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected abstract void executeWhenAllReceiversAreDoneLoading();
|
||||||
|
|
||||||
|
}
|
||||||
+52
-4
@@ -1,6 +1,10 @@
|
|||||||
package com.sap.sailing.domain.tractracadapter.impl;
|
package com.sap.sailing.domain.tractracadapter.impl;
|
||||||
|
|
||||||
import java.util.concurrent.LinkedBlockingQueue;
|
import java.util.HashMap;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.concurrent.LinkedBlockingDeque;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
import java.util.logging.Logger;
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
@@ -11,9 +15,11 @@ import com.sap.sailing.domain.tracking.RaceTracker;
|
|||||||
import com.sap.sailing.domain.tracking.TrackedRace;
|
import com.sap.sailing.domain.tracking.TrackedRace;
|
||||||
import com.sap.sailing.domain.tracking.TrackedRegatta;
|
import com.sap.sailing.domain.tracking.TrackedRegatta;
|
||||||
import com.sap.sailing.domain.tractracadapter.DomainFactory;
|
import com.sap.sailing.domain.tractracadapter.DomainFactory;
|
||||||
|
import com.sap.sailing.domain.tractracadapter.LoadingQueueDoneCallBack;
|
||||||
import com.sap.sailing.domain.tractracadapter.Receiver;
|
import com.sap.sailing.domain.tractracadapter.Receiver;
|
||||||
import com.tractrac.model.lib.api.event.IEvent;
|
|
||||||
import com.sap.sse.common.Util;
|
import com.sap.sse.common.Util;
|
||||||
|
import com.sap.sse.common.Util.Triple;
|
||||||
|
import com.tractrac.model.lib.api.event.IEvent;
|
||||||
import com.tractrac.model.lib.api.event.IRace;
|
import com.tractrac.model.lib.api.event.IRace;
|
||||||
import com.tractrac.subscription.lib.api.IEventSubscriber;
|
import com.tractrac.subscription.lib.api.IEventSubscriber;
|
||||||
import com.tractrac.subscription.lib.api.IRaceSubscriber;
|
import com.tractrac.subscription.lib.api.IRaceSubscriber;
|
||||||
@@ -29,7 +35,7 @@ import com.tractrac.subscription.lib.api.IRaceSubscriber;
|
|||||||
public abstract class AbstractReceiverWithQueue<A, B, C> implements Runnable, Receiver {
|
public abstract class AbstractReceiverWithQueue<A, B, C> implements Runnable, Receiver {
|
||||||
private static Logger logger = Logger.getLogger(AbstractReceiverWithQueue.class.getName());
|
private static Logger logger = Logger.getLogger(AbstractReceiverWithQueue.class.getName());
|
||||||
|
|
||||||
private final LinkedBlockingQueue<Util.Triple<A, B, C>> queue;
|
private final LinkedBlockingDeque<Util.Triple<A, B, C>> queue;
|
||||||
private final DomainFactory domainFactory;
|
private final DomainFactory domainFactory;
|
||||||
private final IEvent tractracEvent;
|
private final IEvent tractracEvent;
|
||||||
private final IEventSubscriber eventSubscriber;
|
private final IEventSubscriber eventSubscriber;
|
||||||
@@ -37,6 +43,7 @@ public abstract class AbstractReceiverWithQueue<A, B, C> implements Runnable, Re
|
|||||||
private final DynamicTrackedRegatta trackedRegatta;
|
private final DynamicTrackedRegatta trackedRegatta;
|
||||||
private final Simulator simulator;
|
private final Simulator simulator;
|
||||||
private final Thread thread;
|
private final Thread thread;
|
||||||
|
private final Map<Util.Triple<A, B, C>, Set<LoadingQueueDoneCallBack>> loadingQueueDoneCallBacks;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* used by {@link #stopAfterNotReceivingEventsForSomeTime(long)} and {@link #run()} to check if an event was received
|
* used by {@link #stopAfterNotReceivingEventsForSomeTime(long)} and {@link #run()} to check if an event was received
|
||||||
@@ -53,8 +60,9 @@ public abstract class AbstractReceiverWithQueue<A, B, C> implements Runnable, Re
|
|||||||
this.trackedRegatta = trackedRegatta;
|
this.trackedRegatta = trackedRegatta;
|
||||||
this.domainFactory = domainFactory;
|
this.domainFactory = domainFactory;
|
||||||
this.simulator = simulator;
|
this.simulator = simulator;
|
||||||
this.queue = new LinkedBlockingQueue<Util.Triple<A, B, C>>();
|
this.queue = new LinkedBlockingDeque<Util.Triple<A, B, C>>();
|
||||||
this.thread = new Thread(this, getClass().getName());
|
this.thread = new Thread(this, getClass().getName());
|
||||||
|
this.loadingQueueDoneCallBacks = new HashMap<>();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected IEventSubscriber getEventSubscriber() {
|
protected IEventSubscriber getEventSubscriber() {
|
||||||
@@ -136,6 +144,28 @@ public abstract class AbstractReceiverWithQueue<A, B, C> implements Runnable, Re
|
|||||||
if (!isStopEvent(event)) {
|
if (!isStopEvent(event)) {
|
||||||
handleEvent(event);
|
handleEvent(event);
|
||||||
}
|
}
|
||||||
|
final Set<LoadingQueueDoneCallBack> callBacks;
|
||||||
|
synchronized (loadingQueueDoneCallBacks) {
|
||||||
|
if (getSimulator() != null) {
|
||||||
|
// when simulator is running, loading is considered finished and all callbacks will
|
||||||
|
// be satisfied instantly
|
||||||
|
callBacks = new HashSet<>();
|
||||||
|
for (Set<LoadingQueueDoneCallBack> set : loadingQueueDoneCallBacks.values()) {
|
||||||
|
callBacks.addAll(set);
|
||||||
|
}
|
||||||
|
loadingQueueDoneCallBacks.clear();
|
||||||
|
} else {
|
||||||
|
// otherwise, check only if there are callbacks that registered at the event
|
||||||
|
// currently consumed and notify if any are found
|
||||||
|
callBacks = loadingQueueDoneCallBacks.remove(event);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (callBacks != null) {
|
||||||
|
for (LoadingQueueDoneCallBack callback : callBacks) {
|
||||||
|
callback.loadingQueueDone(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
} catch (InterruptedException e) {
|
} catch (InterruptedException e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
}
|
}
|
||||||
@@ -180,4 +210,22 @@ public abstract class AbstractReceiverWithQueue<A, B, C> implements Runnable, Re
|
|||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void callBackWhenLoadingQueueIsDone(LoadingQueueDoneCallBack callback) {
|
||||||
|
synchronized (loadingQueueDoneCallBacks) {
|
||||||
|
Triple<A, B, C> lastInQueue = queue.peekLast();
|
||||||
|
// when simulator is attached, consider loading already done; the simulator simulates "live" tracking
|
||||||
|
if (lastInQueue == null || getSimulator() != null) {
|
||||||
|
callback.loadingQueueDone(this);
|
||||||
|
} else {
|
||||||
|
Set<LoadingQueueDoneCallBack> set = loadingQueueDoneCallBacks.get(lastInQueue);
|
||||||
|
if (set == null) {
|
||||||
|
set = new HashSet<>();
|
||||||
|
loadingQueueDoneCallBacks.put(lastInQueue, set);
|
||||||
|
}
|
||||||
|
set.add(callback);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
+33
-4
@@ -510,9 +510,21 @@ public class TracTracRaceTrackerImpl extends AbstractRaceTrackerImpl implements
|
|||||||
receiver.stopAfterProcessingQueuedEvents();
|
receiver.stopAfterProcessingQueuedEvents();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (!stopReceiversPreemtively) {
|
||||||
|
// wait for their queues to be worked down before signalling the FINISHED state.
|
||||||
|
new AbstractLoadingQueueDoneCallBack(receivers) {
|
||||||
|
@Override
|
||||||
|
protected void executeWhenAllReceiversAreDoneLoading() {
|
||||||
lastStatus = new TrackedRaceStatusImpl(TrackedRaceStatusEnum.FINISHED, /* will be ignored */1.0);
|
lastStatus = new TrackedRaceStatusImpl(TrackedRaceStatusEnum.FINISHED, /* will be ignored */1.0);
|
||||||
updateStatusOfTrackedRaces();
|
updateStatusOfTrackedRaces();
|
||||||
}
|
}
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
// queues contents were cleared preemptively; this means we're done with loading immediately
|
||||||
|
lastStatus = new TrackedRaceStatusImpl(TrackedRaceStatusEnum.FINISHED, /* will be ignored */1.0);
|
||||||
|
updateStatusOfTrackedRaces();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -577,7 +589,16 @@ public class TracTracRaceTrackerImpl extends AbstractRaceTrackerImpl implements
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
logger.info("Stored data progress in tracker "+getID()+" for race(s) "+getRaces()+": "+progress);
|
logger.info("Stored data progress in tracker "+getID()+" for race(s) "+getRaces()+": "+progress);
|
||||||
lastStatus = new TrackedRaceStatusImpl(progress==1.0 ? TrackedRaceStatusEnum.TRACKING : TrackedRaceStatusEnum.LOADING, progress);
|
lastStatus = new TrackedRaceStatusImpl(TrackedRaceStatusEnum.LOADING, progress);
|
||||||
|
if (progress==1.0) {
|
||||||
|
new AbstractLoadingQueueDoneCallBack(receivers) {
|
||||||
|
@Override
|
||||||
|
protected void executeWhenAllReceiversAreDoneLoading() {
|
||||||
|
lastStatus = new TrackedRaceStatusImpl(TrackedRaceStatusEnum.TRACKING, progress);
|
||||||
|
updateStatusOfTrackedRaces();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
lastProgressPerID.put(getID(), new Util.Pair<Integer, Float>(counter, progress));
|
lastProgressPerID.put(getID(), new Util.Pair<Integer, Float>(counter, progress));
|
||||||
updateStatusOfTrackedRaces();
|
updateStatusOfTrackedRaces();
|
||||||
}
|
}
|
||||||
@@ -620,14 +641,20 @@ public class TracTracRaceTrackerImpl extends AbstractRaceTrackerImpl implements
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void stopped(Object o) {
|
public void stopped(Object o) {
|
||||||
logger.info("stopped TracTrac tracking in tracker "+getID()+" for "+getRaces()+" while in status "+lastStatus);
|
logger.info("stopped TracTrac tracking in tracker " + getID() + " for " + getRaces() + " while in status "
|
||||||
|
+ lastStatus);
|
||||||
|
new AbstractLoadingQueueDoneCallBack(receivers) {
|
||||||
|
@Override
|
||||||
|
protected void executeWhenAllReceiversAreDoneLoading() {
|
||||||
lastStatus = new TrackedRaceStatusImpl(TrackedRaceStatusEnum.FINISHED, 1.0);
|
lastStatus = new TrackedRaceStatusImpl(TrackedRaceStatusEnum.FINISHED, 1.0);
|
||||||
updateStatusOfTrackedRaces();
|
updateStatusOfTrackedRaces();
|
||||||
if (!stopped) {
|
if (!stopped) {
|
||||||
try {
|
try {
|
||||||
for (RaceDefinition race : getRaces()) {
|
for (RaceDefinition race : getRaces()) {
|
||||||
// See also bug 1517; with TracAPI we assume that when stopped(IEvent) is called by the TracAPI then
|
// See also bug 1517; with TracAPI we assume that when stopped(IEvent) is called by the
|
||||||
// all subscriptions have received all their data and it's therefore safe to stop all subscriptions
|
// TracAPI then
|
||||||
|
// all subscriptions have received all their data and it's therefore safe to stop all
|
||||||
|
// subscriptions
|
||||||
// at this point without missing any data.
|
// at this point without missing any data.
|
||||||
trackedRegattaRegistry.stopTracking(regatta, race);
|
trackedRegattaRegistry.stopTracking(regatta, race);
|
||||||
}
|
}
|
||||||
@@ -636,6 +663,8 @@ public class TracTracRaceTrackerImpl extends AbstractRaceTrackerImpl implements
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public GPSFixStore getGPSFixStore() {
|
public GPSFixStore getGPSFixStore() {
|
||||||
|
|||||||
+1
-1
@@ -45,7 +45,7 @@ public class MarkPassingUpdateListener extends AbstractRaceChangeListener {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void statusChanged(TrackedRaceStatus newStatus) {
|
public void statusChanged(TrackedRaceStatus newStatus, TrackedRaceStatus oldStatus) {
|
||||||
if (newStatus.getStatus() == TrackedRaceStatusEnum.FINISHED) {
|
if (newStatus.getStatus() == TrackedRaceStatusEnum.FINISHED) {
|
||||||
queue.add(end);
|
queue.add(end);
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-1
@@ -50,5 +50,5 @@ public interface RaceChangeListener extends CourseListener {
|
|||||||
|
|
||||||
void windSourcesToExcludeChanged(Iterable<? extends WindSource> windSourcesToExclude);
|
void windSourcesToExcludeChanged(Iterable<? extends WindSource> windSourcesToExclude);
|
||||||
|
|
||||||
void statusChanged(TrackedRaceStatus newStatus);
|
void statusChanged(TrackedRaceStatus newStatus, TrackedRaceStatus oldStatus);
|
||||||
}
|
}
|
||||||
+1
-1
@@ -40,7 +40,7 @@ public abstract class AbstractRaceChangeListener implements RaceChangeListener {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void statusChanged(TrackedRaceStatus newStatus) {
|
public void statusChanged(TrackedRaceStatus newStatus, TrackedRaceStatus oldStatus) {
|
||||||
defaultAction();
|
defaultAction();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+7
-3
@@ -147,8 +147,9 @@ DynamicTrackedRace, GPSTrackListener<Competitor, GPSFixMoving> {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setStatus(TrackedRaceStatus newStatus) {
|
public void setStatus(TrackedRaceStatus newStatus) {
|
||||||
|
TrackedRaceStatus oldStatus = getStatus();
|
||||||
super.setStatus(newStatus);
|
super.setStatus(newStatus);
|
||||||
notifyListeners(newStatus);
|
notifyListeners(newStatus, oldStatus);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -189,7 +190,10 @@ DynamicTrackedRace, GPSTrackListener<Competitor, GPSFixMoving> {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setAndFixDelayToLiveInMillis(long delayToLiveInMillis) {
|
public void setAndFixDelayToLiveInMillis(long delayToLiveInMillis) {
|
||||||
|
if (getDelayToLiveInMillis() != delayToLiveInMillis) {
|
||||||
super.setDelayToLiveInMillis(delayToLiveInMillis);
|
super.setDelayToLiveInMillis(delayToLiveInMillis);
|
||||||
|
notifyListenersDelayToLiveChanged(delayToLiveInMillis);
|
||||||
|
}
|
||||||
delayToLiveInMillisFixed = true;
|
delayToLiveInMillisFixed = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -415,8 +419,8 @@ DynamicTrackedRace, GPSTrackListener<Competitor, GPSFixMoving> {
|
|||||||
notifyListeners(listener -> listener.competitorPositionChanged(fix, competitor));
|
notifyListeners(listener -> listener.competitorPositionChanged(fix, competitor));
|
||||||
}
|
}
|
||||||
|
|
||||||
private void notifyListeners(TrackedRaceStatus status) {
|
private void notifyListeners(TrackedRaceStatus status, TrackedRaceStatus oldStatus) {
|
||||||
notifyListeners(listener -> listener.statusChanged(status));
|
notifyListeners(listener -> listener.statusChanged(status, oldStatus));
|
||||||
}
|
}
|
||||||
|
|
||||||
private void notifyListeners(Wind wind, WindSource windSource) {
|
private void notifyListeners(Wind wind, WindSource windSource) {
|
||||||
|
|||||||
+1
-1
@@ -667,7 +667,7 @@ public class TrackBasedEstimationWindTrackImpl extends VirtualWindTrackImpl {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void statusChanged(TrackedRaceStatus newStatus) {
|
public void statusChanged(TrackedRaceStatus newStatus, TrackedRaceStatus oldStatus) {
|
||||||
// This virtual wind track's cache can cope with an empty cache after the LOADING phase and populates the
|
// This virtual wind track's cache can cope with an empty cache after the LOADING phase and populates the
|
||||||
// cache
|
// cache
|
||||||
// upon request. Invalidation happens also during the LOADING phase, preserving the cache's invariant.
|
// upon request. Invalidation happens also during the LOADING phase, preserving the cache's invariant.
|
||||||
|
|||||||
+1
-1
@@ -269,7 +269,7 @@ public class TrackedLegImpl implements TrackedLeg {
|
|||||||
* no-op; the leg doesn't mind the tracked race's status being updated
|
* no-op; the leg doesn't mind the tracked race's status being updated
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void statusChanged(TrackedRaceStatus newStatus) {
|
public void statusChanged(TrackedRaceStatus newStatus, TrackedRaceStatus oldStatus) {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
+24
-3
@@ -22,6 +22,7 @@ import java.util.NavigableSet;
|
|||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.Timer;
|
import java.util.Timer;
|
||||||
import java.util.TimerTask;
|
import java.util.TimerTask;
|
||||||
|
import java.util.WeakHashMap;
|
||||||
import java.util.concurrent.Callable;
|
import java.util.concurrent.Callable;
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
import java.util.concurrent.ConcurrentSkipListSet;
|
import java.util.concurrent.ConcurrentSkipListSet;
|
||||||
@@ -251,6 +252,13 @@ public abstract class TrackedRaceImpl extends TrackedRaceWithWindEssentials impl
|
|||||||
|
|
||||||
protected transient ConcurrentHashMap<Serializable, RaceLog> attachedRaceLogs;
|
protected transient ConcurrentHashMap<Serializable, RaceLog> attachedRaceLogs;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Holds optional race states for the race logs in {@link #attachedRaceLogs}. By using a {@link WeakHashMap},
|
||||||
|
* 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<RaceLog, ReadonlyRaceState> raceStates;
|
||||||
|
|
||||||
protected transient ConcurrentHashMap<Serializable, RegattaLog> attachedRegattaLogs;
|
protected transient ConcurrentHashMap<Serializable, RegattaLog> attachedRegattaLogs;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -304,6 +312,7 @@ public abstract class TrackedRaceImpl extends TrackedRaceWithWindEssentials impl
|
|||||||
long delayToLiveInMillis, final long millisecondsOverWhichToAverageWind,
|
long delayToLiveInMillis, final long millisecondsOverWhichToAverageWind,
|
||||||
long millisecondsOverWhichToAverageSpeed, long delayForWindEstimationCacheInvalidation) {
|
long millisecondsOverWhichToAverageSpeed, long delayForWindEstimationCacheInvalidation) {
|
||||||
super(race, trackedRegatta, windStore, millisecondsOverWhichToAverageWind);
|
super(race, trackedRegatta, windStore, millisecondsOverWhichToAverageWind);
|
||||||
|
raceStates = new WeakHashMap<>();
|
||||||
shortTimeWindCache = new ShortTimeWindCache(this, millisecondsOverWhichToAverageWind / 2);
|
shortTimeWindCache = new ShortTimeWindCache(this, millisecondsOverWhichToAverageWind / 2);
|
||||||
locksForMarkPassings = new IdentityHashMap<>();
|
locksForMarkPassings = new IdentityHashMap<>();
|
||||||
attachedRaceLogs = new ConcurrentHashMap<>();
|
attachedRaceLogs = new ConcurrentHashMap<>();
|
||||||
@@ -2844,6 +2853,18 @@ public abstract class TrackedRaceImpl extends TrackedRaceWithWindEssentials impl
|
|||||||
loadFixesForLog(raceLog, attachedRaceLogs);
|
loadFixesForLog(raceLog, attachedRaceLogs);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private ReadonlyRaceState getRaceState(RaceLog raceLog) {
|
||||||
|
ReadonlyRaceState result;
|
||||||
|
synchronized (raceStates) {
|
||||||
|
result = raceStates.get(raceLog);
|
||||||
|
if (result == null) {
|
||||||
|
result = RaceStateImpl.create(raceLog);
|
||||||
|
raceStates.put(raceLog, result);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void attachRegattaLog(RegattaLog regattaLog) {
|
public void attachRegattaLog(RegattaLog regattaLog) {
|
||||||
loadFixesForLog(regattaLog, attachedRegattaLogs);
|
loadFixesForLog(regattaLog, attachedRegattaLogs);
|
||||||
@@ -3312,8 +3333,8 @@ public abstract class TrackedRaceImpl extends TrackedRaceWithWindEssentials impl
|
|||||||
public Boolean isGateStart() {
|
public Boolean isGateStart() {
|
||||||
Boolean result = null;
|
Boolean result = null;
|
||||||
for (RaceLog raceLog : attachedRaceLogs.values()) {
|
for (RaceLog raceLog : attachedRaceLogs.values()) {
|
||||||
ReadonlyRaceState raceState = RaceStateImpl.create(raceLog);
|
ReadonlyRaceState raceState = getRaceState(raceLog);
|
||||||
ReadonlyRacingProcedure procedure = raceState.getRacingProcedure();
|
ReadonlyRacingProcedure procedure = raceState.getRacingProcedureNoFallback();
|
||||||
if (procedure != null && procedure.getType() != null) {
|
if (procedure != null && procedure.getType() != null) {
|
||||||
result = procedure.getType() == RacingProcedureType.GateStart;
|
result = procedure.getType() == RacingProcedureType.GateStart;
|
||||||
break;
|
break;
|
||||||
@@ -3327,7 +3348,7 @@ public abstract class TrackedRaceImpl extends TrackedRaceWithWindEssentials impl
|
|||||||
final Distance result;
|
final Distance result;
|
||||||
final Leg startLeg = getRace().getCourse().getFirstLeg();
|
final Leg startLeg = getRace().getCourse().getFirstLeg();
|
||||||
final TrackedLegOfCompetitor competitorLeg;
|
final TrackedLegOfCompetitor competitorLeg;
|
||||||
if (startLeg != null && isGateStart() == true && (competitorLeg=getTrackedLeg(competitor, startLeg)).hasStartedLeg(timePoint)) {
|
if (startLeg != null && isGateStart() == Boolean.TRUE && (competitorLeg=getTrackedLeg(competitor, startLeg)).hasStartedLeg(timePoint)) {
|
||||||
TimePoint competitorLegStartTime = competitorLeg.getStartTime();
|
TimePoint competitorLegStartTime = competitorLeg.getStartTime();
|
||||||
final Mark portMarkOfStartLine = getStartLine(competitorLegStartTime).getPortMarkWhileApproachingLine();
|
final Mark portMarkOfStartLine = getStartLine(competitorLegStartTime).getPortMarkWhileApproachingLine();
|
||||||
final Position portSideOfStartLinePosition = getOrCreateTrack(portMarkOfStartLine)
|
final Position portSideOfStartLinePosition = getOrCreateTrack(portMarkOfStartLine)
|
||||||
|
|||||||
+1
-1
@@ -110,7 +110,7 @@ eventRegattaRacesLegendWind=Wind Data
|
|||||||
eventRegattaRacesLegendVideo=Video Stream
|
eventRegattaRacesLegendVideo=Video Stream
|
||||||
eventRegattaRacesLegendAudio=Audio Stream
|
eventRegattaRacesLegendAudio=Audio Stream
|
||||||
eventSponsorsTitle=Event Sponsorships
|
eventSponsorsTitle=Event Sponsorships
|
||||||
footerCopyright=\u00A9 2014 SAP Sailing Analytics
|
footerCopyright=\u00A9 2015 SAP Sailing Analytics
|
||||||
footerLanguage=SAP Sailing offered in
|
footerLanguage=SAP Sailing offered in
|
||||||
footerLegal=Legal Disclosure
|
footerLegal=Legal Disclosure
|
||||||
footerPrivacy=Privacy
|
footerPrivacy=Privacy
|
||||||
|
|||||||
+1
-1
@@ -110,7 +110,7 @@ eventRegattaRacesLegendWind=Winddaten
|
|||||||
eventRegattaRacesLegendVideo=Video Stream
|
eventRegattaRacesLegendVideo=Video Stream
|
||||||
eventRegattaRacesLegendAudio=Audio Stream
|
eventRegattaRacesLegendAudio=Audio Stream
|
||||||
eventSponsorsTitle=Veranstaltungssponsoren
|
eventSponsorsTitle=Veranstaltungssponsoren
|
||||||
footerCopyright=\u00A9 2014 SAP Sailing Analytics
|
footerCopyright=\u00A9 2015 SAP Sailing Analytics
|
||||||
footerLanguage=SAP Sailing in
|
footerLanguage=SAP Sailing in
|
||||||
footerLegal=Impressum
|
footerLegal=Impressum
|
||||||
footerPrivacy=Datenschutz
|
footerPrivacy=Datenschutz
|
||||||
|
|||||||
@@ -194,5 +194,5 @@ public interface PolarDataService {
|
|||||||
*/
|
*/
|
||||||
PolynomialFunction getAngleRegressionFunction(BoatClass boatClass, LegType legType, Tack tack) throws NotEnoughDataHasBeenAddedException;
|
PolynomialFunction getAngleRegressionFunction(BoatClass boatClass, LegType legType, Tack tack) throws NotEnoughDataHasBeenAddedException;
|
||||||
|
|
||||||
void raceFinishedTracking(TrackedRace race);
|
void raceFinishedLoading(TrackedRace race);
|
||||||
}
|
}
|
||||||
+1
-1
@@ -148,7 +148,7 @@ public class PolarDataServiceImpl implements PolarDataService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void raceFinishedTracking(TrackedRace race) {
|
public void raceFinishedLoading(TrackedRace race) {
|
||||||
polarDataMiner.raceFinishedTracking(race);
|
polarDataMiner.raceFinishedTracking(race);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -43,7 +43,7 @@ import com.sap.sailing.domain.tracking.TrackedRace;
|
|||||||
import com.sap.sailing.polars.impl.CubicEquation;
|
import com.sap.sailing.polars.impl.CubicEquation;
|
||||||
import com.sap.sailing.polars.regression.NotEnoughDataHasBeenAddedException;
|
import com.sap.sailing.polars.regression.NotEnoughDataHasBeenAddedException;
|
||||||
import com.sap.sse.common.Util.Pair;
|
import com.sap.sse.common.Util.Pair;
|
||||||
import com.sap.sse.common.impl.MillisecondsTimePoint;
|
import com.sap.sse.datamining.components.FilterCriterion;
|
||||||
import com.sap.sse.datamining.components.Processor;
|
import com.sap.sse.datamining.components.Processor;
|
||||||
import com.sap.sse.datamining.data.ClusterGroup;
|
import com.sap.sse.datamining.data.ClusterGroup;
|
||||||
import com.sap.sse.datamining.functions.Function;
|
import com.sap.sse.datamining.functions.Function;
|
||||||
@@ -58,7 +58,7 @@ public class PolarDataMiner {
|
|||||||
private static final int THREAD_POOL_SIZE = Math.max((int) (Runtime.getRuntime().availableProcessors() * (3.0/4.0)), 3);
|
private static final int THREAD_POOL_SIZE = Math.max((int) (Runtime.getRuntime().availableProcessors() * (3.0/4.0)), 3);
|
||||||
private final ThreadPoolExecutor executor = createExecutor();
|
private final ThreadPoolExecutor executor = createExecutor();
|
||||||
private final PolarSheetGenerationSettings backendPolarSheetGenerationSettings;
|
private final PolarSheetGenerationSettings backendPolarSheetGenerationSettings;
|
||||||
private final Map<TrackedRace, Set<GPSFixMovingWithOriginInfo>> fixesForReplayRacesWhichAreStillLoading = new HashMap<>();
|
private final Map<TrackedRace, Set<GPSFixMovingWithOriginInfo>> fixesForRacesWhichAreStillLoading = new HashMap<>();
|
||||||
|
|
||||||
private final Queue<GPSFixMovingWithOriginInfo> fixQueue = new ConcurrentLinkedQueue<GPSFixMovingWithOriginInfo>();
|
private final Queue<GPSFixMovingWithOriginInfo> fixQueue = new ConcurrentLinkedQueue<GPSFixMovingWithOriginInfo>();
|
||||||
|
|
||||||
@@ -79,14 +79,14 @@ public class PolarDataMiner {
|
|||||||
synchronized (fixQueue) {
|
synchronized (fixQueue) {
|
||||||
while (this.getQueue().size() < (EXECUTOR_QUEUE_SIZE / 10) && !fixQueue.isEmpty()) {
|
while (this.getQueue().size() < (EXECUTOR_QUEUE_SIZE / 10) && !fixQueue.isEmpty()) {
|
||||||
GPSFixMovingWithOriginInfo fix = fixQueue.poll();
|
GPSFixMovingWithOriginInfo fix = fixQueue.poll();
|
||||||
enrichingProcessor.processElement(fix);
|
preFilteringProcessor.processElement(fix);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
private AbstractEnrichingProcessor<GPSFixMovingWithOriginInfo, GPSFixMovingWithPolarContext> enrichingProcessor;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This processor keeps track of the moving average of the speed values and the average angle for each course (legtype tack combination)
|
* This processor keeps track of the moving average of the speed values and the average angle for each course (legtype tack combination)
|
||||||
@@ -100,6 +100,7 @@ public class PolarDataMiner {
|
|||||||
private CubicRegressionPerCourseProcessor cubicRegressionPerCourseProcessor;
|
private CubicRegressionPerCourseProcessor cubicRegressionPerCourseProcessor;
|
||||||
|
|
||||||
private SpeedRegressionPerAngleClusterProcessor speedRegressionPerAngleClusterProcessor;
|
private SpeedRegressionPerAngleClusterProcessor speedRegressionPerAngleClusterProcessor;
|
||||||
|
private ParallelFilteringProcessor<GPSFixMovingWithOriginInfo> preFilteringProcessor;
|
||||||
|
|
||||||
public PolarDataMiner() {
|
public PolarDataMiner() {
|
||||||
this(PolarSheetGenerationSettingsImpl.createBackendPolarSettings());
|
this(PolarSheetGenerationSettingsImpl.createBackendPolarSettings());
|
||||||
@@ -170,15 +171,42 @@ public class PolarDataMiner {
|
|||||||
.asList(filteringProcessor);
|
.asList(filteringProcessor);
|
||||||
|
|
||||||
|
|
||||||
enrichingProcessor = new AbstractEnrichingProcessor<GPSFixMovingWithOriginInfo, GPSFixMovingWithPolarContext>(
|
AbstractEnrichingProcessor<GPSFixMovingWithOriginInfo, GPSFixMovingWithPolarContext> enrichingProcessor = new AbstractEnrichingProcessor<GPSFixMovingWithOriginInfo, GPSFixMovingWithPolarContext>(
|
||||||
GPSFixMovingWithOriginInfo.class, GPSFixMovingWithPolarContext.class, executor, enrichingResultReceivers) {
|
GPSFixMovingWithOriginInfo.class, GPSFixMovingWithPolarContext.class, executor,
|
||||||
|
enrichingResultReceivers) {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected GPSFixMovingWithPolarContext enrich(GPSFixMovingWithOriginInfo element) {
|
protected GPSFixMovingWithPolarContext enrich(GPSFixMovingWithOriginInfo element) {
|
||||||
return new GPSFixMovingWithPolarContext(element.getFix(), element.getTrackedRace(), element.getCompetitor(),
|
GPSFixMovingWithPolarContext result = null;
|
||||||
speedClusterGroup, angleClusterGroup);
|
result = new GPSFixMovingWithPolarContext(element.getFix(), element.getTrackedRace(),
|
||||||
|
element.getCompetitor(), speedClusterGroup, angleClusterGroup);
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Collection<Processor<GPSFixMovingWithOriginInfo, ?>> preFilterResultReceivers = Arrays
|
||||||
|
.asList(enrichingProcessor);
|
||||||
|
|
||||||
|
preFilteringProcessor = new ParallelFilteringProcessor<GPSFixMovingWithOriginInfo>(
|
||||||
|
GPSFixMovingWithOriginInfo.class, executor, preFilterResultReceivers, new FilterCriterion<GPSFixMovingWithOriginInfo>() {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean matches(GPSFixMovingWithOriginInfo element) {
|
||||||
|
boolean result = false;
|
||||||
|
if (PolarFixFilterCriteria.isInLeadingCompetitors(element.getTrackedRace(), element.getCompetitor(),
|
||||||
|
backendPolarSheetGenerationSettings.getPctOfLeadingCompetitorsToInclude())) {
|
||||||
|
result = true;
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Class<GPSFixMovingWithOriginInfo> getElementType() {
|
||||||
|
return GPSFixMovingWithOriginInfo.class;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -188,48 +216,34 @@ public class PolarDataMiner {
|
|||||||
|
|
||||||
public void addFix(GPSFixMoving fix, Competitor competitor, TrackedRace trackedRace) {
|
public void addFix(GPSFixMoving fix, Competitor competitor, TrackedRace trackedRace) {
|
||||||
GPSFixMovingWithOriginInfo fixWithOriginInfo = new GPSFixMovingWithOriginInfo(fix, trackedRace, competitor);
|
GPSFixMovingWithOriginInfo fixWithOriginInfo = new GPSFixMovingWithOriginInfo(fix, trackedRace, competitor);
|
||||||
if (isReplayAndFinishedOrLive(trackedRace)) {
|
if (trackedRace.getStatus().getStatus() == TrackedRaceStatusEnum.LOADING) {
|
||||||
processFix(trackedRace, fixWithOriginInfo);
|
|
||||||
} else {
|
|
||||||
/*
|
/*
|
||||||
* logger.info("Received fix for replay race which has not finished loading. Queuing. " +
|
* logger.info("Received fix for replay race which has not finished loading. Queuing. " +
|
||||||
* (trackedRace.getRace() != null ? trackedRace.getRace().getName() : trackedRace.getRaceIdentifier()
|
* (trackedRace.getRace() != null ? trackedRace.getRace().getName() : trackedRace.getRaceIdentifier()
|
||||||
* .getRaceName()));
|
* .getRaceName()));
|
||||||
*/
|
*/
|
||||||
synchronized (fixesForReplayRacesWhichAreStillLoading) {
|
synchronized (fixesForRacesWhichAreStillLoading) {
|
||||||
Set<GPSFixMovingWithOriginInfo> fixes = fixesForReplayRacesWhichAreStillLoading.get(trackedRace);
|
Set<GPSFixMovingWithOriginInfo> fixes = fixesForRacesWhichAreStillLoading.get(trackedRace);
|
||||||
if (fixes == null) {
|
if (fixes == null) {
|
||||||
fixes = new HashSet<>();
|
fixes = new HashSet<>();
|
||||||
fixesForReplayRacesWhichAreStillLoading.put(trackedRace, fixes);
|
fixesForRacesWhichAreStillLoading.put(trackedRace, fixes);
|
||||||
}
|
}
|
||||||
fixes.add(fixWithOriginInfo);
|
fixes.add(fixWithOriginInfo);
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
processFix(trackedRace, fixWithOriginInfo);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void processFix(TrackedRace trackedRace, GPSFixMovingWithOriginInfo fixWithOriginInfo) {
|
private void processFix(TrackedRace trackedRace, GPSFixMovingWithOriginInfo fixWithOriginInfo) {
|
||||||
// Pre Filter for performance. We don't need to run wind estimation for this filter
|
|
||||||
if (PolarFixFilterCriteria.isInLeadingCompetitors(trackedRace, fixWithOriginInfo.getCompetitor(),
|
|
||||||
backendPolarSheetGenerationSettings.getPctOfLeadingCompetitorsToInclude())) {
|
|
||||||
synchronized (fixQueue) {
|
synchronized (fixQueue) {
|
||||||
if (executor.getQueue().size() >= EXECUTOR_QUEUE_SIZE / 10) {
|
if (executor.getQueue().size() >= EXECUTOR_QUEUE_SIZE / 10) {
|
||||||
fixQueue.add(fixWithOriginInfo);
|
fixQueue.add(fixWithOriginInfo);
|
||||||
} else {
|
} else {
|
||||||
enrichingProcessor.processElement(fixWithOriginInfo);
|
preFilteringProcessor.processElement(fixWithOriginInfo);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
private boolean isReplayAndFinishedOrLive(TrackedRace trackedRace) {
|
|
||||||
boolean isLive = trackedRace.isLive(new MillisecondsTimePoint(System.currentTimeMillis()));
|
|
||||||
boolean loadingFinished = false;
|
|
||||||
if (trackedRace.getStatus().getStatus() == TrackedRaceStatusEnum.FINISHED) {
|
|
||||||
loadingFinished = true;
|
|
||||||
}
|
|
||||||
boolean replayRaceAndFinished = !isLive && loadingFinished;
|
|
||||||
return replayRaceAndFinished || isLive;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isCurrentlyActiveAndOrHasQueue() {
|
public boolean isCurrentlyActiveAndOrHasQueue() {
|
||||||
boolean isActive = executor.getActiveCount() > 0;
|
boolean isActive = executor.getActiveCount() > 0;
|
||||||
@@ -399,11 +413,11 @@ public class PolarDataMiner {
|
|||||||
|
|
||||||
public void raceFinishedTracking(TrackedRace race) {
|
public void raceFinishedTracking(TrackedRace race) {
|
||||||
Set<GPSFixMovingWithOriginInfo> fixes = null;
|
Set<GPSFixMovingWithOriginInfo> fixes = null;
|
||||||
synchronized (fixesForReplayRacesWhichAreStillLoading) {
|
synchronized (fixesForRacesWhichAreStillLoading) {
|
||||||
fixes = fixesForReplayRacesWhichAreStillLoading.remove(race);
|
fixes = fixesForRacesWhichAreStillLoading.remove(race);
|
||||||
}
|
}
|
||||||
if (fixes != null) {
|
if (fixes != null) {
|
||||||
logger.info("All queued fixes for newly completed race will process now. " + (race.getRace() != null ? race
|
logger.info("All queued fixes for newly loaded race will process now. " + (race.getRace() != null ? race
|
||||||
.getRace().getName() : race.getRaceIdentifier().getRaceName()));
|
.getRace().getName() : race.getRaceIdentifier().getRaceName()));
|
||||||
for (GPSFixMovingWithOriginInfo fix : fixes) {
|
for (GPSFixMovingWithOriginInfo fix : fixes) {
|
||||||
processFix(race, fix);
|
processFix(race, fix);
|
||||||
|
|||||||
+10
-4
@@ -1540,9 +1540,10 @@ public class RacingEventServiceImpl implements RacingEventService, ClearStateTes
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void statusChanged(TrackedRaceStatus newStatus) {
|
public void statusChanged(TrackedRaceStatus newStatus, TrackedRaceStatus oldStatus) {
|
||||||
if (newStatus.getStatus() == TrackedRaceStatusEnum.FINISHED) {
|
if (oldStatus.getStatus() == TrackedRaceStatusEnum.LOADING
|
||||||
polarDataService.raceFinishedTracking(race);
|
&& newStatus.getStatus() != TrackedRaceStatusEnum.LOADING) {
|
||||||
|
polarDataService.raceFinishedLoading(race);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1617,7 +1618,7 @@ public class RacingEventServiceImpl implements RacingEventService, ClearStateTes
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void statusChanged(TrackedRaceStatus newStatus) {
|
public void statusChanged(TrackedRaceStatus newStatus, TrackedRaceStatus oldStatus) {
|
||||||
replicate(new UpdateTrackedRaceStatus(getRaceIdentifier(), newStatus));
|
replicate(new UpdateTrackedRaceStatus(getRaceIdentifier(), newStatus));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2288,6 +2289,11 @@ public class RacingEventServiceImpl implements RacingEventService, ClearStateTes
|
|||||||
return getBaseDomainFactory().createObjectInputStreamResolvingAgainstThisFactory(is);
|
return getBaseDomainFactory().createObjectInputStreamResolvingAgainstThisFactory(is);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ClassLoader getDeserializationClassLoader() {
|
||||||
|
return getCombinedMasterDataClassLoader();
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Serializable getId() {
|
public Serializable getId() {
|
||||||
return getClass().getName();
|
return getClass().getName();
|
||||||
|
|||||||
@@ -338,7 +338,7 @@ public class Util {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static String join(String separator, Iterable<? extends Named> nameds) {
|
public static String join(String separator, Iterable<? extends Named> nameds) {
|
||||||
return join(separator, toArray(nameds, new Named[size(nameds)]));
|
return join(separator, toArray(nameds, new Named[0]));
|
||||||
}
|
}
|
||||||
|
|
||||||
public static String join(String separator, Named... nameds) {
|
public static String join(String separator, Named... nameds) {
|
||||||
|
|||||||
-8
@@ -37,14 +37,6 @@ public class AbstractMailServiceReplicationTest extends AbstractServerWithSingle
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static class MailServerReplicationTestSetUp extends AbstractServerReplicationTestSetUp<MailService, MailServiceImpl> {
|
public static class MailServerReplicationTestSetUp extends AbstractServerReplicationTestSetUp<MailService, MailServiceImpl> {
|
||||||
public MailServerReplicationTestSetUp() {
|
|
||||||
super();
|
|
||||||
}
|
|
||||||
|
|
||||||
public MailServerReplicationTestSetUp(int servletPort) {
|
|
||||||
super(servletPort);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected MailServiceImpl createNewMaster() throws MailException {
|
protected MailServiceImpl createNewMaster() throws MailException {
|
||||||
return createMailCountingService(true);
|
return createMailCountingService(true);
|
||||||
|
|||||||
+13
-11
@@ -45,7 +45,7 @@ public abstract class AbstractServerReplicationTestSetUp<ReplicableInterface ext
|
|||||||
|
|
||||||
protected static final int DEFAULT_SERVLET_PORT = 9990;
|
protected static final int DEFAULT_SERVLET_PORT = 9990;
|
||||||
|
|
||||||
private final int servletPort;
|
private int servletPort;
|
||||||
protected ReplicableImpl replica;
|
protected ReplicableImpl replica;
|
||||||
protected ReplicableImpl master;
|
protected ReplicableImpl master;
|
||||||
protected ReplicationServiceTestImpl<ReplicableInterface> replicaReplicator;
|
protected ReplicationServiceTestImpl<ReplicableInterface> replicaReplicator;
|
||||||
@@ -54,7 +54,6 @@ public abstract class AbstractServerReplicationTestSetUp<ReplicableInterface ext
|
|||||||
protected ReplicationMasterDescriptor masterDescriptor;
|
protected ReplicationMasterDescriptor masterDescriptor;
|
||||||
|
|
||||||
protected AbstractServerReplicationTestSetUp() {
|
protected AbstractServerReplicationTestSetUp() {
|
||||||
servletPort = DEFAULT_SERVLET_PORT;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected AbstractServerReplicationTestSetUp(int servletPort) {
|
protected AbstractServerReplicationTestSetUp(int servletPort) {
|
||||||
@@ -127,9 +126,10 @@ public abstract class AbstractServerReplicationTestSetUp<ReplicableInterface ext
|
|||||||
masterReplicator.registerReplica(replicaDescriptor);
|
masterReplicator.registerReplica(replicaDescriptor);
|
||||||
// connect to exchange host and local server running as master
|
// connect to exchange host and local server running as master
|
||||||
// master server and exchange host can be two different hosts
|
// master server and exchange host can be two different hosts
|
||||||
masterDescriptor = new ReplicationMasterDescriptorImpl(exchangeHost, exchangeName, 0, UUID.randomUUID().toString(), "localhost", servletPort);
|
|
||||||
ReplicationServiceTestImpl<ReplicableInterface> replicaReplicator = new ReplicationServiceTestImpl<ReplicableInterface>(exchangeName, exchangeHost, rim, replicaDescriptor,
|
ReplicationServiceTestImpl<ReplicableInterface> replicaReplicator = new ReplicationServiceTestImpl<ReplicableInterface>(exchangeName, exchangeHost, rim, replicaDescriptor,
|
||||||
this.replica, this.master, masterReplicator, masterDescriptor, servletPort);
|
this.replica, this.master, masterReplicator, masterDescriptor);
|
||||||
|
masterDescriptor = replicaReplicator.getMasterDescriptor();
|
||||||
|
servletPort = masterDescriptor.getServletPort();
|
||||||
Pair<ReplicationServiceTestImpl<ReplicableInterface>, ReplicationMasterDescriptor> result = new Pair<>(replicaReplicator, masterDescriptor);
|
Pair<ReplicationServiceTestImpl<ReplicableInterface>, ReplicationMasterDescriptor> result = new Pair<>(replicaReplicator, masterDescriptor);
|
||||||
logger.info("starting initial load transmission servlet for "+getClass().getName());
|
logger.info("starting initial load transmission servlet for "+getClass().getName());
|
||||||
initialLoadTestServerThread = replicaReplicator.startInitialLoadTransmissionServlet();
|
initialLoadTestServerThread = replicaReplicator.startInitialLoadTransmissionServlet();
|
||||||
@@ -197,28 +197,30 @@ public abstract class AbstractServerReplicationTestSetUp<ReplicableInterface ext
|
|||||||
private final ReplicaDescriptor replicaDescriptor;
|
private final ReplicaDescriptor replicaDescriptor;
|
||||||
private final ReplicationService masterReplicationService;
|
private final ReplicationService masterReplicationService;
|
||||||
private final ReplicationMasterDescriptor masterDescriptor;
|
private final ReplicationMasterDescriptor masterDescriptor;
|
||||||
private final int servletPort;
|
private final ServerSocket ss;
|
||||||
|
|
||||||
public ReplicationServiceTestImpl(String exchangeName, String exchangeHost, ReplicationInstancesManager replicationInstancesManager,
|
public ReplicationServiceTestImpl(String exchangeName, String exchangeHost, ReplicationInstancesManager replicationInstancesManager,
|
||||||
ReplicaDescriptor replicaDescriptor, ReplicableInterface replica,
|
ReplicaDescriptor replicaDescriptor, ReplicableInterface replica,
|
||||||
ReplicableInterface master, ReplicationService masterReplicationService, ReplicationMasterDescriptor masterDescriptor,
|
ReplicableInterface master, ReplicationService masterReplicationService, ReplicationMasterDescriptor masterDescriptor)
|
||||||
int servletPort)
|
|
||||||
throws IOException {
|
throws IOException {
|
||||||
super(exchangeName, exchangeHost, 0, replicationInstancesManager, new SingletonReplicablesProvider(replica));
|
super(exchangeName, exchangeHost, 0, replicationInstancesManager, new SingletonReplicablesProvider(replica));
|
||||||
this.replicaDescriptor = replicaDescriptor;
|
this.replicaDescriptor = replicaDescriptor;
|
||||||
this.master = master;
|
this.master = master;
|
||||||
|
ss = new ServerSocket(0); // bind to any free port
|
||||||
this.masterReplicationService = masterReplicationService;
|
this.masterReplicationService = masterReplicationService;
|
||||||
this.masterDescriptor = masterDescriptor;
|
this.masterDescriptor = new ReplicationMasterDescriptorImpl(exchangeHost, exchangeName, /* messagingPort */ 0,
|
||||||
this.servletPort = servletPort;
|
UUID.randomUUID().toString(), "localhost", ss.getLocalPort());
|
||||||
|
}
|
||||||
|
|
||||||
|
ReplicationMasterDescriptor getMasterDescriptor() {
|
||||||
|
return masterDescriptor;
|
||||||
}
|
}
|
||||||
|
|
||||||
private Thread startInitialLoadTransmissionServlet() throws InterruptedException {
|
private Thread startInitialLoadTransmissionServlet() throws InterruptedException {
|
||||||
final boolean[] listening = new boolean[] { false };
|
final boolean[] listening = new boolean[] { false };
|
||||||
Thread initialLoadTestServerThread = new Thread("Replication initial load test server") {
|
Thread initialLoadTestServerThread = new Thread("Replication initial load test server") {
|
||||||
public void run() {
|
public void run() {
|
||||||
ServerSocket ss = null;
|
|
||||||
try {
|
try {
|
||||||
ss = new ServerSocket(servletPort);
|
|
||||||
synchronized (listening) {
|
synchronized (listening) {
|
||||||
listening[0] = true;
|
listening[0] = true;
|
||||||
listening.notifyAll();
|
listening.notifyAll();
|
||||||
|
|||||||
+14
-1
@@ -70,7 +70,7 @@ public interface ReplicableWithObjectInputStream<S, O extends OperationWithResul
|
|||||||
try {
|
try {
|
||||||
final ObjectInputStream objectInputStream = createObjectInputStreamResolvingAgainstCache(is);
|
final ObjectInputStream objectInputStream = createObjectInputStreamResolvingAgainstCache(is);
|
||||||
ClassLoader oldContextClassloader = Thread.currentThread().getContextClassLoader();
|
ClassLoader oldContextClassloader = Thread.currentThread().getContextClassLoader();
|
||||||
Thread.currentThread().setContextClassLoader(getClass().getClassLoader());
|
Thread.currentThread().setContextClassLoader(getDeserializationClassLoader());
|
||||||
try {
|
try {
|
||||||
initiallyFillFromInternal(objectInputStream);
|
initiallyFillFromInternal(objectInputStream);
|
||||||
} finally {
|
} finally {
|
||||||
@@ -81,6 +81,13 @@ public interface ReplicableWithObjectInputStream<S, O extends OperationWithResul
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The class loader to use for de-serializing objects. By default, this object's class's class loader is used.
|
||||||
|
*/
|
||||||
|
default ClassLoader getDeserializationClassLoader() {
|
||||||
|
return getClass().getClassLoader();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Wraps <code>os</code> by an {@link ObjectOutputStream} and invokes
|
* Wraps <code>os</code> by an {@link ObjectOutputStream} and invokes
|
||||||
* {@link #serializeForInitialReplicationInternal(ObjectOutputStream)}.
|
* {@link #serializeForInitialReplicationInternal(ObjectOutputStream)}.
|
||||||
@@ -92,7 +99,13 @@ public interface ReplicableWithObjectInputStream<S, O extends OperationWithResul
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
default O readOperation(InputStream inputStream) throws IOException, ClassNotFoundException {
|
default O readOperation(InputStream inputStream) throws IOException, ClassNotFoundException {
|
||||||
|
ClassLoader oldContextClassloader = Thread.currentThread().getContextClassLoader();
|
||||||
|
Thread.currentThread().setContextClassLoader(getDeserializationClassLoader());
|
||||||
|
try {
|
||||||
return readOperationInternal(createObjectInputStreamResolvingAgainstCache(inputStream));
|
return readOperationInternal(createObjectInputStreamResolvingAgainstCache(inputStream));
|
||||||
|
} finally {
|
||||||
|
Thread.currentThread().setContextClassLoader(oldContextClassloader);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
-6
@@ -67,12 +67,6 @@ public class SecurityReplicationLeadingToEmailReplicationTest extends AbstractSe
|
|||||||
}
|
}
|
||||||
|
|
||||||
private class MailServerReplicationTestSetUp extends AbstractMailServiceReplicationTest.MailServerReplicationTestSetUp {
|
private class MailServerReplicationTestSetUp extends AbstractMailServiceReplicationTest.MailServerReplicationTestSetUp {
|
||||||
private static final int SERVLET_PORT = 9991;
|
|
||||||
|
|
||||||
public MailServerReplicationTestSetUp() {
|
|
||||||
super(SERVLET_PORT);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected MailServiceImpl createNewMaster() throws MailException {
|
protected MailServiceImpl createNewMaster() throws MailException {
|
||||||
return masterMailService;
|
return masterMailService;
|
||||||
|
|||||||
Reference in new issue
Block a user