mirror of
https://github.com/eclipse-sailing-analytics/sailing-analytics.git
synced 2026-10-25 05:23:51 +00:00
Merge branch 'master' into ubilabs--tracking_app--develop
This commit is contained in:
commit
742c71c637
41 files changed
+552
-249
No files matched your search
@@ -660,30 +660,31 @@ if [[ "$@" == "build" ]] || [[ "$@" == "all" ]]; then
|
|||||||
if [[ ${PIPESTATUS[0]} != 0 ]]; then
|
if [[ ${PIPESTATUS[0]} != 0 ]]; then
|
||||||
exit 103
|
exit 103
|
||||||
fi
|
fi
|
||||||
adb emu kill
|
# TODO find a way that the emulator test is stable in hudson
|
||||||
echo "Downloading image (sys-img-${ANDROID_ABI}-android-${TEST_API})..." | tee -a $START_DIR/build.log
|
# adb emu kill
|
||||||
echo yes | "$ANDROID" update sdk $ANDROID_OPTIONS --filter sys-img-${ANDROID_ABI}-android-${TEST_API} --no-ui --force --all > /dev/null
|
# echo "Downloading image (sys-img-${ANDROID_ABI}-android-${TEST_API})..." | tee -a $START_DIR/build.log
|
||||||
echo no | "$ANDROID" create avd --name ${AVD_NAME} --target android-${TEST_API} --abi ${ANDROID_ABI} --force -p ${START_DIR}/emulator
|
# echo yes | "$ANDROID" update sdk $ANDROID_OPTIONS --filter sys-img-${ANDROID_ABI}-android-${TEST_API} --no-ui --force --all > /dev/null
|
||||||
echo "Starting emulator..." | tee -a $START_DIR/build.log
|
# echo no | "$ANDROID" create avd --name ${AVD_NAME} --target android-${TEST_API} --abi ${ANDROID_ABI} --force -p ${START_DIR}/emulator
|
||||||
emulator -avd ${AVD_NAME} -no-skin -no-audio -no-window &
|
# echo "Starting emulator..." | tee -a $START_DIR/build.log
|
||||||
echo "Waiting for startup..." | tee -a $START_DIR/build.log
|
# emulator -avd ${AVD_NAME} -no-skin -no-audio -no-window &
|
||||||
adb wait-for-device
|
# echo "Waiting for startup..." | tee -a $START_DIR/build.log
|
||||||
sleep 60
|
# adb wait-for-device
|
||||||
$PROJECT_HOME/configuration/androidWaitForEmulator.sh
|
# sleep 60
|
||||||
if [[ $? != 0 ]]; then
|
# $PROJECT_HOME/configuration/androidWaitForEmulator.sh
|
||||||
adb emu kill
|
# if [[ $? != 0 ]]; then
|
||||||
"$ANDROID" delete avd --name ${AVD_NAME}
|
# adb emu kill
|
||||||
exit 102
|
# "$ANDROID" delete avd --name ${AVD_NAME}
|
||||||
fi
|
# exit 102
|
||||||
adb shell input keyevent 82 &
|
# fi
|
||||||
./gradlew deviceCheck connectedCheck | tee -a $START_DIR/build.log
|
# adb shell input keyevent 82 &
|
||||||
if [[ ${PIPESTATUS[0]} != 0 ]]; then
|
# ./gradlew deviceCheck connectedCheck | tee -a $START_DIR/build.log
|
||||||
adb emu kill
|
# if [[ ${PIPESTATUS[0]} != 0 ]]; then
|
||||||
"$ANDROID" delete avd --name ${AVD_NAME}
|
# adb emu kill
|
||||||
exit 101
|
# "$ANDROID" delete avd --name ${AVD_NAME}
|
||||||
fi
|
# exit 101
|
||||||
adb emu kill
|
# fi
|
||||||
"$ANDROID" delete avd --name ${AVD_NAME}
|
# adb emu kill
|
||||||
|
# "$ANDROID" delete avd --name ${AVD_NAME}
|
||||||
fi
|
fi
|
||||||
else
|
else
|
||||||
echo "INFO: Deactivating mobile modules"
|
echo "INFO: Deactivating mobile modules"
|
||||||
|
|||||||
+3
-13
@@ -8,7 +8,6 @@ import com.sap.sailing.domain.common.SpeedWithBearing;
|
|||||||
import com.sap.sailing.domain.common.impl.AbstractSpeedWithAbstractBearingImpl;
|
import com.sap.sailing.domain.common.impl.AbstractSpeedWithAbstractBearingImpl;
|
||||||
import com.sap.sailing.domain.common.tracking.GPSFix;
|
import com.sap.sailing.domain.common.tracking.GPSFix;
|
||||||
import com.sap.sse.common.TimePoint;
|
import com.sap.sse.common.TimePoint;
|
||||||
import com.sap.sse.common.impl.AbstractTimePoint;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A compact representation of a GPS fix which collects all primitive-typed attributes in one object to avoid
|
* A compact representation of a GPS fix which collects all primitive-typed attributes in one object to avoid
|
||||||
@@ -42,7 +41,7 @@ public class CompactGPSFixImpl extends AbstractGPSFixImpl {
|
|||||||
|
|
||||||
private final double latDeg;
|
private final double latDeg;
|
||||||
private final double lngDeg;
|
private final double lngDeg;
|
||||||
private final long timePointAsMillis;
|
private final TimePoint timePoint;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tells if in the containing {@link DynamicGPSFixTrackImpl} this fix is considered valid. This cache
|
* Tells if in the containing {@link DynamicGPSFixTrackImpl} this fix is considered valid. This cache
|
||||||
@@ -78,15 +77,6 @@ public class CompactGPSFixImpl extends AbstractGPSFixImpl {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private class CompactTimePoint extends AbstractTimePoint implements TimePoint {
|
|
||||||
private static final long serialVersionUID = -2470922642359937437L;
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public long asMillis() {
|
|
||||||
return timePointAsMillis;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private class CompactEstimatedSpeedBearing extends AbstractBearing {
|
private class CompactEstimatedSpeedBearing extends AbstractBearing {
|
||||||
private static final long serialVersionUID = 8549231429037883121L;
|
private static final long serialVersionUID = 8549231429037883121L;
|
||||||
|
|
||||||
@@ -113,7 +103,7 @@ public class CompactGPSFixImpl extends AbstractGPSFixImpl {
|
|||||||
public CompactGPSFixImpl(Position position, TimePoint timePoint) {
|
public CompactGPSFixImpl(Position position, TimePoint timePoint) {
|
||||||
latDeg = position.getLatDeg();
|
latDeg = position.getLatDeg();
|
||||||
lngDeg = position.getLngDeg();
|
lngDeg = position.getLngDeg();
|
||||||
timePointAsMillis = timePoint==null?-1:timePoint.asMillis();
|
this.timePoint = timePoint;
|
||||||
}
|
}
|
||||||
|
|
||||||
public CompactGPSFixImpl(GPSFix gpsFix) {
|
public CompactGPSFixImpl(GPSFix gpsFix) {
|
||||||
@@ -132,7 +122,7 @@ public class CompactGPSFixImpl extends AbstractGPSFixImpl {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public TimePoint getTimePoint() {
|
public TimePoint getTimePoint() {
|
||||||
return new CompactTimePoint();
|
return timePoint;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
+38
@@ -0,0 +1,38 @@
|
|||||||
|
package com.sap.sailing.domain.abstractlog.race.analyzing.impl;
|
||||||
|
|
||||||
|
import com.sap.sailing.domain.abstractlog.race.RaceLog;
|
||||||
|
import com.sap.sse.common.TimePoint;
|
||||||
|
|
||||||
|
public class IsIndividualRecallDisplayedAnalyzer extends RaceLogAnalyzer<Boolean> {
|
||||||
|
|
||||||
|
private final IndividualRecallFinder displayedFinder;
|
||||||
|
private final IndividualRecallFinder removedFinder;
|
||||||
|
|
||||||
|
public IsIndividualRecallDisplayedAnalyzer(RaceLog raceLog) {
|
||||||
|
this(raceLog, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public IsIndividualRecallDisplayedAnalyzer(RaceLog raceLog, TimePoint at) {
|
||||||
|
this(raceLog, new IndividualRecallDisplayedFinder(raceLog, at), new IndividualRecallRemovedFinder(raceLog, at), at);
|
||||||
|
}
|
||||||
|
|
||||||
|
public IsIndividualRecallDisplayedAnalyzer(RaceLog raceLog, IndividualRecallDisplayedFinder displayedFinder,
|
||||||
|
IndividualRecallRemovedFinder removedFinder, TimePoint at) {
|
||||||
|
super(raceLog);
|
||||||
|
this.displayedFinder = displayedFinder;
|
||||||
|
this.removedFinder = removedFinder;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Boolean performAnalysis() {
|
||||||
|
TimePoint displayedAt = displayedFinder.analyze();
|
||||||
|
TimePoint removedAt = removedFinder.analyze();
|
||||||
|
if (displayedAt != null) {
|
||||||
|
if (removedAt == null || displayedAt.after(removedAt)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
+5
@@ -30,4 +30,9 @@ public class RaceLogProtestStartTimeEventImpl extends RaceLogEventImpl implement
|
|||||||
return protestStartTime;
|
return protestStartTime;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getShortInfo() {
|
||||||
|
return "protestStartTime=" + protestStartTime;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
+1
-1
@@ -30,7 +30,7 @@ public class SimpleRaceLogIdentifierImpl implements SimpleRaceLogIdentifier {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return "SimpleRaceLogIdentifier [regattaLikeParentName=" + regattaLikeParentName + ", raceCloumnName=" + raceColumnName
|
return "SimpleRaceLogIdentifier [regattaLikeParentName=" + regattaLikeParentName + ", raceColumnName=" + raceColumnName
|
||||||
+ ", fleetName=" + fleetName + "]";
|
+ ", fleetName=" + fleetName + "]";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+33
-41
@@ -15,6 +15,7 @@ import com.sap.sailing.domain.abstractlog.race.analyzing.impl.IndividualRecallDi
|
|||||||
import com.sap.sailing.domain.abstractlog.race.analyzing.impl.IndividualRecallRemovedFinder;
|
import com.sap.sailing.domain.abstractlog.race.analyzing.impl.IndividualRecallRemovedFinder;
|
||||||
import com.sap.sailing.domain.abstractlog.race.analyzing.impl.IsFinishedAnalyzer;
|
import com.sap.sailing.domain.abstractlog.race.analyzing.impl.IsFinishedAnalyzer;
|
||||||
import com.sap.sailing.domain.abstractlog.race.analyzing.impl.IsInFinishingPhaseAnalyzer;
|
import com.sap.sailing.domain.abstractlog.race.analyzing.impl.IsInFinishingPhaseAnalyzer;
|
||||||
|
import com.sap.sailing.domain.abstractlog.race.analyzing.impl.IsIndividualRecallDisplayedAnalyzer;
|
||||||
import com.sap.sailing.domain.abstractlog.race.analyzing.impl.RaceLogResolver;
|
import com.sap.sailing.domain.abstractlog.race.analyzing.impl.RaceLogResolver;
|
||||||
import com.sap.sailing.domain.abstractlog.race.analyzing.impl.StartTimeFinder;
|
import com.sap.sailing.domain.abstractlog.race.analyzing.impl.StartTimeFinder;
|
||||||
import com.sap.sailing.domain.abstractlog.race.impl.RaceLogChangedVisitor;
|
import com.sap.sailing.domain.abstractlog.race.impl.RaceLogChangedVisitor;
|
||||||
@@ -28,9 +29,7 @@ import com.sap.sailing.domain.abstractlog.race.state.racingprocedure.RacingProce
|
|||||||
import com.sap.sailing.domain.abstractlog.race.state.racingprocedure.RacingProcedureChangedListener;
|
import com.sap.sailing.domain.abstractlog.race.state.racingprocedure.RacingProcedureChangedListener;
|
||||||
import com.sap.sailing.domain.base.configuration.RacingProcedureConfiguration;
|
import com.sap.sailing.domain.base.configuration.RacingProcedureConfiguration;
|
||||||
import com.sap.sailing.domain.common.racelog.Flags;
|
import com.sap.sailing.domain.common.racelog.Flags;
|
||||||
import com.sap.sse.common.Duration;
|
|
||||||
import com.sap.sse.common.TimePoint;
|
import com.sap.sse.common.TimePoint;
|
||||||
import com.sap.sse.common.impl.MillisecondsTimePoint;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Base class for all your {@link RacingProcedure}s.
|
* Base class for all your {@link RacingProcedure}s.
|
||||||
@@ -42,10 +41,7 @@ import com.sap.sse.common.impl.MillisecondsTimePoint;
|
|||||||
public abstract class BaseRacingProcedure extends BaseRaceStateChangedListener implements RacingProcedure,
|
public abstract class BaseRacingProcedure extends BaseRaceStateChangedListener implements RacingProcedure,
|
||||||
RaceLogChangedListener {
|
RaceLogChangedListener {
|
||||||
|
|
||||||
/**
|
private final static long individualRecallRemovalTimeout = 4 * 60 * 1000; // minutes * seconds * milliseconds
|
||||||
* The time since race start after which the X-ray flag has to go down
|
|
||||||
*/
|
|
||||||
private final static Duration individualRecallRemovalTimeout = Duration.ONE_MINUTE.times(4);
|
|
||||||
|
|
||||||
private RaceStateEventScheduler scheduler;
|
private RaceStateEventScheduler scheduler;
|
||||||
|
|
||||||
@@ -55,35 +51,41 @@ public abstract class BaseRacingProcedure extends BaseRaceStateChangedListener i
|
|||||||
private final RacingProcedureConfiguration configuration;
|
private final RacingProcedureConfiguration configuration;
|
||||||
|
|
||||||
private final RacingProcedureChangedListeners<? extends RacingProcedureChangedListener> changedListeners;
|
private final RacingProcedureChangedListeners<? extends RacingProcedureChangedListener> changedListeners;
|
||||||
|
private final IsIndividualRecallDisplayedAnalyzer isRecallDisplayedAnalyzer;
|
||||||
private final IndividualRecallDisplayedFinder recallDisplayedFinder;
|
private final IndividualRecallDisplayedFinder recallDisplayedFinder;
|
||||||
private final IndividualRecallRemovedFinder recallRemovedFinder;
|
private final IndividualRecallRemovedFinder recallRemovedFinder;
|
||||||
private final FinishingTimeFinder finishingTimeFinder;
|
private final FinishingTimeFinder finishingTimeFinder;
|
||||||
private final FinishedTimeFinder finishedTimeFinder;
|
private final FinishedTimeFinder finishedTimeFinder;
|
||||||
private final RaceLogEventVisitor raceLogListener;
|
private final RaceLogEventVisitor raceLogListener;
|
||||||
private final StartTimeFinder startTimeFinder;
|
|
||||||
|
|
||||||
private boolean cachedIsIndividualRecallDisplayed;
|
private boolean cachedIsIndividualRecallDisplayed;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* When calling me, call {@link BaseRacingProcedure#update()} afterwards!
|
* When calling me, call {@link BaseRacingProcedure#update()} afterwards!
|
||||||
* @param raceLogResolver TODO
|
*
|
||||||
|
* @param raceLogResolver
|
||||||
|
* is required for a {@link StartTimeFinder} in order to make individual recall timeouts depend on start
|
||||||
|
* time rather than the time the individual recall was issued
|
||||||
*/
|
*/
|
||||||
public BaseRacingProcedure(RaceLog raceLog, AbstractLogEventAuthor author, RaceLogEventFactory factory,
|
public BaseRacingProcedure(RaceLog raceLog, AbstractLogEventAuthor author, RaceLogEventFactory factory,
|
||||||
RacingProcedureConfiguration configuration, RaceLogResolver raceLogResolver) {
|
RacingProcedureConfiguration configuration, RaceLogResolver raceLogResolver) {
|
||||||
if (configuration == null) {
|
if (configuration == null) {
|
||||||
throw new IllegalArgumentException("configuration must not be null");
|
throw new IllegalArgumentException("configuration must not be null");
|
||||||
}
|
}
|
||||||
|
|
||||||
this.raceLog = raceLog;
|
this.raceLog = raceLog;
|
||||||
this.author = author;
|
this.author = author;
|
||||||
this.factory = factory;
|
this.factory = factory;
|
||||||
this.configuration = configuration;
|
this.configuration = configuration;
|
||||||
|
|
||||||
this.changedListeners = createChangedListenerContainer();
|
this.changedListeners = createChangedListenerContainer();
|
||||||
|
this.isRecallDisplayedAnalyzer = new IsIndividualRecallDisplayedAnalyzer(raceLog);
|
||||||
this.recallDisplayedFinder = new IndividualRecallDisplayedFinder(raceLog);
|
this.recallDisplayedFinder = new IndividualRecallDisplayedFinder(raceLog);
|
||||||
this.recallRemovedFinder = new IndividualRecallRemovedFinder(raceLog);
|
this.recallRemovedFinder = new IndividualRecallRemovedFinder(raceLog);
|
||||||
this.finishingTimeFinder = new FinishingTimeFinder(raceLog);
|
this.finishingTimeFinder = new FinishingTimeFinder(raceLog);
|
||||||
this.finishedTimeFinder = new FinishedTimeFinder(raceLog);
|
this.finishedTimeFinder = new FinishedTimeFinder(raceLog);
|
||||||
this.startTimeFinder = new StartTimeFinder(raceLogResolver, raceLog);
|
// Use the following in order to initialize a start time finder once it's needed for start time-dependent individual recall timeouts
|
||||||
|
// this.startTimeFinder = new StartTimeFinder(raceLogResolver, raceLog);
|
||||||
|
|
||||||
this.raceLogListener = new RaceLogChangedVisitor(this);
|
this.raceLogListener = new RaceLogChangedVisitor(this);
|
||||||
this.raceLog.addListener(raceLogListener);
|
this.raceLog.addListener(raceLogListener);
|
||||||
@@ -131,7 +133,7 @@ public abstract class BaseRacingProcedure extends BaseRaceStateChangedListener i
|
|||||||
break;
|
break;
|
||||||
case RUNNING:
|
case RUNNING:
|
||||||
if (isIndividualRecallDisplayed()) {
|
if (isIndividualRecallDisplayed()) {
|
||||||
rescheduleIndividualRecallTimeout();
|
rescheduleIndividualRecallTimeout(recallDisplayedFinder.analyze());
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
@@ -139,10 +141,6 @@ public abstract class BaseRacingProcedure extends BaseRaceStateChangedListener i
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private TimePoint getStartTime() {
|
|
||||||
return startTimeFinder.analyze().getStartTime();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isIndividualRecallDisplayed() {
|
public boolean isIndividualRecallDisplayed() {
|
||||||
return cachedIsIndividualRecallDisplayed;
|
return cachedIsIndividualRecallDisplayed;
|
||||||
@@ -150,10 +148,10 @@ public abstract class BaseRacingProcedure extends BaseRaceStateChangedListener i
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isIndividualRecallDisplayed(TimePoint at) {
|
public boolean isIndividualRecallDisplayed(TimePoint at) {
|
||||||
final TimePoint individualRecallDisplayedTime = getIndividualRecallDisplayedTime();
|
if (hasIndividualRecall()) {
|
||||||
final TimePoint individualRecallRemovalTime = getIndividualRecallRemovalTime();
|
return new IsIndividualRecallDisplayedAnalyzer(getRaceLog(), at).analyze();
|
||||||
return (hasIndividualRecall() && individualRecallDisplayedTime != null && !individualRecallDisplayedTime.after(at) &&
|
}
|
||||||
individualRecallRemovalTime != null && !individualRecallRemovalTime.after(at));
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -166,20 +164,17 @@ public abstract class BaseRacingProcedure extends BaseRaceStateChangedListener i
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public TimePoint getIndividualRecallRemovalTime() {
|
public TimePoint getIndividualRecallRemovalTime() {
|
||||||
final TimePoint result;
|
TimePoint displayed = getIndividualRecallDisplayedTime();
|
||||||
final TimePoint raceStartTime = getStartTime();
|
if (hasIndividualRecall()) {
|
||||||
final TimePoint removedEvent;
|
TimePoint removedEvent = recallRemovedFinder.analyze();
|
||||||
if (hasIndividualRecall() && (removedEvent = recallRemovedFinder.analyze()) != null && (raceStartTime == null || removedEvent.after(raceStartTime))) {
|
if (removedEvent != null && (displayed == null || removedEvent.after(displayed))) {
|
||||||
result = removedEvent;
|
return removedEvent;
|
||||||
} else {
|
|
||||||
final TimePoint individualRecallDisplayedTime = getIndividualRecallDisplayedTime();
|
|
||||||
if (individualRecallDisplayedTime != null && raceStartTime != null) {
|
|
||||||
result = raceStartTime.plus(individualRecallRemovalTimeout);
|
|
||||||
} else {
|
|
||||||
result = null;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return result;
|
if (displayed != null) {
|
||||||
|
return displayed.plus(individualRecallRemovalTimeout);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -217,21 +212,18 @@ public abstract class BaseRacingProcedure extends BaseRaceStateChangedListener i
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected void update() {
|
protected void update() {
|
||||||
// TODO an X-ray up event with a time point in the future will not be recognized here because at the current time the flag is not displayed and no other race log event will trigger the update; we'd need to schedule another state event; as long as clocks are set correctly, additional transmission time will make this unlikely
|
boolean isRecallDisplayed = isRecallDisplayedAnalyzer.analyze();
|
||||||
boolean isRecallDisplayed = isIndividualRecallDisplayed(MillisecondsTimePoint.now());
|
|
||||||
if (cachedIsIndividualRecallDisplayed != isRecallDisplayed) {
|
if (cachedIsIndividualRecallDisplayed != isRecallDisplayed) {
|
||||||
cachedIsIndividualRecallDisplayed = isRecallDisplayed;
|
cachedIsIndividualRecallDisplayed = isRecallDisplayed;
|
||||||
if (!cachedIsIndividualRecallDisplayed) {
|
if (cachedIsIndividualRecallDisplayed) {
|
||||||
// individual recall was removed; no need to schedule an event for removal
|
changedListeners.onIndividualRecallDisplayed(this);
|
||||||
|
rescheduleIndividualRecallTimeout(recallDisplayedFinder.analyze());
|
||||||
|
} else {
|
||||||
changedListeners.onIndividualRecallRemoved(this);
|
changedListeners.onIndividualRecallRemoved(this);
|
||||||
unscheduleStateEvent(RaceStateEvents.INDIVIDUAL_RECALL_TIMEOUT);
|
unscheduleStateEvent(RaceStateEvents.INDIVIDUAL_RECALL_TIMEOUT);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// (re-)schedule the individual recall removal in any case; the removal time may have changed
|
|
||||||
if (cachedIsIndividualRecallDisplayed) {
|
|
||||||
changedListeners.onIndividualRecallDisplayed(this);
|
|
||||||
rescheduleIndividualRecallTimeout();
|
|
||||||
}
|
|
||||||
|
|
||||||
// always call listeners for changed flag, as this does not only affect recall, but also
|
// always call listeners for changed flag, as this does not only affect recall, but also
|
||||||
// changes start procedure, for which some text elements need to be updated
|
// changes start procedure, for which some text elements need to be updated
|
||||||
@@ -239,9 +231,9 @@ public abstract class BaseRacingProcedure extends BaseRaceStateChangedListener i
|
|||||||
changedListeners.onActiveFlagsChanged(this);
|
changedListeners.onActiveFlagsChanged(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void rescheduleIndividualRecallTimeout() {
|
private void rescheduleIndividualRecallTimeout(TimePoint displayTime) {
|
||||||
unscheduleStateEvent(RaceStateEvents.INDIVIDUAL_RECALL_TIMEOUT);
|
unscheduleStateEvent(RaceStateEvents.INDIVIDUAL_RECALL_TIMEOUT);
|
||||||
scheduleStateEvents(new RaceStateEventImpl(getIndividualRecallRemovalTime(), RaceStateEvents.INDIVIDUAL_RECALL_TIMEOUT));
|
scheduleStateEvents(new RaceStateEventImpl(displayTime.plus(individualRecallRemovalTimeout), RaceStateEvents.INDIVIDUAL_RECALL_TIMEOUT));
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void scheduleStateEvents(RaceStateEvent stateEvent) {
|
protected void scheduleStateEvents(RaceStateEvent stateEvent) {
|
||||||
|
|||||||
+2
-2
@@ -61,7 +61,7 @@ public class TestSimpleTimeOnTimeRankingWithOneUpwindLeg {
|
|||||||
private DynamicTrackedRace trackedRace;
|
private DynamicTrackedRace trackedRace;
|
||||||
private Competitor c1, c2;
|
private Competitor c1, c2;
|
||||||
|
|
||||||
private void setUp(Function<Competitor, Double> timeOnTimeFactors, Function<Competitor, Double> timeOnDistanceFactors) {
|
private void setUp(TimeOnTimeFactorMapping timeOnTimeFactors, Function<Competitor, Double> timeOnDistanceFactors) {
|
||||||
c1 = TrackBasedTest.createCompetitor("FastBoat");
|
c1 = TrackBasedTest.createCompetitor("FastBoat");
|
||||||
c2 = TrackBasedTest.createCompetitor("SlowBoat");
|
c2 = TrackBasedTest.createCompetitor("SlowBoat");
|
||||||
trackedRace = createTrackedRace(Arrays.asList(c1, c2), timeOnTimeFactors, timeOnDistanceFactors);
|
trackedRace = createTrackedRace(Arrays.asList(c1, c2), timeOnTimeFactors, timeOnDistanceFactors);
|
||||||
@@ -70,7 +70,7 @@ public class TestSimpleTimeOnTimeRankingWithOneUpwindLeg {
|
|||||||
assertSame(RankingMetrics.TIME_ON_TIME_AND_DISTANCE, trackedRace.getTrackedRegatta().getRegatta().getRankingMetricType());
|
assertSame(RankingMetrics.TIME_ON_TIME_AND_DISTANCE, trackedRace.getTrackedRegatta().getRegatta().getRankingMetricType());
|
||||||
}
|
}
|
||||||
|
|
||||||
private DynamicTrackedRace createTrackedRace(Iterable<Competitor> competitors, Function<Competitor, Double> timeOnTimeFactors, Function<Competitor, Double> timeOnDistanceFactors) {
|
private DynamicTrackedRace createTrackedRace(Iterable<Competitor> competitors, TimeOnTimeFactorMapping timeOnTimeFactors, Function<Competitor, Double> timeOnDistanceFactors) {
|
||||||
final TimePoint timePointForFixes = MillisecondsTimePoint.now();
|
final TimePoint timePointForFixes = MillisecondsTimePoint.now();
|
||||||
BoatClassImpl boatClass = new BoatClassImpl("Some Handicap Boat Class", /* typicallyStartsUpwind */ true);
|
BoatClassImpl boatClass = new BoatClassImpl("Some Handicap Boat Class", /* typicallyStartsUpwind */ true);
|
||||||
Regatta regatta = new RegattaImpl(EmptyRaceLogStore.INSTANCE, EmptyRegattaLogStore.INSTANCE,
|
Regatta regatta = new RegattaImpl(EmptyRaceLogStore.INSTANCE, EmptyRegattaLogStore.INSTANCE,
|
||||||
|
|||||||
+47
@@ -0,0 +1,47 @@
|
|||||||
|
package com.sap.sailing.domain.test;
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertNotNull;
|
||||||
|
import static org.junit.Assert.assertTrue;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import com.sap.sailing.domain.base.BoatClass;
|
||||||
|
import com.sap.sailing.domain.base.Competitor;
|
||||||
|
import com.sap.sailing.domain.base.DomainFactory;
|
||||||
|
import com.sap.sailing.domain.base.Sideline;
|
||||||
|
import com.sap.sailing.domain.base.Waypoint;
|
||||||
|
import com.sap.sailing.domain.base.impl.CourseImpl;
|
||||||
|
import com.sap.sailing.domain.base.impl.RaceDefinitionImpl;
|
||||||
|
import com.sap.sailing.domain.base.impl.RegattaImpl;
|
||||||
|
import com.sap.sailing.domain.leaderboard.impl.LowPoint;
|
||||||
|
import com.sap.sailing.domain.racelog.impl.EmptyRaceLogStore;
|
||||||
|
import com.sap.sailing.domain.racelog.tracking.EmptyGPSFixStore;
|
||||||
|
import com.sap.sailing.domain.ranking.RankingMetric;
|
||||||
|
import com.sap.sailing.domain.ranking.TimeOnTimeAndDistanceRankingMetric;
|
||||||
|
import com.sap.sailing.domain.regattalog.impl.EmptyRegattaLogStore;
|
||||||
|
import com.sap.sailing.domain.tracking.TrackedRace;
|
||||||
|
import com.sap.sailing.domain.tracking.impl.DynamicTrackedRaceImpl;
|
||||||
|
import com.sap.sailing.domain.tracking.impl.DynamicTrackedRegattaImpl;
|
||||||
|
import com.sap.sailing.domain.tracking.impl.EmptyWindStore;
|
||||||
|
|
||||||
|
public class SerializeRankingMetricTest extends AbstractSerializationTest {
|
||||||
|
@Test
|
||||||
|
public void testTimeOnTimeAndDistanceRankingMetricSerialization() throws ClassNotFoundException, IOException {
|
||||||
|
final BoatClass _49er = DomainFactory.INSTANCE.getOrCreateBoatClass("49er");
|
||||||
|
final TrackedRace trackedRace = new DynamicTrackedRaceImpl(new DynamicTrackedRegattaImpl(
|
||||||
|
new RegattaImpl(EmptyRaceLogStore.INSTANCE, EmptyRegattaLogStore.INSTANCE, "Regatta", /* boatClass */ _49er,
|
||||||
|
/* startDate */ null, /* endDate */ null, /* trackedRegattaRegistry */ null,
|
||||||
|
new LowPoint(), UUID.randomUUID(), /* courseArea */ null)),
|
||||||
|
new RaceDefinitionImpl("Race", new CourseImpl("Course", Collections.<Waypoint>emptyList()) ,
|
||||||
|
/* boatClass */ _49er, Collections.<Competitor>emptySet()),
|
||||||
|
Collections.<Sideline>emptyList(), EmptyWindStore.INSTANCE, EmptyGPSFixStore.INSTANCE, 0l, 0l, 0l,
|
||||||
|
false, TimeOnTimeAndDistanceRankingMetric::new, null);
|
||||||
|
RankingMetric clone = cloneBySerialization(trackedRace.getRankingMetric(), DomainFactory.INSTANCE);
|
||||||
|
assertNotNull(clone);
|
||||||
|
assertTrue(clone instanceof TimeOnTimeAndDistanceRankingMetric);
|
||||||
|
}
|
||||||
|
}
|
||||||
+10
-1
@@ -41,6 +41,7 @@ import com.sap.sailing.domain.tracking.TrackedRace;
|
|||||||
import com.sap.sailing.domain.tracking.impl.DynamicGPSFixMovingTrackImpl;
|
import com.sap.sailing.domain.tracking.impl.DynamicGPSFixMovingTrackImpl;
|
||||||
import com.sap.sailing.domain.tracking.impl.DynamicGPSFixTrackImpl;
|
import com.sap.sailing.domain.tracking.impl.DynamicGPSFixTrackImpl;
|
||||||
import com.sap.sse.common.NoCorrespondingServiceRegisteredException;
|
import com.sap.sse.common.NoCorrespondingServiceRegisteredException;
|
||||||
|
import com.sap.sse.common.Util;
|
||||||
import com.sap.sse.common.WithID;
|
import com.sap.sse.common.WithID;
|
||||||
import com.sap.sse.common.impl.TimeRangeImpl;
|
import com.sap.sse.common.impl.TimeRangeImpl;
|
||||||
|
|
||||||
@@ -255,7 +256,15 @@ public class TopLevelMasterData implements Serializable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void setMasterDataExportFlagOnRaceColumns(boolean flagValue) {
|
public void setMasterDataExportFlagOnRaceColumns(boolean flagValue) {
|
||||||
for (LeaderboardGroup group : leaderboardGroups) {
|
// collect all leaderboard groups for all events that will be touched during serialization
|
||||||
|
final Set<LeaderboardGroup> allLeaderboardGroups = new HashSet<>();
|
||||||
|
allLeaderboardGroups.addAll(leaderboardGroups);
|
||||||
|
for (Entry<LeaderboardGroup, Set<Event>> i : eventForLeaderboardGroup.entrySet()) {
|
||||||
|
for (Event e : i.getValue()) {
|
||||||
|
Util.addAll(e.getLeaderboardGroups(), allLeaderboardGroups);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (LeaderboardGroup group : allLeaderboardGroups) {
|
||||||
for (Leaderboard leaderboard : group.getLeaderboards()) {
|
for (Leaderboard leaderboard : group.getLeaderboards()) {
|
||||||
for (RaceColumn raceColumn : leaderboard.getRaceColumns()) {
|
for (RaceColumn raceColumn : leaderboard.getRaceColumns()) {
|
||||||
raceColumn.setMasterDataExportOngoingThreadFlag(true);
|
raceColumn.setMasterDataExportOngoingThreadFlag(true);
|
||||||
|
|||||||
@@ -228,5 +228,19 @@ public interface PolarDataService {
|
|||||||
|
|
||||||
void insertExistingFixes(TrackedRace trackedRace);
|
void insertExistingFixes(TrackedRace trackedRace);
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param boatClass When polars of this boat class change, the listener will be notified. May not be null.
|
||||||
|
* @param listener may not be null
|
||||||
|
*/
|
||||||
|
void registerListener(BoatClass boatClass, PolarsChangedListener listener);
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param boatClass
|
||||||
|
* @param listener
|
||||||
|
*/
|
||||||
|
void unregisterListener(BoatClass boatClass, PolarsChangedListener listener);
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
+10
@@ -0,0 +1,10 @@
|
|||||||
|
package com.sap.sailing.domain.polars;
|
||||||
|
|
||||||
|
public interface PolarsChangedListener {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Is called when the polars of the boat class you registered the listener for changed
|
||||||
|
*/
|
||||||
|
void polarsChanged();
|
||||||
|
|
||||||
|
}
|
||||||
+18
-7
@@ -10,6 +10,7 @@ import java.util.function.Supplier;
|
|||||||
import java.util.stream.StreamSupport;
|
import java.util.stream.StreamSupport;
|
||||||
|
|
||||||
import com.sap.sailing.domain.base.Competitor;
|
import com.sap.sailing.domain.base.Competitor;
|
||||||
|
import com.sap.sailing.domain.base.Course;
|
||||||
import com.sap.sailing.domain.base.Leg;
|
import com.sap.sailing.domain.base.Leg;
|
||||||
import com.sap.sailing.domain.base.Waypoint;
|
import com.sap.sailing.domain.base.Waypoint;
|
||||||
import com.sap.sailing.domain.base.impl.CompetitorImpl;
|
import com.sap.sailing.domain.base.impl.CompetitorImpl;
|
||||||
@@ -24,6 +25,7 @@ import com.sap.sailing.domain.tracking.TrackedLegOfCompetitor;
|
|||||||
import com.sap.sailing.domain.tracking.TrackedRace;
|
import com.sap.sailing.domain.tracking.TrackedRace;
|
||||||
import com.sap.sailing.domain.tracking.WindLegTypeAndLegBearingCache;
|
import com.sap.sailing.domain.tracking.WindLegTypeAndLegBearingCache;
|
||||||
import com.sap.sailing.domain.tracking.WindPositionMode;
|
import com.sap.sailing.domain.tracking.WindPositionMode;
|
||||||
|
import com.sap.sailing.domain.tracking.impl.AbstractRaceRankComparator;
|
||||||
import com.sap.sse.common.Duration;
|
import com.sap.sse.common.Duration;
|
||||||
import com.sap.sse.common.TimePoint;
|
import com.sap.sse.common.TimePoint;
|
||||||
|
|
||||||
@@ -281,17 +283,20 @@ public abstract class AbstractRankingMetric implements RankingMetric {
|
|||||||
/**
|
/**
|
||||||
* Constructs a comparator based on the results of
|
* Constructs a comparator based on the results of
|
||||||
* {@link #getWindwardDistanceTraveled(Competitor, TimePoint, WindLegTypeAndLegBearingCache)} where competitors are
|
* {@link #getWindwardDistanceTraveled(Competitor, TimePoint, WindLegTypeAndLegBearingCache)} where competitors are
|
||||||
* "less" than other competitors ("better") if they have a greater windward distance traveled.
|
* "less" than other competitors ("better") if they are in a later leg or, if in the same leg, have a greater
|
||||||
|
* windward distance traveled. If both competitors have already finished the race, the finishing time is compared.
|
||||||
*/
|
*/
|
||||||
private Comparator<Competitor> getWindwardDistanceTraveledComparator(final TimePoint timePoint, final WindLegTypeAndLegBearingCache cache) {
|
private Comparator<Competitor> getWindwardDistanceTraveledComparator(final TimePoint timePoint, final WindLegTypeAndLegBearingCache cache) {
|
||||||
final Map<Competitor, Distance> windwardDistanceTraveledPerCompetitor = new HashMap<>();
|
final Map<Competitor, Distance> windwardDistanceTraveledPerCompetitor = new HashMap<>();
|
||||||
for (final Competitor competitor : getCompetitors()) {
|
for (final Competitor competitor : getCompetitors()) {
|
||||||
windwardDistanceTraveledPerCompetitor.put(competitor, getWindwardDistanceTraveled(competitor, timePoint, cache));
|
windwardDistanceTraveledPerCompetitor.put(competitor, getWindwardDistanceTraveled(competitor, timePoint, cache));
|
||||||
}
|
}
|
||||||
final Comparator<Distance> nullsFirstDistanceComparator = Comparator.nullsFirst(Comparator.naturalOrder());
|
return new AbstractRaceRankComparator<Distance>(trackedRace, timePoint, /* lessIsBetter */ false) {
|
||||||
return (c1, c2) -> nullsFirstDistanceComparator.compare(
|
@Override
|
||||||
windwardDistanceTraveledPerCompetitor.get(c2),
|
protected Distance getComparisonValueForSameLeg(Competitor competitor) {
|
||||||
windwardDistanceTraveledPerCompetitor.get(c1));
|
return windwardDistanceTraveledPerCompetitor.get(competitor);
|
||||||
|
}
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -508,8 +513,8 @@ public abstract class AbstractRankingMetric implements RankingMetric {
|
|||||||
if (legTo.hasFinishedLeg(timePoint)) {
|
if (legTo.hasFinishedLeg(timePoint)) {
|
||||||
// calculate actual time it takes who to reach the end of the leg starting at timePoint:
|
// calculate actual time it takes who to reach the end of the leg starting at timePoint:
|
||||||
final TimePoint whosLegFinishTime = legWho.getFinishTime();
|
final TimePoint whosLegFinishTime = legWho.getFinishTime();
|
||||||
if (whosLegFinishTime != null) {
|
if (whosLegFinishTime != null && !whosLegFinishTime.after(timePoint)) {
|
||||||
// who's leg finishing time is known; we don't need to extrapolate
|
// who's leg finishing time is known and is already reached at timePoint; we don't need to extrapolate
|
||||||
toEndOfLegOrTo = timePoint.until(whosLegFinishTime);
|
toEndOfLegOrTo = timePoint.until(whosLegFinishTime);
|
||||||
} else {
|
} else {
|
||||||
assert getWindwardDistanceTraveled(legTo.getCompetitor(), legTo.hasFinishedLeg(timePoint)?legTo.getFinishTime():timePoint, cache).compareTo(
|
assert getWindwardDistanceTraveled(legTo.getCompetitor(), legTo.hasFinishedLeg(timePoint)?legTo.getFinishTime():timePoint, cache).compareTo(
|
||||||
@@ -601,6 +606,9 @@ public abstract class AbstractRankingMetric implements RankingMetric {
|
|||||||
} else {
|
} else {
|
||||||
Distance d = Distance.NULL;
|
Distance d = Distance.NULL;
|
||||||
boolean count = false; // start counting only once the "from" waypoint has been found
|
boolean count = false; // start counting only once the "from" waypoint has been found
|
||||||
|
final Course course = getTrackedRace().getRace().getCourse();
|
||||||
|
course.lockForRead();
|
||||||
|
try {
|
||||||
for (final TrackedLeg trackedLeg : getTrackedRace().getTrackedLegs()) {
|
for (final TrackedLeg trackedLeg : getTrackedRace().getTrackedLegs()) {
|
||||||
count = count || trackedLeg.getLeg().getFrom() == from;
|
count = count || trackedLeg.getLeg().getFrom() == from;
|
||||||
if (count) {
|
if (count) {
|
||||||
@@ -629,6 +637,9 @@ public abstract class AbstractRankingMetric implements RankingMetric {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
} finally {
|
||||||
|
course.unlockAfterRead();
|
||||||
|
}
|
||||||
result = d;
|
result = d;
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
|
|||||||
+9
@@ -0,0 +1,9 @@
|
|||||||
|
package com.sap.sailing.domain.ranking;
|
||||||
|
|
||||||
|
import com.sap.sailing.domain.base.Competitor;
|
||||||
|
import com.sap.sse.common.Duration;
|
||||||
|
import com.sap.sse.util.SerializableFunction;
|
||||||
|
|
||||||
|
@FunctionalInterface
|
||||||
|
public interface TimeOnDistanceAllowancePerNauticalMileMap extends SerializableFunction<Competitor, Duration> {
|
||||||
|
}
|
||||||
+4
-5
@@ -3,7 +3,6 @@ package com.sap.sailing.domain.ranking;
|
|||||||
import java.util.Comparator;
|
import java.util.Comparator;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.function.Function;
|
|
||||||
import java.util.function.Supplier;
|
import java.util.function.Supplier;
|
||||||
|
|
||||||
import com.sap.sailing.domain.base.Competitor;
|
import com.sap.sailing.domain.base.Competitor;
|
||||||
@@ -52,9 +51,9 @@ public class TimeOnTimeAndDistanceRankingMetric extends AbstractRankingMetric {
|
|||||||
|
|
||||||
public final static RankingMetricConstructor CONSTRUCTOR = TimeOnTimeAndDistanceRankingMetric::new;
|
public final static RankingMetricConstructor CONSTRUCTOR = TimeOnTimeAndDistanceRankingMetric::new;
|
||||||
|
|
||||||
private final Function<Competitor, Double> timeOnTimeFactor;
|
private final TimeOnTimeFactorMapping timeOnTimeFactor;
|
||||||
|
|
||||||
private final Function<Competitor, Duration> timeOnDistanceFactorNauticalMile;
|
private final TimeOnDistanceAllowancePerNauticalMileMap timeOnDistanceFactorNauticalMile;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The regular constructor that can also be used as <code>TimeOnTimeAndDistanceRankingMetric::new</code>
|
* The regular constructor that can also be used as <code>TimeOnTimeAndDistanceRankingMetric::new</code>
|
||||||
@@ -72,8 +71,8 @@ public class TimeOnTimeAndDistanceRankingMetric extends AbstractRankingMetric {
|
|||||||
* its regatta, handicap mappings can be passed directly and overrule anything defined for the competitor or
|
* its regatta, handicap mappings can be passed directly and overrule anything defined for the competitor or
|
||||||
* on the regatta.
|
* on the regatta.
|
||||||
*/
|
*/
|
||||||
public TimeOnTimeAndDistanceRankingMetric(final TrackedRace trackedRace, Function<Competitor, Double> timeOnTimeFactor,
|
public TimeOnTimeAndDistanceRankingMetric(final TrackedRace trackedRace, TimeOnTimeFactorMapping timeOnTimeFactor,
|
||||||
Function<Competitor, Duration> timeOnDistanceFactorInSecondsPerNauticalMile) {
|
TimeOnDistanceAllowancePerNauticalMileMap timeOnDistanceFactorInSecondsPerNauticalMile) {
|
||||||
super(trackedRace);
|
super(trackedRace);
|
||||||
this.timeOnTimeFactor = timeOnTimeFactor;
|
this.timeOnTimeFactor = timeOnTimeFactor;
|
||||||
this.timeOnDistanceFactorNauticalMile = timeOnDistanceFactorInSecondsPerNauticalMile;
|
this.timeOnDistanceFactorNauticalMile = timeOnDistanceFactorInSecondsPerNauticalMile;
|
||||||
|
|||||||
Executable
+8
@@ -0,0 +1,8 @@
|
|||||||
|
package com.sap.sailing.domain.ranking;
|
||||||
|
|
||||||
|
import com.sap.sailing.domain.base.Competitor;
|
||||||
|
import com.sap.sse.util.SerializableFunction;
|
||||||
|
|
||||||
|
@FunctionalInterface
|
||||||
|
public interface TimeOnTimeFactorMapping extends SerializableFunction<Competitor, Double> {
|
||||||
|
}
|
||||||
+129
@@ -0,0 +1,129 @@
|
|||||||
|
package com.sap.sailing.domain.tracking.impl;
|
||||||
|
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.Comparator;
|
||||||
|
import java.util.NavigableSet;
|
||||||
|
import java.util.SortedSet;
|
||||||
|
|
||||||
|
import com.sap.sailing.domain.base.Competitor;
|
||||||
|
import com.sap.sailing.domain.base.Course;
|
||||||
|
import com.sap.sailing.domain.tracking.MarkPassing;
|
||||||
|
import com.sap.sailing.domain.tracking.TrackedLegOfCompetitor;
|
||||||
|
import com.sap.sailing.domain.tracking.TrackedRace;
|
||||||
|
import com.sap.sse.common.TimePoint;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Compares two competitors by their ranking in the overall race for a given time point. Competitors who haven't started
|
||||||
|
* the first leg are all equally ranked last. Competitors in different legs are ranked by inverse leg index: the higher
|
||||||
|
* the number of the leg the lesser (better) the rank. Competitors in the same leg are ranked by their windward distance
|
||||||
|
* to go in that leg, requiring wind data or estimates to be available for the given time point. The wind is estimated at
|
||||||
|
* the middle of the leg for consistent ordering, so the same wind data will be used for comparing all competitors in the
|
||||||
|
* same leg at a given point in time.
|
||||||
|
* <p>
|
||||||
|
*
|
||||||
|
* This comparator assumes that the race's {@link Course} remains unchanged from the time this comparator's constructor
|
||||||
|
* is invoked and the last call to {@link #compare(Competitor, Competitor)} on this comparator. This should be obvious
|
||||||
|
* because course changes have an effect on the race's leg structure and therefore on the foundations for ranking.
|
||||||
|
* Clients should use {@link Course#lockForRead()} and {@link Course#unlockAfterRead()} to frame the construction and
|
||||||
|
* use of this comparator.<p>
|
||||||
|
*
|
||||||
|
* Two different competitors may end up being ranked equal by this comparator. So take care and don't use this
|
||||||
|
* comparator class when inserting into an {@link SortedSet} when you want something like a ranking. It may overwrite
|
||||||
|
* existing entries. Use {@link Collections#sort(java.util.List, Comparator)} instead.
|
||||||
|
*
|
||||||
|
* @author Axel Uhl (d043530)
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public abstract class AbstractRaceRankComparator<C extends Comparable<C>> implements Comparator<Competitor> {
|
||||||
|
private final TrackedRace trackedRace;
|
||||||
|
private final TimePoint timePoint;
|
||||||
|
private final DummyMarkPassingWithTimePointOnly markPassingWithTimePoint;
|
||||||
|
private final boolean lessIsBetter;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param lessIsBetter
|
||||||
|
* tells whether lesser return values for {@link #getComparisonValueForSameLeg(Competitor)} denote a
|
||||||
|
* better competitor ranking or not.
|
||||||
|
*/
|
||||||
|
public AbstractRaceRankComparator(TrackedRace trackedRace, TimePoint timePoint, boolean lessIsBetter) {
|
||||||
|
super();
|
||||||
|
this.trackedRace = trackedRace;
|
||||||
|
this.timePoint = timePoint;
|
||||||
|
this.markPassingWithTimePoint = new DummyMarkPassingWithTimePointOnly(timePoint);
|
||||||
|
this.lessIsBetter = lessIsBetter;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int compare(Competitor o1, Competitor o2) {
|
||||||
|
int result;
|
||||||
|
if (o1 == o2) {
|
||||||
|
result = 0;
|
||||||
|
} else {
|
||||||
|
NavigableSet<MarkPassing> o1MarkPassings = trackedRace.getMarkPassings(o1);
|
||||||
|
NavigableSet<MarkPassing> o1MarkPassingsBeforeTimePoint;
|
||||||
|
MarkPassing o1LastMarkPassingBeforeTimePoint = null;
|
||||||
|
int o1MarkPassingsBeforeTimePointSize;
|
||||||
|
TrackedLegOfCompetitor o1Leg;
|
||||||
|
trackedRace.lockForRead(o1MarkPassings);
|
||||||
|
try {
|
||||||
|
o1MarkPassingsBeforeTimePoint = o1MarkPassings.headSet(
|
||||||
|
markPassingWithTimePoint, /* inclusive */true);
|
||||||
|
o1MarkPassingsBeforeTimePointSize = o1MarkPassingsBeforeTimePoint.size();
|
||||||
|
if (o1MarkPassingsBeforeTimePointSize > 0) {
|
||||||
|
o1LastMarkPassingBeforeTimePoint = o1MarkPassingsBeforeTimePoint.last();
|
||||||
|
}
|
||||||
|
o1Leg = trackedRace.getCurrentLeg(o1, timePoint);
|
||||||
|
} finally {
|
||||||
|
trackedRace.unlockAfterRead(o1MarkPassings);
|
||||||
|
}
|
||||||
|
NavigableSet<MarkPassing> o2MarkPassings = trackedRace.getMarkPassings(o2);
|
||||||
|
NavigableSet<MarkPassing> o2MarkPassingsBeforeTimePoint;
|
||||||
|
MarkPassing o2LastMarkPassingBeforeTimePoint = null;
|
||||||
|
int o2MarkPassingsBeforeTimePointSize;
|
||||||
|
TrackedLegOfCompetitor o2Leg;
|
||||||
|
trackedRace.lockForRead(o2MarkPassings);
|
||||||
|
try {
|
||||||
|
o2MarkPassingsBeforeTimePoint = o2MarkPassings.headSet(markPassingWithTimePoint, /* inclusive */true);
|
||||||
|
o2MarkPassingsBeforeTimePointSize = o2MarkPassingsBeforeTimePoint.size();
|
||||||
|
if (o2MarkPassingsBeforeTimePointSize > 0) {
|
||||||
|
o2LastMarkPassingBeforeTimePoint = o2MarkPassingsBeforeTimePoint.last();
|
||||||
|
}
|
||||||
|
o2Leg = trackedRace.getCurrentLeg(o2, timePoint);
|
||||||
|
} finally {
|
||||||
|
trackedRace.unlockAfterRead(o2MarkPassings);
|
||||||
|
}
|
||||||
|
result = o2MarkPassingsBeforeTimePointSize - o1MarkPassingsBeforeTimePointSize; // inverted: more legs means
|
||||||
|
// smaller rank
|
||||||
|
if (result == 0 && o1MarkPassingsBeforeTimePointSize > 0) {
|
||||||
|
// Competitors are on same leg and both have already started the first leg.
|
||||||
|
// TrackedLegOfCompetitor comparison also correctly uses finish times for a leg
|
||||||
|
// in case we have the final leg, so both competitors finished the race.
|
||||||
|
if (o1Leg == null) {
|
||||||
|
// both must already have finished race; sort by race finish time: earlier time means smaller
|
||||||
|
// (better) rank
|
||||||
|
result = o1LastMarkPassingBeforeTimePoint.getTimePoint().compareTo(
|
||||||
|
o2LastMarkPassingBeforeTimePoint.getTimePoint());
|
||||||
|
} else {
|
||||||
|
if (o2Leg == null) {
|
||||||
|
result = 1; // o1Leg != null, so o1 has started leg already, o2 hasn't
|
||||||
|
} else {
|
||||||
|
if (o1Leg.getLeg() != o2Leg.getLeg()) {
|
||||||
|
// strange: both have the same number of mark passings but are in different legs; something is
|
||||||
|
// broken, but we can only try our best:
|
||||||
|
result = trackedRace.getRace().getCourse().getLegs().indexOf(o1Leg.getLeg()) -
|
||||||
|
trackedRace.getRace().getCourse().getLegs().indexOf(o2Leg.getLeg());
|
||||||
|
} else {
|
||||||
|
// competitors are in same leg; compare their windward distance to go
|
||||||
|
final C wwdtgO1 = getComparisonValueForSameLeg(o1);
|
||||||
|
final C wwdtgO2 = getComparisonValueForSameLeg(o2);
|
||||||
|
result = wwdtgO1==null?wwdtgO2==null?0:-1:wwdtgO2==null?1:(lessIsBetter?1:-1)*wwdtgO1.compareTo(wwdtgO2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected abstract C getComparisonValueForSameLeg(Competitor competitor);
|
||||||
|
}
|
||||||
+4
-79
@@ -4,13 +4,11 @@ import java.util.Collections;
|
|||||||
import java.util.Comparator;
|
import java.util.Comparator;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.NavigableSet;
|
|
||||||
import java.util.SortedSet;
|
import java.util.SortedSet;
|
||||||
|
|
||||||
import com.sap.sailing.domain.base.Competitor;
|
import com.sap.sailing.domain.base.Competitor;
|
||||||
import com.sap.sailing.domain.base.Course;
|
import com.sap.sailing.domain.base.Course;
|
||||||
import com.sap.sailing.domain.common.Distance;
|
import com.sap.sailing.domain.common.Distance;
|
||||||
import com.sap.sailing.domain.tracking.MarkPassing;
|
|
||||||
import com.sap.sailing.domain.tracking.TrackedLegOfCompetitor;
|
import com.sap.sailing.domain.tracking.TrackedLegOfCompetitor;
|
||||||
import com.sap.sailing.domain.tracking.TrackedRace;
|
import com.sap.sailing.domain.tracking.TrackedRace;
|
||||||
import com.sap.sailing.domain.tracking.WindLegTypeAndLegBearingCache;
|
import com.sap.sailing.domain.tracking.WindLegTypeAndLegBearingCache;
|
||||||
@@ -39,17 +37,11 @@ import com.sap.sse.common.TimePoint;
|
|||||||
* @author Axel Uhl (d043530)
|
* @author Axel Uhl (d043530)
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
public class RaceRankComparator implements Comparator<Competitor> {
|
public class RaceRankComparator extends AbstractRaceRankComparator<Distance> {
|
||||||
private final TrackedRace trackedRace;
|
|
||||||
private final TimePoint timePoint;
|
|
||||||
private final DummyMarkPassingWithTimePointOnly markPassingWithTimePoint;
|
|
||||||
private final Map<Competitor, Distance> windwardDistanceToGoInLegCache;
|
private final Map<Competitor, Distance> windwardDistanceToGoInLegCache;
|
||||||
|
|
||||||
public RaceRankComparator(TrackedRace trackedRace, TimePoint timePoint, WindLegTypeAndLegBearingCache cache) {
|
public RaceRankComparator(TrackedRace trackedRace, TimePoint timePoint, WindLegTypeAndLegBearingCache cache) {
|
||||||
super();
|
super(trackedRace, timePoint, /* lessIsBetter */ true);
|
||||||
this.trackedRace = trackedRace;
|
|
||||||
this.timePoint = timePoint;
|
|
||||||
this.markPassingWithTimePoint = new DummyMarkPassingWithTimePointOnly(timePoint);
|
|
||||||
this.windwardDistanceToGoInLegCache = new HashMap<Competitor, Distance>();
|
this.windwardDistanceToGoInLegCache = new HashMap<Competitor, Distance>();
|
||||||
for (Competitor competitor : trackedRace.getRace().getCompetitors()) {
|
for (Competitor competitor : trackedRace.getRace().getCompetitors()) {
|
||||||
final TrackedLegOfCompetitor trackedLegOfCompetitor = trackedRace.getTrackedLeg(competitor, timePoint);
|
final TrackedLegOfCompetitor trackedLegOfCompetitor = trackedRace.getTrackedLeg(competitor, timePoint);
|
||||||
@@ -61,74 +53,7 @@ public class RaceRankComparator implements Comparator<Competitor> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int compare(Competitor o1, Competitor o2) {
|
protected Distance getComparisonValueForSameLeg(Competitor o1) {
|
||||||
int result;
|
return windwardDistanceToGoInLegCache.get(o1);
|
||||||
if (o1 == o2) {
|
|
||||||
result = 0;
|
|
||||||
} else {
|
|
||||||
NavigableSet<MarkPassing> o1MarkPassings = trackedRace.getMarkPassings(o1);
|
|
||||||
NavigableSet<MarkPassing> o1MarkPassingsBeforeTimePoint;
|
|
||||||
MarkPassing o1LastMarkPassingBeforeTimePoint = null;
|
|
||||||
int o1MarkPassingsBeforeTimePointSize;
|
|
||||||
TrackedLegOfCompetitor o1Leg;
|
|
||||||
trackedRace.lockForRead(o1MarkPassings);
|
|
||||||
try {
|
|
||||||
o1MarkPassingsBeforeTimePoint = o1MarkPassings.headSet(
|
|
||||||
markPassingWithTimePoint, /* inclusive */true);
|
|
||||||
o1MarkPassingsBeforeTimePointSize = o1MarkPassingsBeforeTimePoint.size();
|
|
||||||
if (o1MarkPassingsBeforeTimePointSize > 0) {
|
|
||||||
o1LastMarkPassingBeforeTimePoint = o1MarkPassingsBeforeTimePoint.last();
|
|
||||||
}
|
|
||||||
o1Leg = trackedRace.getCurrentLeg(o1, timePoint);
|
|
||||||
} finally {
|
|
||||||
trackedRace.unlockAfterRead(o1MarkPassings);
|
|
||||||
}
|
|
||||||
NavigableSet<MarkPassing> o2MarkPassings = trackedRace.getMarkPassings(o2);
|
|
||||||
NavigableSet<MarkPassing> o2MarkPassingsBeforeTimePoint;
|
|
||||||
MarkPassing o2LastMarkPassingBeforeTimePoint = null;
|
|
||||||
int o2MarkPassingsBeforeTimePointSize;
|
|
||||||
TrackedLegOfCompetitor o2Leg;
|
|
||||||
trackedRace.lockForRead(o2MarkPassings);
|
|
||||||
try {
|
|
||||||
o2MarkPassingsBeforeTimePoint = o2MarkPassings.headSet(markPassingWithTimePoint, /* inclusive */true);
|
|
||||||
o2MarkPassingsBeforeTimePointSize = o2MarkPassingsBeforeTimePoint.size();
|
|
||||||
if (o2MarkPassingsBeforeTimePointSize > 0) {
|
|
||||||
o2LastMarkPassingBeforeTimePoint = o2MarkPassingsBeforeTimePoint.last();
|
|
||||||
}
|
|
||||||
o2Leg = trackedRace.getCurrentLeg(o2, timePoint);
|
|
||||||
} finally {
|
|
||||||
trackedRace.unlockAfterRead(o2MarkPassings);
|
|
||||||
}
|
|
||||||
result = o2MarkPassingsBeforeTimePointSize - o1MarkPassingsBeforeTimePointSize; // inverted: more legs means
|
|
||||||
// smaller rank
|
|
||||||
if (result == 0 && o1MarkPassingsBeforeTimePointSize > 0) {
|
|
||||||
// Competitors are on same leg and both have already started the first leg.
|
|
||||||
// TrackedLegOfCompetitor comparison also correctly uses finish times for a leg
|
|
||||||
// in case we have the final leg, so both competitors finished the race.
|
|
||||||
if (o1Leg == null) {
|
|
||||||
// both must already have finished race; sort by race finish time: earlier time means smaller
|
|
||||||
// (better) rank
|
|
||||||
result = o1LastMarkPassingBeforeTimePoint.getTimePoint().compareTo(
|
|
||||||
o2LastMarkPassingBeforeTimePoint.getTimePoint());
|
|
||||||
} else {
|
|
||||||
if (o2Leg == null) {
|
|
||||||
result = 1; // o1Leg != null, so o1 has started leg already, o2 hasn't
|
|
||||||
} else {
|
|
||||||
if (o1Leg.getLeg() != o2Leg.getLeg()) {
|
|
||||||
// strange: both have the same number of mark passings but are in different legs; something is
|
|
||||||
// broken, but we can only try our best:
|
|
||||||
result = trackedRace.getRace().getCourse().getLegs().indexOf(o1Leg.getLeg()) -
|
|
||||||
trackedRace.getRace().getCourse().getLegs().indexOf(o2Leg.getLeg());
|
|
||||||
} else {
|
|
||||||
// competitors are in same leg; compare their windward distance to go
|
|
||||||
final Distance wwdtgO1 = windwardDistanceToGoInLegCache.get(o1);
|
|
||||||
final Distance wwdtgO2 = windwardDistanceToGoInLegCache.get(o2);
|
|
||||||
result = wwdtgO1==null?wwdtgO2==null?0:-1:wwdtgO2==null?1:wwdtgO1.compareTo(wwdtgO2);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Executable → Regular
File mode changed.
Executable → Regular
File mode changed.
+1
-1
@@ -189,7 +189,7 @@ public class AdminConsoleEntryPoint extends AbstractSailingEntryPoint implements
|
|||||||
|
|
||||||
StructureImportManagementPanel structureImportUrlsManagementPanel = new StructureImportManagementPanel(sailingService, this, getStringMessages(), this, eventManagementPanel);
|
StructureImportManagementPanel structureImportUrlsManagementPanel = new StructureImportManagementPanel(sailingService, this, getStringMessages(), this, eventManagementPanel);
|
||||||
panel.addToTabPanel(connectorsTabPanel, new DefaultRefreshableAdminConsolePanel<StructureImportManagementPanel>(structureImportUrlsManagementPanel),
|
panel.addToTabPanel(connectorsTabPanel, new DefaultRefreshableAdminConsolePanel<StructureImportManagementPanel>(structureImportUrlsManagementPanel),
|
||||||
getStringMessages().structureImportUrls(), Permission.MANAGE_STRUCTURE_IMPORT_URLS);
|
getStringMessages().manage2Sail() + " " + getStringMessages().regattaStructureImport(), Permission.MANAGE_STRUCTURE_IMPORT_URLS);
|
||||||
|
|
||||||
/* ADVANCED */
|
/* ADVANCED */
|
||||||
|
|
||||||
|
|||||||
+39
-29
@@ -10,7 +10,6 @@ import java.util.Map;
|
|||||||
import java.util.Map.Entry;
|
import java.util.Map.Entry;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
import com.google.gwt.dom.client.Style.Unit;
|
|
||||||
import com.google.gwt.event.dom.client.ChangeEvent;
|
import com.google.gwt.event.dom.client.ChangeEvent;
|
||||||
import com.google.gwt.event.dom.client.ChangeHandler;
|
import com.google.gwt.event.dom.client.ChangeHandler;
|
||||||
import com.google.gwt.event.dom.client.ClickEvent;
|
import com.google.gwt.event.dom.client.ClickEvent;
|
||||||
@@ -18,16 +17,18 @@ import com.google.gwt.event.dom.client.ClickHandler;
|
|||||||
import com.google.gwt.user.client.Window;
|
import com.google.gwt.user.client.Window;
|
||||||
import com.google.gwt.user.client.rpc.AsyncCallback;
|
import com.google.gwt.user.client.rpc.AsyncCallback;
|
||||||
import com.google.gwt.user.client.ui.Button;
|
import com.google.gwt.user.client.ui.Button;
|
||||||
|
import com.google.gwt.user.client.ui.CaptionPanel;
|
||||||
import com.google.gwt.user.client.ui.FlexTable;
|
import com.google.gwt.user.client.ui.FlexTable;
|
||||||
import com.google.gwt.user.client.ui.FlowPanel;
|
import com.google.gwt.user.client.ui.FlowPanel;
|
||||||
import com.google.gwt.user.client.ui.Grid;
|
import com.google.gwt.user.client.ui.Grid;
|
||||||
import com.google.gwt.user.client.ui.HasVerticalAlignment;
|
|
||||||
import com.google.gwt.user.client.ui.HorizontalPanel;
|
import com.google.gwt.user.client.ui.HorizontalPanel;
|
||||||
import com.google.gwt.user.client.ui.Label;
|
import com.google.gwt.user.client.ui.Label;
|
||||||
import com.google.gwt.user.client.ui.ListBox;
|
import com.google.gwt.user.client.ui.ListBox;
|
||||||
import com.google.gwt.user.client.ui.Panel;
|
import com.google.gwt.user.client.ui.Panel;
|
||||||
|
import com.google.gwt.user.client.ui.SimplePanel;
|
||||||
import com.google.gwt.user.client.ui.TextBox;
|
import com.google.gwt.user.client.ui.TextBox;
|
||||||
import com.google.gwt.user.client.ui.VerticalPanel;
|
import com.google.gwt.user.client.ui.VerticalPanel;
|
||||||
|
import com.google.gwt.user.client.ui.Widget;
|
||||||
import com.google.gwt.view.client.SelectionChangeEvent;
|
import com.google.gwt.view.client.SelectionChangeEvent;
|
||||||
import com.google.gwt.view.client.SelectionChangeEvent.Handler;
|
import com.google.gwt.view.client.SelectionChangeEvent.Handler;
|
||||||
import com.sap.sailing.domain.common.RankingMetrics;
|
import com.sap.sailing.domain.common.RankingMetrics;
|
||||||
@@ -49,7 +50,7 @@ import com.sap.sse.gwt.client.controls.busyindicator.BusyIndicator;
|
|||||||
import com.sap.sse.gwt.client.controls.busyindicator.SimpleBusyIndicator;
|
import com.sap.sse.gwt.client.controls.busyindicator.SimpleBusyIndicator;
|
||||||
import com.sap.sse.gwt.client.dialog.DataEntryDialog.DialogCallback;
|
import com.sap.sse.gwt.client.dialog.DataEntryDialog.DialogCallback;
|
||||||
|
|
||||||
public class StructureImportManagementPanel extends FlowPanel implements RegattaStructureProvider {
|
public class StructureImportManagementPanel extends SimplePanel implements RegattaStructureProvider {
|
||||||
private final SailingServiceAsync sailingService;
|
private final SailingServiceAsync sailingService;
|
||||||
private final ErrorReporter errorReporter;
|
private final ErrorReporter errorReporter;
|
||||||
private final StringMessages stringMessages;
|
private final StringMessages stringMessages;
|
||||||
@@ -59,7 +60,7 @@ public class StructureImportManagementPanel extends FlowPanel implements Regatta
|
|||||||
private final BusyIndicator busyIndicator;
|
private final BusyIndicator busyIndicator;
|
||||||
private TextBox jsonURLTextBox;
|
private TextBox jsonURLTextBox;
|
||||||
private TextBox eventIDTextBox;
|
private TextBox eventIDTextBox;
|
||||||
|
private CaptionPanel regattaImportPanel;
|
||||||
private Button listRegattasButton;
|
private Button listRegattasButton;
|
||||||
private Button importDetailsButton;
|
private Button importDetailsButton;
|
||||||
private VerticalPanel editSeriesPanel;
|
private VerticalPanel editSeriesPanel;
|
||||||
@@ -105,7 +106,12 @@ public class StructureImportManagementPanel extends FlowPanel implements Regatta
|
|||||||
this.regattaListComposite = new StructureImportListComposite(this.sailingService, new RegattaSelectionModel(
|
this.regattaListComposite = new StructureImportListComposite(this.sailingService, new RegattaSelectionModel(
|
||||||
true), this.regattaRefresher, this, this.errorReporter, this.stringMessages);
|
true), this.regattaRefresher, this, this.errorReporter, this.stringMessages);
|
||||||
regattaListComposite.ensureDebugId("RegattaListComposite");
|
regattaListComposite.ensureDebugId("RegattaListComposite");
|
||||||
createUI();
|
|
||||||
|
VerticalPanel mainPanel = new VerticalPanel();
|
||||||
|
setWidget(mainPanel);
|
||||||
|
mainPanel.setWidth("100%");
|
||||||
|
|
||||||
|
createUI(mainPanel);
|
||||||
regattaListComposite.addSelectionChangeHandler(new Handler() {
|
regattaListComposite.addSelectionChangeHandler(new Handler() {
|
||||||
@Override
|
@Override
|
||||||
public void onSelectionChange(SelectionChangeEvent event) {
|
public void onSelectionChange(SelectionChangeEvent event) {
|
||||||
@@ -116,12 +122,10 @@ public class StructureImportManagementPanel extends FlowPanel implements Regatta
|
|||||||
regattaStructureGrid = new FlexTable();
|
regattaStructureGrid = new FlexTable();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void createUI() {
|
private void createUI(VerticalPanel mainPanel) {
|
||||||
final Panel progressPanel = new FlowPanel();
|
final Panel progressPanel = new FlowPanel();
|
||||||
progressPanel.add(busyIndicator);
|
progressPanel.add(busyIndicator);
|
||||||
Grid URLgrid = new Grid(2, 2);
|
|
||||||
Label eventIDLabel = new Label(stringMessages.event() + ":");
|
|
||||||
Label jsonURLLabel = new Label(stringMessages.jsonUrl() + ":");
|
|
||||||
eventIDTextBox = new TextBox();
|
eventIDTextBox = new TextBox();
|
||||||
eventIDTextBox.addChangeHandler(new ChangeHandler() {
|
eventIDTextBox.addChangeHandler(new ChangeHandler() {
|
||||||
@Override
|
@Override
|
||||||
@@ -161,33 +165,39 @@ public class StructureImportManagementPanel extends FlowPanel implements Regatta
|
|||||||
listRegattasAndTheirStructures();
|
listRegattasAndTheirStructures();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
VerticalPanel vp = new VerticalPanel();
|
|
||||||
|
|
||||||
HorizontalPanel buttonPanel = new HorizontalPanel();
|
Grid eventURLGrid = new Grid(3, 2);
|
||||||
URLgrid.setWidget(0, 0, eventIDLabel);
|
eventURLGrid.setWidget(0, 0, new Label(stringMessages.manage2Sail() + " " + stringMessages.event() + " " + stringMessages.id() + ":"));
|
||||||
URLgrid.setWidget(0, 1, eventIDTextBox);
|
eventURLGrid.setWidget(0, 1, eventIDTextBox);
|
||||||
URLgrid.setWidget(1, 0, jsonURLLabel);
|
eventURLGrid.setWidget(1, 0, new Label(stringMessages.jsonUrl() + ":"));
|
||||||
URLgrid.setWidget(1, 1, jsonURLTextBox);
|
eventURLGrid.setWidget(1, 1, jsonURLTextBox);
|
||||||
vp.add(URLgrid);
|
eventURLGrid.setWidget(2, 1, listRegattasButton);
|
||||||
vp.add(buttonPanel);
|
|
||||||
buttonPanel.add(listRegattasButton);
|
mainPanel.add(progressPanel);
|
||||||
buttonPanel.add(importDetailsButton);
|
mainPanel.add(eventURLGrid);
|
||||||
Grid grid = new Grid(1, 1);
|
|
||||||
vp.add(grid);
|
regattaImportPanel = new CaptionPanel(stringMessages.manage2Sail() + " " + stringMessages.event());
|
||||||
|
mainPanel.add(regattaImportPanel);
|
||||||
|
VerticalPanel regattaImportContentPanel = new VerticalPanel();
|
||||||
|
regattaImportPanel.setContentWidget(regattaImportContentPanel);
|
||||||
|
|
||||||
grid.setWidget(0, 0, regattaListComposite);
|
|
||||||
grid.getRowFormatter().setVerticalAlign(0, HasVerticalAlignment.ALIGN_TOP);
|
|
||||||
grid.getColumnFormatter().getElement(0/** 1 */).getStyle().setPaddingTop(2.0, Unit.EM);
|
|
||||||
editSeriesPanel = new VerticalPanel();
|
editSeriesPanel = new VerticalPanel();
|
||||||
add(progressPanel);
|
|
||||||
add(vp);
|
HorizontalPanel hPanel = new HorizontalPanel();
|
||||||
add(editSeriesPanel);
|
hPanel.setSpacing(10);
|
||||||
|
hPanel.add(regattaListComposite);
|
||||||
|
hPanel.setCellWidth(regattaListComposite, "50%");
|
||||||
|
hPanel.add(editSeriesPanel);
|
||||||
|
hPanel.setCellWidth(editSeriesPanel, "50%");
|
||||||
|
|
||||||
|
regattaImportContentPanel.add(hPanel);
|
||||||
|
regattaImportContentPanel.add(importDetailsButton);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Adds an event selector and a "create new event" button to the {@link #editSeriesPanel} in its first row
|
* Adds an event selector and a "create new event" button to the {@link #editSeriesPanel} in its first row
|
||||||
*/
|
*/
|
||||||
private void createEventSelectionAndCreateEventButtonUI() {
|
private Widget createEventSelectionAndCreateEventButtonUI() {
|
||||||
Grid grid = new Grid(1, 2);
|
Grid grid = new Grid(1, 2);
|
||||||
sailingEventsListBox = new ListBox();
|
sailingEventsListBox = new ListBox();
|
||||||
sailingEventsListBox.setMultipleSelect(false);
|
sailingEventsListBox.setMultipleSelect(false);
|
||||||
@@ -223,7 +233,7 @@ public class StructureImportManagementPanel extends FlowPanel implements Regatta
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
return grid;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void openEventCreateDialog() {
|
private void openEventCreateDialog() {
|
||||||
|
|||||||
+2
-1
@@ -11,6 +11,7 @@ import com.sap.sse.gwt.client.DefaultRule_1_0n;
|
|||||||
public interface StringMessages extends com.sap.sse.gwt.client.StringMessages, com.sap.sse.gwt.adminconsole.StringMessages {
|
public interface StringMessages extends com.sap.sse.gwt.client.StringMessages, com.sap.sse.gwt.adminconsole.StringMessages {
|
||||||
public static final StringMessages INSTANCE = GWT.create(StringMessages.class);
|
public static final StringMessages INSTANCE = GWT.create(StringMessages.class);
|
||||||
|
|
||||||
|
String manage2Sail();
|
||||||
String tracTracEvents();
|
String tracTracEvents();
|
||||||
String swissTimingEvents();
|
String swissTimingEvents();
|
||||||
String trackedBefore();
|
String trackedBefore();
|
||||||
@@ -1164,7 +1165,7 @@ public interface StringMessages extends com.sap.sse.gwt.client.StringMessages, c
|
|||||||
@Override
|
@Override
|
||||||
String errorCommunicatingWithServer();
|
String errorCommunicatingWithServer();
|
||||||
String userManagement();
|
String userManagement();
|
||||||
String structureImportUrls();
|
String regattaStructureImport();
|
||||||
String filteredBy();
|
String filteredBy();
|
||||||
String filterBy();
|
String filterBy();
|
||||||
String editSeries();
|
String editSeries();
|
||||||
|
|||||||
+2
-1
@@ -1,3 +1,4 @@
|
|||||||
|
manage2Sail=Manage2Sail
|
||||||
tracTracEvents=TracTrac Events
|
tracTracEvents=TracTrac Events
|
||||||
swissTimingEvents=SwissTiming Events
|
swissTimingEvents=SwissTiming Events
|
||||||
trackedBefore=History of tracked events
|
trackedBefore=History of tracked events
|
||||||
@@ -1134,7 +1135,7 @@ remoteProcedureCall=Remote Procedure Call
|
|||||||
serverReplies=Server replies
|
serverReplies=Server replies
|
||||||
errorCommunicatingWithServer=Error communicating with server
|
errorCommunicatingWithServer=Error communicating with server
|
||||||
userManagement=User Management
|
userManagement=User Management
|
||||||
structureImportUrls=Regatta Structure Import
|
regattaStructureImport=Regatta Structure Import
|
||||||
filteredBy=filtered by
|
filteredBy=filtered by
|
||||||
editSeries=Edit Series
|
editSeries=Edit Series
|
||||||
pleaseSelectAtLeastOneRegatta=Please select at least one regatta
|
pleaseSelectAtLeastOneRegatta=Please select at least one regatta
|
||||||
|
|||||||
+2
-1
@@ -1,3 +1,4 @@
|
|||||||
|
manage2Sail=Manage2Sail
|
||||||
createNewEvent=Create New EventtracTracEvents=TracTrac Events
|
createNewEvent=Create New EventtracTracEvents=TracTrac Events
|
||||||
swissTimingEvents=SwissTiming Events
|
swissTimingEvents=SwissTiming Events
|
||||||
trackedBefore=Historie verfolgter Events
|
trackedBefore=Historie verfolgter Events
|
||||||
@@ -1128,7 +1129,7 @@ remoteProcedureCall=Entfernter Prozeduraufruf
|
|||||||
serverReplies=Server antwortet
|
serverReplies=Server antwortet
|
||||||
errorCommunicatingWithServer=Fehler bei der Kommunikation mit dem Server
|
errorCommunicatingWithServer=Fehler bei der Kommunikation mit dem Server
|
||||||
userManagement=Benutzerverwaltung
|
userManagement=Benutzerverwaltung
|
||||||
structureImportUrls=Regattastruktur-Import
|
regattaStructureImport=Regattastruktur-Import
|
||||||
editSeries=Serie bearbeiten
|
editSeries=Serie bearbeiten
|
||||||
filteredBy=gefiltert nach
|
filteredBy=gefiltert nach
|
||||||
pleaseSelectAtLeastOneRegatta=Bitte wenigstens eine Regatta auswählen
|
pleaseSelectAtLeastOneRegatta=Bitte wenigstens eine Regatta auswählen
|
||||||
|
|||||||
+2
-1
@@ -1,4 +1,5 @@
|
|||||||
# If you want new properties translated then sent this over GMR (Mark Angell <mangell@gmr.com>)
|
# If you want new properties translated then sent this over GMR (Mark Angell <mangell@gmr.com>)
|
||||||
|
manage2Sail=Manage2Sail
|
||||||
tracTracEvents=События Трак Трак
|
tracTracEvents=События Трак Трак
|
||||||
swissTimingEvents=События Swiss Timing
|
swissTimingEvents=События Swiss Timing
|
||||||
trackedBefore=Ранее Отслеженные
|
trackedBefore=Ранее Отслеженные
|
||||||
@@ -1076,7 +1077,7 @@ remoteProcedureCall=Remote Procedure Call
|
|||||||
serverReplies=Server replies
|
serverReplies=Server replies
|
||||||
errorCommunicatingWithServer=Error communicating with server
|
errorCommunicatingWithServer=Error communicating with server
|
||||||
userManagement=User Management
|
userManagement=User Management
|
||||||
structureImportUrls=Regatta structure import
|
regattaStructureImport=Regatta structure import
|
||||||
editSeries=Edit Series
|
editSeries=Edit Series
|
||||||
filteredBy=filtered by
|
filteredBy=filtered by
|
||||||
pleaseSelectAtLeastOneRegatta=Please select at least one regatta
|
pleaseSelectAtLeastOneRegatta=Please select at least one regatta
|
||||||
|
|||||||
+2
-1
@@ -1,3 +1,4 @@
|
|||||||
|
manage2Sail=Manage2Sail
|
||||||
enableRaceFilter=Enable filter
|
enableRaceFilter=Enable filter
|
||||||
finishLine=终点线
|
finishLine=终点线
|
||||||
raceLabel=比赛轮次
|
raceLabel=比赛轮次
|
||||||
@@ -460,7 +461,7 @@ createFlexibleLeaderboard=Create flexible leaderboard
|
|||||||
unknown=Unknown
|
unknown=Unknown
|
||||||
furtherSignalsAshore=Further signals ashore
|
furtherSignalsAshore=Further signals ashore
|
||||||
pleaseSelectAtLeastOneRegatta=Please select at least one regatta
|
pleaseSelectAtLeastOneRegatta=Please select at least one regatta
|
||||||
structureImportUrls=Regatta Structure Import
|
regattaStructureImport=Regatta Structure Import
|
||||||
raceAbandoned=放弃
|
raceAbandoned=放弃
|
||||||
sheetName=Sheet name
|
sheetName=Sheet name
|
||||||
rrs26Start=RRS26 start
|
rrs26Start=RRS26 start
|
||||||
|
|||||||
+2
-1
@@ -56,6 +56,7 @@ public class RaceContext {
|
|||||||
private final RaceLog raceLog;
|
private final RaceLog raceLog;
|
||||||
private final ReadonlyRaceState state;
|
private final ReadonlyRaceState state;
|
||||||
private final Event event;
|
private final Event event;
|
||||||
|
private final long TIME_BEFORE_START_TO_SHOW_RACES_AS_LIVE = 15 * 60 * 1000; // 15 min
|
||||||
private final long TIME_TO_SHOW_CANCELED_RACES_AS_LIVE = 5 * 60 * 1000; // 5 min
|
private final long TIME_TO_SHOW_CANCELED_RACES_AS_LIVE = 5 * 60 * 1000; // 5 min
|
||||||
|
|
||||||
public RaceContext(Event event, Leaderboard leaderboard, RaceColumn raceColumn, Fleet fleet, RaceLogResolver raceLogResolver) {
|
public RaceContext(Event event, Leaderboard leaderboard, RaceColumn raceColumn, Fleet fleet, RaceLogResolver raceLogResolver) {
|
||||||
@@ -308,7 +309,7 @@ public class RaceContext {
|
|||||||
result = trackedRace.isLive(now);
|
result = trackedRace.isLive(now);
|
||||||
} else {
|
} else {
|
||||||
// no data from tracking but maybe a manual setting of the start and finish time
|
// no data from tracking but maybe a manual setting of the start and finish time
|
||||||
TimePoint startOfLivePeriod = startTime.minus(TimingConstants.PRE_START_PHASE_DURATION_IN_MILLIS);
|
TimePoint startOfLivePeriod = startTime.minus(TIME_BEFORE_START_TO_SHOW_RACES_AS_LIVE);
|
||||||
TimePoint endOfLivePeriod = finishTime != null ? finishTime.plus(TimingConstants.IS_LIVE_GRACE_PERIOD_IN_MILLIS) : null;
|
TimePoint endOfLivePeriod = finishTime != null ? finishTime.plus(TimingConstants.IS_LIVE_GRACE_PERIOD_IN_MILLIS) : null;
|
||||||
if(now.after(startOfLivePeriod) && (endOfLivePeriod == null || now.before(endOfLivePeriod))) {
|
if(now.after(startOfLivePeriod) && (endOfLivePeriod == null || now.before(endOfLivePeriod))) {
|
||||||
result = true;
|
result = true;
|
||||||
|
|||||||
+7
-5
@@ -11,6 +11,7 @@ import com.sap.sailing.domain.base.Event;
|
|||||||
import com.sap.sailing.domain.leaderboard.Leaderboard;
|
import com.sap.sailing.domain.leaderboard.Leaderboard;
|
||||||
import com.sap.sailing.domain.leaderboard.LeaderboardGroup;
|
import com.sap.sailing.domain.leaderboard.LeaderboardGroup;
|
||||||
import com.sap.sailing.domain.leaderboard.RegattaLeaderboard;
|
import com.sap.sailing.domain.leaderboard.RegattaLeaderboard;
|
||||||
|
import com.sap.sailing.domain.leaderboard.SettableScoreCorrection;
|
||||||
import com.sap.sailing.news.EventNewsItem;
|
import com.sap.sailing.news.EventNewsItem;
|
||||||
import com.sap.sailing.news.EventNewsProvider;
|
import com.sap.sailing.news.EventNewsProvider;
|
||||||
import com.sap.sse.common.TimePoint;
|
import com.sap.sse.common.TimePoint;
|
||||||
@@ -28,11 +29,10 @@ public class LeaderboardUpdateEventNewsProvider implements EventNewsProvider {
|
|||||||
Iterable<LeaderboardGroup> leaderboardGroups = event.getLeaderboardGroups();
|
Iterable<LeaderboardGroup> leaderboardGroups = event.getLeaderboardGroups();
|
||||||
for(LeaderboardGroup leaderboardGroup: leaderboardGroups) {
|
for(LeaderboardGroup leaderboardGroup: leaderboardGroups) {
|
||||||
for(Leaderboard leaderboard: leaderboardGroup.getLeaderboards()) {
|
for(Leaderboard leaderboard: leaderboardGroup.getLeaderboards()) {
|
||||||
TimePoint timePointOfLatestModification = leaderboard.getTimePointOfLatestModification();
|
SettableScoreCorrection scoreCorrection = leaderboard.getScoreCorrection();
|
||||||
if(timePointOfLatestModification == null) {
|
if(scoreCorrection != null) {
|
||||||
continue;
|
TimePoint timePointOfLatestModification = scoreCorrection.getTimePointOfLastCorrectionsValidity();
|
||||||
}
|
if(timePointOfLatestModification != null) {
|
||||||
|
|
||||||
String displayName = leaderboard.getDisplayName() != null ?leaderboard.getDisplayName() :leaderboard.getName();
|
String displayName = leaderboard.getDisplayName() != null ?leaderboard.getDisplayName() :leaderboard.getName();
|
||||||
String boatClassName= null;
|
String boatClassName= null;
|
||||||
if(leaderboard instanceof RegattaLeaderboard) {
|
if(leaderboard instanceof RegattaLeaderboard) {
|
||||||
@@ -44,6 +44,8 @@ public class LeaderboardUpdateEventNewsProvider implements EventNewsProvider {
|
|||||||
result.add(new LeaderboardUpdateNewsItem(event.getId(), timePointOfLatestModification.asDate(), leaderboard.getName(), displayName, boatClassName));
|
result.add(new LeaderboardUpdateNewsItem(event.getId(), timePointOfLatestModification.asDate(), leaderboard.getName(), displayName, boatClassName));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Collections.sort(result);
|
Collections.sort(result);
|
||||||
|
|
||||||
|
|||||||
@@ -25,6 +25,7 @@ import com.sap.sailing.domain.common.impl.KnotSpeedWithBearingImpl;
|
|||||||
import com.sap.sailing.domain.common.tracking.GPSFixMoving;
|
import com.sap.sailing.domain.common.tracking.GPSFixMoving;
|
||||||
import com.sap.sailing.domain.polars.NotEnoughDataHasBeenAddedException;
|
import com.sap.sailing.domain.polars.NotEnoughDataHasBeenAddedException;
|
||||||
import com.sap.sailing.domain.polars.PolarDataService;
|
import com.sap.sailing.domain.polars.PolarDataService;
|
||||||
|
import com.sap.sailing.domain.polars.PolarsChangedListener;
|
||||||
import com.sap.sailing.domain.tracking.TrackedRace;
|
import com.sap.sailing.domain.tracking.TrackedRace;
|
||||||
import com.sap.sailing.polars.aggregation.PolarFixAggregator;
|
import com.sap.sailing.polars.aggregation.PolarFixAggregator;
|
||||||
import com.sap.sailing.polars.aggregation.SimplePolarFixRaceInterval;
|
import com.sap.sailing.polars.aggregation.SimplePolarFixRaceInterval;
|
||||||
@@ -206,4 +207,14 @@ public class PolarDataServiceImpl implements PolarDataService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void registerListener(BoatClass boatClass, PolarsChangedListener listener) {
|
||||||
|
polarDataMiner.registerListener(boatClass, listener);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void unregisterListener(BoatClass boatClass, PolarsChangedListener listener) {
|
||||||
|
polarDataMiner.unregisterListener(boatClass, listener);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
+14
@@ -4,6 +4,7 @@ import java.util.HashMap;
|
|||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
import java.util.logging.Logger;
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
import org.apache.commons.math.analysis.polynomials.PolynomialFunction;
|
import org.apache.commons.math.analysis.polynomials.PolynomialFunction;
|
||||||
@@ -14,6 +15,7 @@ import com.sap.sailing.domain.common.LegType;
|
|||||||
import com.sap.sailing.domain.common.Speed;
|
import com.sap.sailing.domain.common.Speed;
|
||||||
import com.sap.sailing.domain.common.Tack;
|
import com.sap.sailing.domain.common.Tack;
|
||||||
import com.sap.sailing.domain.polars.NotEnoughDataHasBeenAddedException;
|
import com.sap.sailing.domain.polars.NotEnoughDataHasBeenAddedException;
|
||||||
|
import com.sap.sailing.domain.polars.PolarsChangedListener;
|
||||||
import com.sap.sse.datamining.AdditionalResultDataBuilder;
|
import com.sap.sse.datamining.AdditionalResultDataBuilder;
|
||||||
import com.sap.sse.datamining.components.Processor;
|
import com.sap.sse.datamining.components.Processor;
|
||||||
import com.sap.sse.datamining.factories.GroupKeyFactory;
|
import com.sap.sse.datamining.factories.GroupKeyFactory;
|
||||||
@@ -26,6 +28,12 @@ public class CubicRegressionPerCourseProcessor implements Processor<GroupedDataE
|
|||||||
|
|
||||||
private final Map<GroupKey, AngleAndSpeedRegression> regressions = new HashMap<>();
|
private final Map<GroupKey, AngleAndSpeedRegression> regressions = new HashMap<>();
|
||||||
|
|
||||||
|
private ConcurrentHashMap<BoatClass, Set<PolarsChangedListener>> listeners;
|
||||||
|
|
||||||
|
public CubicRegressionPerCourseProcessor(ConcurrentHashMap<BoatClass, Set<PolarsChangedListener>> listeners) {
|
||||||
|
this.listeners = listeners;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean canProcessElements() {
|
public boolean canProcessElements() {
|
||||||
// TODO Auto-generated method stub
|
// TODO Auto-generated method stub
|
||||||
@@ -46,6 +54,12 @@ public class CubicRegressionPerCourseProcessor implements Processor<GroupedDataE
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
regression.addData(fix.getWind(), fix.getAbsoluteAngleToTheWind(), fix.getBoatSpeed());
|
regression.addData(fix.getWind(), fix.getAbsoluteAngleToTheWind(), fix.getBoatSpeed());
|
||||||
|
Set<PolarsChangedListener> listenersForBoatClass = listeners.get(fix.getBoatClass());
|
||||||
|
if (listenersForBoatClass != null) {
|
||||||
|
for (PolarsChangedListener listener : listenersForBoatClass) {
|
||||||
|
listener.polarsChanged();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -3,11 +3,13 @@ package com.sap.sailing.polars.mining;
|
|||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
|
import java.util.Collections;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Queue;
|
import java.util.Queue;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
import java.util.concurrent.ConcurrentLinkedQueue;
|
import java.util.concurrent.ConcurrentLinkedQueue;
|
||||||
import java.util.concurrent.LinkedBlockingQueue;
|
import java.util.concurrent.LinkedBlockingQueue;
|
||||||
import java.util.concurrent.RejectedExecutionHandler;
|
import java.util.concurrent.RejectedExecutionHandler;
|
||||||
@@ -40,6 +42,7 @@ import com.sap.sailing.domain.common.impl.PolarSheetsHistogramDataImpl;
|
|||||||
import com.sap.sailing.domain.common.impl.WindSpeedSteppingWithMaxDistance;
|
import com.sap.sailing.domain.common.impl.WindSpeedSteppingWithMaxDistance;
|
||||||
import com.sap.sailing.domain.common.tracking.GPSFixMoving;
|
import com.sap.sailing.domain.common.tracking.GPSFixMoving;
|
||||||
import com.sap.sailing.domain.polars.NotEnoughDataHasBeenAddedException;
|
import com.sap.sailing.domain.polars.NotEnoughDataHasBeenAddedException;
|
||||||
|
import com.sap.sailing.domain.polars.PolarsChangedListener;
|
||||||
import com.sap.sailing.domain.tracking.TrackedRace;
|
import com.sap.sailing.domain.tracking.TrackedRace;
|
||||||
import com.sap.sailing.polars.impl.CubicEquation;
|
import com.sap.sailing.polars.impl.CubicEquation;
|
||||||
import com.sap.sse.datamining.components.FilterCriterion;
|
import com.sap.sse.datamining.components.FilterCriterion;
|
||||||
@@ -65,6 +68,8 @@ public class PolarDataMiner {
|
|||||||
|
|
||||||
private static final Logger logger = Logger.getLogger(PolarDataMiner.class.getSimpleName());
|
private static final Logger logger = Logger.getLogger(PolarDataMiner.class.getSimpleName());
|
||||||
|
|
||||||
|
private final ConcurrentHashMap<BoatClass, Set<PolarsChangedListener>> listeners = new ConcurrentHashMap<>();
|
||||||
|
|
||||||
private ThreadPoolExecutor createExecutor() {
|
private ThreadPoolExecutor createExecutor() {
|
||||||
return new ThreadPoolExecutor(THREAD_POOL_SIZE, THREAD_POOL_SIZE, 60, TimeUnit.SECONDS,
|
return new ThreadPoolExecutor(THREAD_POOL_SIZE, THREAD_POOL_SIZE, 60, TimeUnit.SECONDS,
|
||||||
new LinkedBlockingQueue<Runnable>(EXECUTOR_QUEUE_SIZE), new RejectedExecutionHandler() {
|
new LinkedBlockingQueue<Runnable>(EXECUTOR_QUEUE_SIZE), new RejectedExecutionHandler() {
|
||||||
@@ -135,7 +140,7 @@ public class PolarDataMiner {
|
|||||||
GPSFixMovingWithPolarContext.class, executor, movingAverageGrouperResultReceivers, parameterizedDimensions);
|
GPSFixMovingWithPolarContext.class, executor, movingAverageGrouperResultReceivers, parameterizedDimensions);
|
||||||
|
|
||||||
|
|
||||||
cubicRegressionPerCourseProcessor = new CubicRegressionPerCourseProcessor();
|
cubicRegressionPerCourseProcessor = new CubicRegressionPerCourseProcessor(listeners);
|
||||||
Collection<Processor<GroupedDataEntry<GPSFixMovingWithPolarContext>, ?>> regressionPerCourseGrouperResultReceivers = new ArrayList<Processor<GroupedDataEntry<GPSFixMovingWithPolarContext>, ?>>();
|
Collection<Processor<GroupedDataEntry<GPSFixMovingWithPolarContext>, ?>> regressionPerCourseGrouperResultReceivers = new ArrayList<Processor<GroupedDataEntry<GPSFixMovingWithPolarContext>, ?>>();
|
||||||
regressionPerCourseGrouperResultReceivers.add(cubicRegressionPerCourseProcessor);
|
regressionPerCourseGrouperResultReceivers.add(cubicRegressionPerCourseProcessor);
|
||||||
|
|
||||||
@@ -147,7 +152,7 @@ public class PolarDataMiner {
|
|||||||
GPSFixMovingWithPolarContext.class, executor, regressionPerCourseGrouperResultReceivers, parameterizedDimensionsForCubicRegression);
|
GPSFixMovingWithPolarContext.class, executor, regressionPerCourseGrouperResultReceivers, parameterizedDimensionsForCubicRegression);
|
||||||
|
|
||||||
ClusterGroup<Bearing> angleClusterGroup = createAngleClusterGroup();
|
ClusterGroup<Bearing> angleClusterGroup = createAngleClusterGroup();
|
||||||
speedRegressionPerAngleClusterProcessor = new SpeedRegressionPerAngleClusterProcessor(angleClusterGroup);
|
speedRegressionPerAngleClusterProcessor = new SpeedRegressionPerAngleClusterProcessor(angleClusterGroup, listeners);
|
||||||
Collection<Processor<GroupedDataEntry<GPSFixMovingWithPolarContext>, ?>> regressionPerAngleClusterGrouperResultReceivers = new ArrayList<Processor<GroupedDataEntry<GPSFixMovingWithPolarContext>, ?>>();
|
Collection<Processor<GroupedDataEntry<GPSFixMovingWithPolarContext>, ?>> regressionPerAngleClusterGrouperResultReceivers = new ArrayList<Processor<GroupedDataEntry<GPSFixMovingWithPolarContext>, ?>>();
|
||||||
regressionPerAngleClusterGrouperResultReceivers.add(speedRegressionPerAngleClusterProcessor);
|
regressionPerAngleClusterGrouperResultReceivers.add(speedRegressionPerAngleClusterProcessor);
|
||||||
|
|
||||||
@@ -436,4 +441,21 @@ public class PolarDataMiner {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void registerListener(BoatClass boatClass, PolarsChangedListener listener) {
|
||||||
|
Set<PolarsChangedListener> listenersForBoatClass = listeners.get(boatClass);
|
||||||
|
if (listenersForBoatClass == null) {
|
||||||
|
Map<PolarsChangedListener, Boolean> mapForConcurrency = new ConcurrentHashMap<>();
|
||||||
|
listenersForBoatClass = Collections.newSetFromMap(mapForConcurrency);
|
||||||
|
listeners.put(boatClass, listenersForBoatClass);
|
||||||
|
}
|
||||||
|
listenersForBoatClass.add(listener);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void unregisterListener(BoatClass boatClass, PolarsChangedListener listener) {
|
||||||
|
Set<PolarsChangedListener> listenersForBoatClass = listeners.get(boatClass);
|
||||||
|
if (listenersForBoatClass != null) {
|
||||||
|
listenersForBoatClass.remove(listener);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
+13
-1
@@ -2,6 +2,8 @@ package com.sap.sailing.polars.mining;
|
|||||||
|
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
import java.util.logging.Logger;
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
import org.apache.commons.math.analysis.polynomials.PolynomialFunction;
|
import org.apache.commons.math.analysis.polynomials.PolynomialFunction;
|
||||||
@@ -14,6 +16,7 @@ import com.sap.sailing.domain.common.Speed;
|
|||||||
import com.sap.sailing.domain.common.impl.DegreeBearingImpl;
|
import com.sap.sailing.domain.common.impl.DegreeBearingImpl;
|
||||||
import com.sap.sailing.domain.common.impl.KnotSpeedImpl;
|
import com.sap.sailing.domain.common.impl.KnotSpeedImpl;
|
||||||
import com.sap.sailing.domain.polars.NotEnoughDataHasBeenAddedException;
|
import com.sap.sailing.domain.polars.NotEnoughDataHasBeenAddedException;
|
||||||
|
import com.sap.sailing.domain.polars.PolarsChangedListener;
|
||||||
import com.sap.sailing.polars.regression.IncrementalLeastSquares;
|
import com.sap.sailing.polars.regression.IncrementalLeastSquares;
|
||||||
import com.sap.sailing.polars.regression.impl.IncrementalAnyOrderLeastSquaresImpl;
|
import com.sap.sailing.polars.regression.impl.IncrementalAnyOrderLeastSquaresImpl;
|
||||||
import com.sap.sse.datamining.AdditionalResultDataBuilder;
|
import com.sap.sse.datamining.AdditionalResultDataBuilder;
|
||||||
@@ -34,8 +37,11 @@ public class SpeedRegressionPerAngleClusterProcessor implements Processor<Groupe
|
|||||||
|
|
||||||
private final ClusterGroup<Bearing> angleClusterGroup;
|
private final ClusterGroup<Bearing> angleClusterGroup;
|
||||||
|
|
||||||
public SpeedRegressionPerAngleClusterProcessor(ClusterGroup<Bearing> angleClusterGroup) {
|
private final ConcurrentHashMap<BoatClass, Set<PolarsChangedListener>> listeners;
|
||||||
|
|
||||||
|
public SpeedRegressionPerAngleClusterProcessor(ClusterGroup<Bearing> angleClusterGroup, ConcurrentHashMap<BoatClass, Set<PolarsChangedListener>> listeners) {
|
||||||
this.angleClusterGroup = angleClusterGroup;
|
this.angleClusterGroup = angleClusterGroup;
|
||||||
|
this.listeners = listeners;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -64,6 +70,12 @@ public class SpeedRegressionPerAngleClusterProcessor implements Processor<Groupe
|
|||||||
}
|
}
|
||||||
GPSFixMovingWithPolarContext fix = element.getDataEntry();
|
GPSFixMovingWithPolarContext fix = element.getDataEntry();
|
||||||
regression.addData(fix.getWind().getObject().getKnots(), fix.getBoatSpeed().getObject().getKnots());
|
regression.addData(fix.getWind().getObject().getKnots(), fix.getBoatSpeed().getObject().getKnots());
|
||||||
|
Set<PolarsChangedListener> listenersForBoatClass = listeners.get(fix.getBoatClass());
|
||||||
|
if (listenersForBoatClass != null) {
|
||||||
|
for (PolarsChangedListener listener : listenersForBoatClass) {
|
||||||
|
listener.polarsChanged();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -27,6 +27,6 @@
|
|||||||
<booleanAttribute key="tracing" value="false"/>
|
<booleanAttribute key="tracing" value="false"/>
|
||||||
<booleanAttribute key="useCustomFeatures" value="false"/>
|
<booleanAttribute key="useCustomFeatures" value="false"/>
|
||||||
<booleanAttribute key="useDefaultConfigArea" value="false"/>
|
<booleanAttribute key="useDefaultConfigArea" value="false"/>
|
||||||
<stringAttribute key="workspace_bundles" value="com.google.gwt.osgi@default:default,com.googlecode.java-diff-utils@default:default,com.googlecode.mgwt@default:default,com.sap.sailing.barbados.resultimport@default:default,com.sap.sailing.dashboards.gwt@5:true,com.sap.sailing.datamining.shared@default:default,com.sap.sailing.datamining@default:default,com.sap.sailing.declination@default:default,com.sap.sailing.domain.common@default:default,com.sap.sailing.domain.deckmanadapter@4:true,com.sap.sailing.domain.igtimiadapter.persistence@default:default,com.sap.sailing.domain.igtimiadapter@default:default,com.sap.sailing.domain.persistence@default:default,com.sap.sailing.domain.racelogtrackingadapter@3:default,com.sap.sailing.domain.shared.android@default:default,com.sap.sailing.domain.swisstimingadapter.persistence@default:default,com.sap.sailing.domain.swisstimingadapter@4:true,com.sap.sailing.domain.swisstimingreplayadapter@4:true,com.sap.sailing.domain.tractracadapter.persistence@default:default,com.sap.sailing.domain.tractracadapter@4:true,com.sap.sailing.domain@default:default,com.sap.sailing.ess40.resultimport@default:default,com.sap.sailing.expeditionconnector@default:default,com.sap.sailing.freg.resultimport@default:default,com.sap.sailing.geocoding@default:default,com.sap.sailing.gwt.ui@5:true,com.sap.sailing.kiworesultimport@default:default,com.sap.sailing.manage2sail.resultimport@default:default,com.sap.sailing.manage2sail@default:default,com.sap.sailing.news@default:default,com.sap.sailing.nmeaconnector@default:default,com.sap.sailing.polars@4:true,com.sap.sailing.resultimport@default:default,com.sap.sailing.sailwave.resultimport@default:default,com.sap.sailing.server.gateway.ess40@4:true,com.sap.sailing.server.gateway.serialization.shared.android@default:default,com.sap.sailing.server.gateway.serialization@default:default,com.sap.sailing.server.gateway@5:true,com.sap.sailing.server.trackfiles@default:default,com.sap.sailing.server@default:default,com.sap.sailing.simulator@default:default,com.sap.sailing.udpconnector@default:default,com.sap.sailing.velum.resultimport@default:default,com.sap.sailing.www.events@4:true,com.sap.sailing.www@4:true,com.sap.sailing.xrr.resultimport@default:default,com.sap.sailing.xrr.schema@default:default,com.sap.sailing.xrr.structureimport@default:default,com.sap.sse.common@default:default,com.sap.sse.datamining.shared@default:default,com.sap.sse.datamining@default:default,com.sap.sse.filestorage@default:default,com.sap.sse.gwt.adminconsole@default:default,com.sap.sse.gwt@default:default,com.sap.sse.mail@4:true,com.sap.sse.mongodb@default:default,com.sap.sse.operationaltransformation@default:default,com.sap.sse.replication@4:true,com.sap.sse.security.common@default:default,com.sap.sse.security.ui@6:true,com.sap.sse.security.userstore.mongodb@4:true,com.sap.sse.security@5:true,com.sap.sse.shared.android@default:default,com.sap.sse@default:default,com.tractrac.clientmodule@default:default,net.sf.marineapi@default:default,org.json.simple@default:default,org.moxieapps.gwt.highcharts@default:default"/>
|
<stringAttribute key="workspace_bundles" value="com.google.gwt.osgi@default:default,com.googlecode.java-diff-utils@default:default,com.googlecode.mgwt@default:default,com.sap.sailing.barbados.resultimport@default:default,com.sap.sailing.dashboards.gwt@5:true,com.sap.sailing.datamining.shared@default:default,com.sap.sailing.datamining@default:default,com.sap.sailing.declination@default:default,com.sap.sailing.domain.common@default:default,com.sap.sailing.domain.deckmanadapter@4:true,com.sap.sailing.domain.igtimiadapter.persistence@default:default,com.sap.sailing.domain.igtimiadapter@default:default,com.sap.sailing.domain.persistence@default:default,com.sap.sailing.domain.racelogtrackingadapter@3:default,com.sap.sailing.domain.shared.android@default:default,com.sap.sailing.domain.swisstimingadapter.persistence@default:default,com.sap.sailing.domain.swisstimingadapter@4:true,com.sap.sailing.domain.swisstimingreplayadapter@4:true,com.sap.sailing.domain.tractracadapter.persistence@default:default,com.sap.sailing.domain.tractracadapter@4:true,com.sap.sailing.domain@default:default,com.sap.sailing.ess40.resultimport@default:default,com.sap.sailing.expeditionconnector@default:default,com.sap.sailing.freg.resultimport@default:default,com.sap.sailing.geocoding@default:default,com.sap.sailing.gwt.ui@5:true,com.sap.sailing.kiworesultimport@default:default,com.sap.sailing.manage2sail.resultimport@default:default,com.sap.sailing.manage2sail@default:default,com.sap.sailing.news@default:default,com.sap.sailing.nmeaconnector@default:default,com.sap.sailing.polars@4:true,com.sap.sailing.resultimport@default:default,com.sap.sailing.sailwave.resultimport@default:default,com.sap.sailing.server.gateway.ess40@4:true,com.sap.sailing.server.gateway.serialization.shared.android@default:default,com.sap.sailing.server.gateway.serialization@default:default,com.sap.sailing.server.gateway@5:true,com.sap.sailing.server.trackfiles@default:default,com.sap.sailing.server@default:default,com.sap.sailing.simulator@default:default,com.sap.sailing.udpconnector@default:default,com.sap.sailing.velum.resultimport@default:default,com.sap.sailing.www.events@4:true,com.sap.sailing.www@4:true,com.sap.sailing.xrr.resultimport@default:default,com.sap.sailing.xrr.schema@default:default,com.sap.sailing.xrr.structureimport@default:default,com.sap.sse.common@default:default,com.sap.sse.datamining.shared@default:default,com.sap.sse.datamining@default:default,com.sap.sse.filestorage@default:default,com.sap.sse.gwt.adminconsole@default:default,com.sap.sse.gwt.theme@default:default,com.sap.sse.gwt@default:default,com.sap.sse.mail@4:true,com.sap.sse.mongodb@default:default,com.sap.sse.operationaltransformation@default:default,com.sap.sse.replication@4:true,com.sap.sse.security.common@default:default,com.sap.sse.security.ui@6:true,com.sap.sse.security.userstore.mongodb@4:true,com.sap.sse.security@5:true,com.sap.sse.shared.android@default:default,com.sap.sse@default:default,com.tractrac.clientmodule@default:default,net.sf.marineapi@default:default,org.json.simple@default:default,org.moxieapps.gwt.highcharts@default:default"/>
|
||||||
<stringAttribute key="yk-options" value=" additional-options2=onexit\=snapshot "/>
|
<stringAttribute key="yk-options" value=" additional-options2=onexit\=snapshot "/>
|
||||||
</launchConfiguration>
|
</launchConfiguration>
|
||||||
@@ -16,10 +16,10 @@
|
|||||||
<listEntry value="org.eclipse.debug.ui.launchGroup.run"/>
|
<listEntry value="org.eclipse.debug.ui.launchGroup.run"/>
|
||||||
</listAttribute>
|
</listAttribute>
|
||||||
<booleanAttribute key="org.eclipse.jdt.launching.ATTR_USE_START_ON_FIRST_THREAD" value="true"/>
|
<booleanAttribute key="org.eclipse.jdt.launching.ATTR_USE_START_ON_FIRST_THREAD" value="true"/>
|
||||||
<stringAttribute key="org.eclipse.jdt.launching.JRE_CONTAINER" value="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/jre1.8.0_20"/>
|
<stringAttribute key="org.eclipse.jdt.launching.JRE_CONTAINER" value="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/sapjvm_8"/>
|
||||||
<stringAttribute key="org.eclipse.jdt.launching.PROGRAM_ARGUMENTS" value="-os ${target.os} -ws ${target.ws} -arch ${target.arch} -nl ${target.nl} -consoleLog -console -clean"/>
|
<stringAttribute key="org.eclipse.jdt.launching.PROGRAM_ARGUMENTS" value="-os ${target.os} -ws ${target.ws} -arch ${target.arch} -nl ${target.nl} -consoleLog -console -clean"/>
|
||||||
<stringAttribute key="org.eclipse.jdt.launching.SOURCE_PATH_PROVIDER" value="org.eclipse.pde.ui.workbenchClasspathProvider"/>
|
<stringAttribute key="org.eclipse.jdt.launching.SOURCE_PATH_PROVIDER" value="org.eclipse.pde.ui.workbenchClasspathProvider"/>
|
||||||
<stringAttribute key="org.eclipse.jdt.launching.VM_ARGUMENTS" value="-Xdebug -Xrunjdwp:transport=dt_socket,address=8000,server=y -ea -Declipse.ignoreApp=true -Dosgi.noShutdown=true -Dfile.encoding=cp1252 -Dexpedition.udp.port=2010 -Xmx6000m -XX:+UseG1GC -Djetty.home=${project_loc:com.sap.sailing.server}/../target/configuration/jetty -Djava.util.logging.config.file=${project_loc:com.sap.sailing.server}/../target/configuration/logging_debug.properties -Dkiwo.results=${project_loc:com.sap.sailing.kiworesultimport.test}/resources -Dpersistentcompetitors.clear=false -XX:+UseMembar -Digtimi.client.id=7fcdd217e0aa16090edb4ad55b09ec43b2021090e209541fc9b7003c2a2b70c6 -Digtimi.client.secret=aa569cf4909bdc7b0e04b11873f3c4ea20687421e010fcc25b771cca9e6f3f9a -Digtimi.client.redirecturi=http://127.0.0.1:8888/igtimi/oauth/v1/authorizationcallback -DspatialWind=true -Dmongo.host=172.31.25.253 -Dmongo.port=10200 -Dmongo.dbName=LOAD_TEST"/>
|
<stringAttribute key="org.eclipse.jdt.launching.VM_ARGUMENTS" value="-Xdebug -Xrunjdwp:transport=dt_socket,address=8000,server=y -ea -Declipse.ignoreApp=true -Dosgi.noShutdown=true -Dfile.encoding=cp1252 -Dexpedition.udp.port=2010 -Xmx6000m -XX:+UseG1GC -Djetty.home=${project_loc:com.sap.sailing.server}/../target/configuration/jetty -Djava.util.logging.config.file=${project_loc:com.sap.sailing.server}/../target/configuration/logging_debug.properties -Dkiwo.results=${project_loc:com.sap.sailing.kiworesultimport.test}/resources -Dpersistentcompetitors.clear=false -XX:+UseMembar -Digtimi.client.id=7fcdd217e0aa16090edb4ad55b09ec43b2021090e209541fc9b7003c2a2b70c6 -Digtimi.client.secret=aa569cf4909bdc7b0e04b11873f3c4ea20687421e010fcc25b771cca9e6f3f9a -Digtimi.client.redirecturi=http://127.0.0.1:8888/igtimi/oauth/v1/authorizationcallback"/>
|
||||||
<stringAttribute key="org.eclipse.jdt.launching.WORKING_DIRECTORY" value="${workspace_loc}"/>
|
<stringAttribute key="org.eclipse.jdt.launching.WORKING_DIRECTORY" value="${workspace_loc}"/>
|
||||||
<stringAttribute key="pde.version" value="3.3"/>
|
<stringAttribute key="pde.version" value="3.3"/>
|
||||||
<booleanAttribute key="show_selected_only" value="false"/>
|
<booleanAttribute key="show_selected_only" value="false"/>
|
||||||
|
|||||||
+25
-17
@@ -88,6 +88,7 @@ import com.sap.sailing.domain.base.impl.EventImpl;
|
|||||||
import com.sap.sailing.domain.base.impl.RegattaImpl;
|
import com.sap.sailing.domain.base.impl.RegattaImpl;
|
||||||
import com.sap.sailing.domain.base.impl.RemoteSailingServerReferenceImpl;
|
import com.sap.sailing.domain.base.impl.RemoteSailingServerReferenceImpl;
|
||||||
import com.sap.sailing.domain.common.DataImportProgress;
|
import com.sap.sailing.domain.common.DataImportProgress;
|
||||||
|
import com.sap.sailing.domain.common.Distance;
|
||||||
import com.sap.sailing.domain.common.LeaderboardNameConstants;
|
import com.sap.sailing.domain.common.LeaderboardNameConstants;
|
||||||
import com.sap.sailing.domain.common.Position;
|
import com.sap.sailing.domain.common.Position;
|
||||||
import com.sap.sailing.domain.common.RegattaAndRaceIdentifier;
|
import com.sap.sailing.domain.common.RegattaAndRaceIdentifier;
|
||||||
@@ -2374,13 +2375,6 @@ public class RacingEventServiceImpl implements RacingEventService, ClearStateTes
|
|||||||
public void serializeForInitialReplicationInternal(ObjectOutputStream oos) throws IOException {
|
public void serializeForInitialReplicationInternal(ObjectOutputStream oos) throws IOException {
|
||||||
StringBuffer logoutput = new StringBuffer();
|
StringBuffer logoutput = new StringBuffer();
|
||||||
|
|
||||||
logger.info("Serializing events...");
|
|
||||||
oos.writeObject(eventsById);
|
|
||||||
logoutput.append("\nSerialized " + eventsById.size() + " events\n");
|
|
||||||
for (Event event : eventsById.values()) {
|
|
||||||
logoutput.append(String.format("%3s\n", event.toString()));
|
|
||||||
}
|
|
||||||
|
|
||||||
logger.info("Serializing regattas...");
|
logger.info("Serializing regattas...");
|
||||||
oos.writeObject(regattasByName);
|
oos.writeObject(regattasByName);
|
||||||
logoutput.append("Serialized " + regattasByName.size() + " regattas\n");
|
logoutput.append("Serialized " + regattasByName.size() + " regattas\n");
|
||||||
@@ -2388,6 +2382,13 @@ public class RacingEventServiceImpl implements RacingEventService, ClearStateTes
|
|||||||
logoutput.append(String.format("%3s\n", regatta.toString()));
|
logoutput.append(String.format("%3s\n", regatta.toString()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
logger.info("Serializing events...");
|
||||||
|
oos.writeObject(eventsById);
|
||||||
|
logoutput.append("\nSerialized " + eventsById.size() + " events\n");
|
||||||
|
for (Event event : eventsById.values()) {
|
||||||
|
logoutput.append(String.format("%3s\n", event.toString()));
|
||||||
|
}
|
||||||
|
|
||||||
logger.info("Serializing regattas observed...");
|
logger.info("Serializing regattas observed...");
|
||||||
oos.writeObject(regattasObservedForDefaultLeaderboard);
|
oos.writeObject(regattasObservedForDefaultLeaderboard);
|
||||||
logger.info("Serializing regatta tracking cache...");
|
logger.info("Serializing regatta tracking cache...");
|
||||||
@@ -2441,13 +2442,6 @@ public class RacingEventServiceImpl implements RacingEventService, ClearStateTes
|
|||||||
// de-serialization; this will cause all classes to be visible that this bundle
|
// de-serialization; this will cause all classes to be visible that this bundle
|
||||||
// (com.sap.sailing.server) can see
|
// (com.sap.sailing.server) can see
|
||||||
StringBuffer logoutput = new StringBuffer();
|
StringBuffer logoutput = new StringBuffer();
|
||||||
logger.info("Reading all events...");
|
|
||||||
eventsById.putAll((Map<Serializable, Event>) ois.readObject());
|
|
||||||
logoutput.append("\nReceived " + eventsById.size() + " NEW events\n");
|
|
||||||
for (Event event : eventsById.values()) {
|
|
||||||
logoutput.append(String.format("%3s\n", event.toString()));
|
|
||||||
}
|
|
||||||
|
|
||||||
logger.info("Reading all regattas...");
|
logger.info("Reading all regattas...");
|
||||||
regattasByName.putAll((Map<String, Regatta>) ois.readObject());
|
regattasByName.putAll((Map<String, Regatta>) ois.readObject());
|
||||||
logoutput.append("Received " + regattasByName.size() + " NEW regattas\n");
|
logoutput.append("Received " + regattasByName.size() + " NEW regattas\n");
|
||||||
@@ -2455,6 +2449,13 @@ public class RacingEventServiceImpl implements RacingEventService, ClearStateTes
|
|||||||
logoutput.append(String.format("%3s\n", regatta.toString()));
|
logoutput.append(String.format("%3s\n", regatta.toString()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
logger.info("Reading all events...");
|
||||||
|
eventsById.putAll((Map<Serializable, Event>) ois.readObject());
|
||||||
|
logoutput.append("\nReceived " + eventsById.size() + " NEW events\n");
|
||||||
|
for (Event event : eventsById.values()) {
|
||||||
|
logoutput.append(String.format("%3s\n", event.toString()));
|
||||||
|
}
|
||||||
|
|
||||||
// it is important that the leaderboards and tracked regattas are cleared before auto-linking to
|
// it is important that the leaderboards and tracked regattas are cleared before auto-linking to
|
||||||
// old leaderboards takes place which then don't match the new ones
|
// old leaderboards takes place which then don't match the new ones
|
||||||
logger.info("Reading all dynamic tracked regattas...");
|
logger.info("Reading all dynamic tracked regattas...");
|
||||||
@@ -2504,6 +2505,9 @@ public class RacingEventServiceImpl implements RacingEventService, ClearStateTes
|
|||||||
logger.info("Reading competitors...");
|
logger.info("Reading competitors...");
|
||||||
for (Competitor competitor : ((CompetitorStore) ois.readObject()).getCompetitors()) {
|
for (Competitor competitor : ((CompetitorStore) ois.readObject()).getCompetitors()) {
|
||||||
DynamicCompetitor dynamicCompetitor = (DynamicCompetitor) competitor;
|
DynamicCompetitor dynamicCompetitor = (DynamicCompetitor) competitor;
|
||||||
|
// the following should actually be redundant because during de-serialization the Competitor objects,
|
||||||
|
// whose classes implement IsManagedByCache, should already have been got/created from/in the
|
||||||
|
// competitor store
|
||||||
competitorStore.getOrCreateCompetitor(dynamicCompetitor.getId(), dynamicCompetitor.getName(),
|
competitorStore.getOrCreateCompetitor(dynamicCompetitor.getId(), dynamicCompetitor.getName(),
|
||||||
dynamicCompetitor.getColor(), dynamicCompetitor.getEmail(), dynamicCompetitor.getFlagImage(),
|
dynamicCompetitor.getColor(), dynamicCompetitor.getEmail(), dynamicCompetitor.getFlagImage(),
|
||||||
dynamicCompetitor.getTeam(), dynamicCompetitor.getBoat(), dynamicCompetitor.getTimeOnTimeFactor(),
|
dynamicCompetitor.getTeam(), dynamicCompetitor.getBoat(), dynamicCompetitor.getTimeOnTimeFactor(),
|
||||||
@@ -3218,9 +3222,13 @@ public class RacingEventServiceImpl implements RacingEventService, ClearStateTes
|
|||||||
public Iterable<Competitor> getCompetitorInOrderOfWindwardDistanceTraveledFarthestFirst(TrackedRace trackedRace, TimePoint timePoint) {
|
public Iterable<Competitor> getCompetitorInOrderOfWindwardDistanceTraveledFarthestFirst(TrackedRace trackedRace, TimePoint timePoint) {
|
||||||
final RankingInfo rankingInfo = trackedRace.getRankingMetric().getRankingInfo(timePoint);
|
final RankingInfo rankingInfo = trackedRace.getRankingMetric().getRankingInfo(timePoint);
|
||||||
final List<Competitor> result = new ArrayList<>();
|
final List<Competitor> result = new ArrayList<>();
|
||||||
Util.addAll(trackedRace.getRace().getCompetitors(), result);
|
final Map<Competitor, Distance> windwardDistanceSailedPerCompetitor = new HashMap<>();
|
||||||
result.sort((c1, c2) -> rankingInfo.getCompetitorRankingInfo().apply(c2).getWindwardDistanceSailed().compareTo(
|
for (final Competitor competitor : trackedRace.getRace().getCompetitors()) {
|
||||||
rankingInfo.getCompetitorRankingInfo().apply(c1).getWindwardDistanceSailed()));
|
result.add(competitor);
|
||||||
|
windwardDistanceSailedPerCompetitor.put(competitor, rankingInfo.getCompetitorRankingInfo().apply(competitor).getWindwardDistanceSailed());
|
||||||
|
}
|
||||||
|
result.sort((c1, c2) -> windwardDistanceSailedPerCompetitor.get(c2).compareTo(
|
||||||
|
windwardDistanceSailedPerCompetitor.get(c1)));
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+4
@@ -379,11 +379,15 @@ public class SimulationServiceImpl implements SimulationService {
|
|||||||
|
|
||||||
// determine legtype upwind/downwind/reaching
|
// determine legtype upwind/downwind/reaching
|
||||||
LegType legType = null;
|
LegType legType = null;
|
||||||
|
if (startTimePoint != null) {
|
||||||
try {
|
try {
|
||||||
legType = trackedRace.getTrackedLeg(leg).getLegType(startTimePoint);
|
legType = trackedRace.getTrackedLeg(leg).getLegType(startTimePoint);
|
||||||
} catch (NoWindException e) {
|
} catch (NoWindException e) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
// get windfield
|
// get windfield
|
||||||
WindFieldGenerator windField = new WindFieldTrackedRaceImpl(trackedRace);
|
WindFieldGenerator windField = new WindFieldTrackedRaceImpl(trackedRace);
|
||||||
|
|||||||
+3
-3
@@ -816,15 +816,15 @@ public class PolarDiagramBase implements PolarDiagram, Serializable {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int compare(Bearing o1, Bearing o2) {
|
public int compare(Bearing o1, Bearing o2) {
|
||||||
Double d1 = o1.getDegrees();
|
double d1 = o1.getDegrees();
|
||||||
if (d1 < 0) {
|
if (d1 < 0) {
|
||||||
d1 = 360 + d1;
|
d1 = 360 + d1;
|
||||||
}
|
}
|
||||||
Double d2 = o2.getDegrees();
|
double d2 = o2.getDegrees();
|
||||||
if (d2 < 0) {
|
if (d2 < 0) {
|
||||||
d2 = 360 + d2;
|
d2 = 360 + d2;
|
||||||
}
|
}
|
||||||
return d1.compareTo(d2);
|
return d1 < d2 ? -1 : d1 == d2 ? 0 : 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -0,0 +1,8 @@
|
|||||||
|
package com.sap.sse.util;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
import java.util.function.Function;
|
||||||
|
|
||||||
|
public interface SerializableFunction<T, R> extends Function<T, R>, Serializable {
|
||||||
|
|
||||||
|
}
|
||||||
+2
-2
@@ -286,7 +286,7 @@ public class MessageSendingService extends Service implements MessageSendingList
|
|||||||
int resendMillis = PrefUtils.getInt(this, R.string.preference_messageResendIntervalMillis_key,
|
int resendMillis = PrefUtils.getInt(this, R.string.preference_messageResendIntervalMillis_key,
|
||||||
R.integer.preference_messageResendIntervalMillis_default);
|
R.integer.preference_messageResendIntervalMillis_default);
|
||||||
if (!success) {
|
if (!success) {
|
||||||
ExLog.i(this, "MS", "success");
|
ExLog.i(this, "MS", "!success");
|
||||||
reportApiConnectivity(APIConnectivity.transmissionError);
|
reportApiConnectivity(APIConnectivity.transmissionError);
|
||||||
ExLog.w(this, TAG, "Error while posting intent to server. Will persist intent...");
|
ExLog.w(this, TAG, "Error while posting intent to server. Will persist intent...");
|
||||||
try {
|
try {
|
||||||
@@ -302,7 +302,7 @@ public class MessageSendingService extends Service implements MessageSendingList
|
|||||||
reportUnsentGPSFixesCount();
|
reportUnsentGPSFixesCount();
|
||||||
serviceLogger.onMessageSentFailed();
|
serviceLogger.onMessageSentFailed();
|
||||||
} else {
|
} else {
|
||||||
ExLog.i(this, "MS", "!success");
|
ExLog.i(this, "MS", "success");
|
||||||
reportApiConnectivity(APIConnectivity.transmissionSuccess);
|
reportApiConnectivity(APIConnectivity.transmissionSuccess);
|
||||||
ExLog.i(this, TAG, "Message successfully sent.");
|
ExLog.i(this, TAG, "Message successfully sent.");
|
||||||
if (persistenceManager.areIntentsDelayed()) {
|
if (persistenceManager.areIntentsDelayed()) {
|
||||||
|
|||||||
+18
-4
@@ -1,5 +1,7 @@
|
|||||||
package com.sap.sailing.android.buoy.positioning.app.ui.fragments;
|
package com.sap.sailing.android.buoy.positioning.app.ui.fragments;
|
||||||
|
|
||||||
|
import java.text.DecimalFormat;
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.location.Location;
|
import android.location.Location;
|
||||||
import android.location.LocationListener;
|
import android.location.LocationListener;
|
||||||
@@ -23,14 +25,15 @@ import com.sap.sailing.android.buoy.positioning.app.util.PingHelper;
|
|||||||
import com.sap.sailing.android.buoy.positioning.app.valueobjects.MarkInfo;
|
import com.sap.sailing.android.buoy.positioning.app.valueobjects.MarkInfo;
|
||||||
import com.sap.sailing.android.buoy.positioning.app.valueobjects.MarkPingInfo;
|
import com.sap.sailing.android.buoy.positioning.app.valueobjects.MarkPingInfo;
|
||||||
import com.sap.sailing.android.shared.data.LeaderboardInfo;
|
import com.sap.sailing.android.shared.data.LeaderboardInfo;
|
||||||
|
import com.sap.sailing.android.shared.logging.ExLog;
|
||||||
import com.sap.sailing.android.shared.ui.customviews.OpenSansButton;
|
import com.sap.sailing.android.shared.ui.customviews.OpenSansButton;
|
||||||
import com.sap.sailing.android.shared.ui.customviews.OpenSansTextView;
|
import com.sap.sailing.android.shared.ui.customviews.OpenSansTextView;
|
||||||
import com.sap.sailing.android.shared.ui.customviews.SignalQualityIndicatorView;
|
import com.sap.sailing.android.shared.ui.customviews.SignalQualityIndicatorView;
|
||||||
import com.sap.sailing.android.ui.fragments.BaseFragment;
|
import com.sap.sailing.android.ui.fragments.BaseFragment;
|
||||||
|
|
||||||
import java.text.DecimalFormat;
|
|
||||||
|
|
||||||
public class BuoyFragment extends BaseFragment implements LocationListener {
|
public class BuoyFragment extends BaseFragment implements LocationListener {
|
||||||
|
private static final int GPS_MIN_DISTANCE = 1;
|
||||||
|
private static final int GPS_MIN_TIME = 1000;
|
||||||
private OpenSansTextView markHeaderTextView;
|
private OpenSansTextView markHeaderTextView;
|
||||||
private OpenSansTextView latitudeTextView;
|
private OpenSansTextView latitudeTextView;
|
||||||
private OpenSansTextView longitudeTextView;
|
private OpenSansTextView longitudeTextView;
|
||||||
@@ -80,7 +83,7 @@ public class BuoyFragment extends BaseFragment implements LocationListener {
|
|||||||
signalQualityIndicatorView.setSignalQuality(GPSQuality.noSignal.toInt());
|
signalQualityIndicatorView.setSignalQuality(GPSQuality.noSignal.toInt());
|
||||||
if (mark != null) {
|
if (mark != null) {
|
||||||
markHeaderTextView.setText(mark.getName());
|
markHeaderTextView.setText(mark.getName());
|
||||||
setUpTextUI(null);
|
setUpTextUI(lastKnownLocation);
|
||||||
GoogleMap map = mapFragment.getMap();
|
GoogleMap map = mapFragment.getMap();
|
||||||
configureMap(map);
|
configureMap(map);
|
||||||
updateMap();
|
updateMap();
|
||||||
@@ -124,6 +127,11 @@ public class BuoyFragment extends BaseFragment implements LocationListener {
|
|||||||
accuracyText += " (" + String.format(accuracyString, accuracyFormatter.format(markPing.getAccuracy()))
|
accuracyText += " (" + String.format(accuracyString, accuracyFormatter.format(markPing.getAccuracy()))
|
||||||
+ ")";
|
+ ")";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ExLog.w(getActivity(), getTag(), "Setting latitude to: "+latitudeText);
|
||||||
|
ExLog.w(getActivity(), getTag(), "Setting longitude to: "+longitudeText);
|
||||||
|
ExLog.w(getActivity(), getTag(), "Setting accuracy to: "+accuracyText);
|
||||||
|
|
||||||
latitudeTextView.setText(latitudeText);
|
latitudeTextView.setText(latitudeText);
|
||||||
longitudeTextView.setText(longitudeText);
|
longitudeTextView.setText(longitudeText);
|
||||||
accuracyTextView.setText(accuracyText);
|
accuracyTextView.setText(accuracyText);
|
||||||
@@ -179,7 +187,13 @@ public class BuoyFragment extends BaseFragment implements LocationListener {
|
|||||||
private void initLocationProvider() {
|
private void initLocationProvider() {
|
||||||
locationManager = (LocationManager) getActivity().getSystemService(Context.LOCATION_SERVICE);
|
locationManager = (LocationManager) getActivity().getSystemService(Context.LOCATION_SERVICE);
|
||||||
locationManager.removeUpdates(this);
|
locationManager.removeUpdates(this);
|
||||||
locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 10000, 10, this);
|
locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, GPS_MIN_TIME, GPS_MIN_DISTANCE, this);
|
||||||
|
|
||||||
|
Location initialLocation = locationManager.getLastKnownLocation(LocationManager.GPS_PROVIDER);
|
||||||
|
|
||||||
|
if (initialLocation != null) {
|
||||||
|
onLocationChanged(initialLocation);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void updateMap() {
|
public void updateMap() {
|
||||||
|
|||||||
@@ -3,22 +3,27 @@
|
|||||||
## Server Landscape
|
## Server Landscape
|
||||||
|
|
||||||
We run four servers for the event:
|
We run four servers for the event:
|
||||||
- on EC2: **Master 1**, **Master 2**, **Replica 1** and **Replica 2** with an **ELB** in front,
|
- on EC2: **Master 1**, **Master 2**, **Master 3**, **Replica 1** and **Replica 2** with an **ELB** in front,
|
||||||
- ELB canonical name is KW2015-553831863.eu-west-1.elb.amazonaws.com
|
- ELB canonical name is KW2015-553831863.eu-west-1.elb.amazonaws.com
|
||||||
- locally: **Cube-Server**
|
- locally: **Cube-Server**
|
||||||
|
|
||||||
for fast and available switching. The DB they use is called `KW2015`, and so is the replication channel. The git branch we use to merge the features we want to deploy to the event servers is called `kielerwoche2015` and the git tag used to build a release for it is called `kielerwoche2015-release`. See http://hudson.sapsailing.com/job/SAPSailingAnalytics-kielerwoche2015/ and http://hudson.sapsailing.com/job/SAPSailingAnalytics-kielerwoche2015-release/, respectively, for their Hudson jobs.
|
for fast and available switching. The DB they use is called `KW2015`, and so is the replication channel. The git branch we use to merge the features we want to deploy to the event servers is called `kielerwoche2015` and the git tag used to build a release for it is called `kielerwoche2015-release`. See http://hudson.sapsailing.com/job/SAPSailingAnalytics-kielerwoche2015/ and http://hudson.sapsailing.com/job/SAPSailingAnalytics-kielerwoche2015-release/, respectively, for their Hudson jobs.
|
||||||
|
|
||||||
### Master 1 Server
|
### Master 1 Server (32GB)
|
||||||
- Admin Console at http://ec2-54-154-151-10.eu-west-1.compute.amazonaws.com:8888/gwt/AdminConsole.html
|
- Admin Console at http://ec2-54-154-151-10.eu-west-1.compute.amazonaws.com:8888/gwt/AdminConsole.html
|
||||||
- External IP: 54.154.151.10
|
- External IP: 54.154.151.10
|
||||||
- Internal IP: 172.31.24.187
|
- Internal IP: 172.31.24.187
|
||||||
|
|
||||||
### Master 2 Server
|
### Master 2 Server (32GB)
|
||||||
- Admin Console at http://ec2-54-76-169-213.eu-west-1.compute.amazonaws.com:8888/gwt/AdminConsole.html
|
- Admin Console at http://ec2-54-76-169-213.eu-west-1.compute.amazonaws.com:8888/gwt/AdminConsole.html
|
||||||
- External IP: 54.76.169.213
|
- External IP: 54.76.169.213
|
||||||
- Internal IP: 172.31.30.73
|
- Internal IP: 172.31.30.73
|
||||||
|
|
||||||
|
### Master 3 Server (64GB)
|
||||||
|
- Admin Console at http://ec2-54-171-148-10.eu-west-1.compute.amazonaws.com:8888/gwt/AdminConsole.html
|
||||||
|
- External IP: 54.171.148.10
|
||||||
|
- Internal IP: 172.31.26.119
|
||||||
|
|
||||||
### "Current" Master
|
### "Current" Master
|
||||||
Whichever master is current, we map the main Apache URL http://kielerwoche2015-master.sapsailing.com to it. This is also the URL to use for Tablet and Smartphone configurations.
|
Whichever master is current, we map the main Apache URL http://kielerwoche2015-master.sapsailing.com to it. This is also the URL to use for Tablet and Smartphone configurations.
|
||||||
|
|
||||||
|
|||||||
Reference in new issue
Block a user