merged with master

This commit is contained in:
Kai Boernert committed 2017-02-13 12:05:50 +01:00
commit 45483c8a5b
62 files changed
+1366 -486

No files matched your search

@@ -1,5 +1,6 @@
package com.sap.sailing.datamining.shared;
import com.sap.sailing.domain.common.Bearing;
import com.sap.sailing.domain.common.Distance;
import com.sap.sailing.domain.common.LegType;
import com.sap.sailing.domain.common.ManeuverType;
@@ -16,6 +17,7 @@ public final class SailingDataMiningSerializationDummy implements SerializationD
private LegType legType;
private Distance distance;
private Bearing bearing;
private CentralAngleDistance centralAngleDistance;
private MeterDistance meterDistance;
private NauticalMileDistance nauticalMileDistance;
@@ -23,6 +23,7 @@ LegSailingDomainRetrieverChain=Legs
GPSFixSailingDomainRetrieverChain=GPS Fixes
BravoFixSailingDomainRetrieverChain=Bravo Fixes
BravoFixTrackSailingDomainRetrieverChain=Bravo Tracks
FoilingSegmentsSailingDomainRetrieverChain=Foiled Segments
WindFixSailingDomainRetrieverChain=Wind Fixes
MarkPassingSailingDomainRetrieverChain=Mark Passings
RaceResultSailingDomainRetrieverChain=Race Results
@@ -96,7 +97,7 @@ WindSourceName=Wind Source Name
windFrom=True Wind Direction (TWD)
windSpeedKnots=True Wind Speed (kts)
speedInKnots=Speed (kts)
bearing=Course over Ground (°T)
bearing=Direction (°T)
WindTrack=Wind Track
timeSpentFoiling=Time spent foiling
yaw=Yaw
@@ -105,4 +106,20 @@ roll=Heel
rideHeight=Ride Height
rideHeightPort=Ride Height Port Hull
rideHeightStarboard=Ride Height Starboard Hull
IsFoiling=Is Foiling
IsFoiling=Is Foiling
FoilingDuration=Foiling Duration
FoilingDistance=Distance Foiled
TakeoffSpeedInKnotsInKnots=Takeoff speed in knots
LandingSpeedInKnots=Landing speed in knots
AbsoluteTrueWindAngleAtTakeoff=Absolute true wind angle (TWA) at takeoff
AbsoluteTrueWindAngleAtLanding=Absolute true wind angle (TWA) at landing
WindStrengthInBeaufortAtTakeoff=Wind strength in beaufort at takeoff
WindStrengthInBeaufortAtLanding=Wind strength in beaufort at landing
WindAtTakeoff=Wind at takeoff
WindAtLanding=Wind at landing
StartsOnLegType=Type of leg at takeoff
EndsOnLegType=Type of leg at landing
FoilingSegments=Foiled Segments
AverageAbsoluteTrueWindAngle=Average absolute true wind angle
AbsoluteTrueWindAngle=Absolute true wind angle (TWA)
Wind=Wind
@@ -21,6 +21,7 @@ LegSailingDomainRetrieverChain=Schenkel
GPSFixSailingDomainRetrieverChain=GPS-Fixes
BravoFixSailingDomainRetrieverChain=Bravo-Fixes
BravoFixTrackSailingDomainRetrieverChain=Bravo Messreihen
FoilingSegmentsSailingDomainRetrieverChain=Gefoilte Abschnitte
WindFixSailingDomainRetrieverChain=Windmessungen
MarkPassingSailingDomainRetrieverChain=Tonnenrundungen
RaceResultSailingDomainRetrieverChain=Rennergebnisse
@@ -96,7 +97,7 @@ WindSourceName=Name der Windmessreihe
windFrom=Wind aus Richtung (TWD)
windSpeedKnots=Wahre Windgeschwindigkeit (kn)
speedInKnots=Fahrt (kn)
bearing=Kurs über Grund (°)
bearing=Richtung (°)
WindTrack=Windmessreihe
timeSpentFoiling=Zeit auf Foils
yaw=Gierung
@@ -105,4 +106,20 @@ roll=Kr
rideHeight=Foiling-Höhe
rideHeightPort=Foiling-Höhe Backbord-Rumpf
rideHeightStarboard=Foiling-Höhe Steuerbord-Rumpf
IsFoiling=Foilt
IsFoiling=Foilt
FoilingDuration=Foilingdauer
FoilingDistance=Gefoilte Distanz
TakeoffSpeedInKnotsInKnots=Abhebegeschwindigkeit in Knoten
LandingSpeedInKnots=Landegeschwindigkeit in Knoten
AbsoluteTrueWindAngleAtTakeoff=Absoluter Winkel zum wahren Wind (TWA) beim Abheben
AbsoluteTrueWindAngleAtLanding=Absoluter Winkel zum wahren Wind (TWA) beim Landen
WindStrengthInBeaufortAtTakeoff=Windstärke beim Abheben in Beaufort
WindStrengthInBeaufortAtLanding=Windstärke beim Landen in Beaufort
WindAtTakeoff=Wind beim Abheben
WindAtLanding=Wind beim Landen
StartsOnLegType=Bahnschnenkeltyp beim Abheben
EndsOnLegType=Bahnschenkeltyp beim Landen
FoilingSegments=Gefoilte Abschnitte
AverageAbsoluteTrueWindAngle=Durchschnittlicher absoluter Winkel zum wahren Wind (TWA)
AbsoluteTrueWindAngle=Absoluter Winkel zum wahren Wind (TWA)
Wind=Wind
@@ -9,6 +9,7 @@ import org.osgi.framework.BundleContext;
import com.sap.sailing.datamining.data.HasBravoFixContext;
import com.sap.sailing.datamining.data.HasBravoFixTrackContext;
import com.sap.sailing.datamining.data.HasFoilingSegmentContext;
import com.sap.sailing.datamining.data.HasGPSFixContext;
import com.sap.sailing.datamining.data.HasLeaderboardContext;
import com.sap.sailing.datamining.data.HasLeaderboardGroupContext;
@@ -22,6 +23,8 @@ import com.sap.sailing.datamining.data.HasTrackedRaceContext;
import com.sap.sailing.datamining.data.HasWindFixContext;
import com.sap.sailing.datamining.data.HasWindTrackContext;
import com.sap.sailing.datamining.impl.components.aggregators.ParallelBearingAverageDegreesAggregationProcessor;
import com.sap.sailing.datamining.impl.components.aggregators.ParallelBearingMaxAggregationProcessor;
import com.sap.sailing.datamining.impl.components.aggregators.ParallelBearingMinAggregationProcessor;
import com.sap.sailing.datamining.impl.components.aggregators.ParallelBoolSumAggregationProcessor;
import com.sap.sailing.datamining.impl.components.aggregators.ParallelDistanceAverageAggregationProcessor;
import com.sap.sailing.datamining.impl.components.aggregators.ParallelDistanceMaxAggregationProcessor;
@@ -95,6 +98,7 @@ public class Activator extends AbstractDataMiningActivatorWithPredefinedQueries
internalClasses.add(HasWindFixContext.class);
internalClasses.add(HasBravoFixContext.class);
internalClasses.add(HasBravoFixTrackContext.class);
internalClasses.add(HasFoilingSegmentContext.class);
internalClasses.add(HasManeuverContext.class);
internalClasses.add(HasMarkPassingContext.class);
internalClasses.add(HasRaceOfCompetitorContext.class);
@@ -131,6 +135,8 @@ public class Activator extends AbstractDataMiningActivatorWithPredefinedQueries
aggregators.add(ParallelDurationMaxAggregationProcessor.getDefinition());
aggregators.add(ParallelDurationMinAggregationProcessor.getDefinition());
aggregators.add(ParallelBearingAverageDegreesAggregationProcessor.getDefinition());
aggregators.add(ParallelBearingMaxAggregationProcessor.getDefinition());
aggregators.add(ParallelBearingMinAggregationProcessor.getDefinition());
return aggregators;
}
@@ -5,6 +5,7 @@ import java.util.Collection;
import com.sap.sailing.datamining.data.HasBravoFixContext;
import com.sap.sailing.datamining.data.HasBravoFixTrackContext;
import com.sap.sailing.datamining.data.HasFoilingSegmentContext;
import com.sap.sailing.datamining.data.HasGPSFixContext;
import com.sap.sailing.datamining.data.HasLeaderboardContext;
import com.sap.sailing.datamining.data.HasManeuverContext;
@@ -19,6 +20,7 @@ import com.sap.sailing.datamining.data.HasWindTrackContext;
import com.sap.sailing.datamining.impl.components.BravoFixRetrievalProcessor;
import com.sap.sailing.datamining.impl.components.BravoFixTrackRetrievalProcessor;
import com.sap.sailing.datamining.impl.components.CompetitorOfRaceInLeaderboardRetrievalProcessor;
import com.sap.sailing.datamining.impl.components.FoilingSegmentRetrievalProcessor;
import com.sap.sailing.datamining.impl.components.GPSFixRetrievalProcessor;
import com.sap.sailing.datamining.impl.components.LeaderboardGroupRetrievalProcessor;
import com.sap.sailing.datamining.impl.components.LeaderboardRetrievalProcessor;
@@ -70,6 +72,12 @@ public class SailingDataRetrievalChainDefinitions {
HasBravoFixTrackContext.class, "BravoFixTrack");
dataRetrieverChainDefinitions.add(bravoFixTrackRetrieverChainDefinition);
final DataRetrieverChainDefinition<RacingEventService, HasFoilingSegmentContext> foilingSegmentsRetrieverChainDefinition = new SimpleDataRetrieverChainDefinition<>(
raceOfCompetitorRetrieverChainDefinition, HasFoilingSegmentContext.class, "FoilingSegmentsSailingDomainRetrieverChain");
foilingSegmentsRetrieverChainDefinition.endWith(RaceOfCompetitorRetrievalProcessor.class, FoilingSegmentRetrievalProcessor.class,
HasFoilingSegmentContext.class, "FoilingSegments");
dataRetrieverChainDefinitions.add(foilingSegmentsRetrieverChainDefinition);
final DataRetrieverChainDefinition<RacingEventService, HasTrackedLegOfCompetitorContext> legOfCompetitorRetrieverChainDefinition = new SimpleDataRetrieverChainDefinition<>(
trackedRaceRetrieverChainDefinition, HasTrackedLegOfCompetitorContext.class, "LegSailingDomainRetrieverChain");
legOfCompetitorRetrieverChainDefinition.addAfter(TrackedRaceRetrievalProcessor.class, TrackedLegRetrievalProcessor.class, HasTrackedLegContext.class, "Leg");
@@ -1,8 +1,13 @@
package com.sap.sailing.datamining.data;
import com.sap.sailing.domain.common.Bearing;
import com.sap.sailing.domain.common.NoWindException;
import com.sap.sailing.domain.common.SpeedWithBearing;
import com.sap.sailing.domain.common.Wind;
import com.sap.sailing.domain.common.tracking.BravoFix;
import com.sap.sse.common.TimePoint;
import com.sap.sse.datamining.annotations.Connector;
import com.sap.sse.datamining.annotations.Statistic;
public interface HasBravoFixContext extends HasWindOnTrackedLeg {
@Connector(scanForStatistics=false)
@@ -10,6 +15,15 @@ public interface HasBravoFixContext extends HasWindOnTrackedLeg {
@Connector(ordinal=1)
BravoFix getBravoFix();
@Connector(messageKey="Speed")
SpeedWithBearing getSpeed();
@Connector(messageKey="Wind")
Wind getWind();
@Statistic(messageKey="AbsoluteTrueWindAngle")
Bearing getAbsoluteTrueWindAngle() throws NoWindException;
@Override
default TimePoint getTimePoint() {
@@ -0,0 +1,64 @@
package com.sap.sailing.datamining.data;
import java.util.Locale;
import com.sap.sailing.domain.common.Bearing;
import com.sap.sailing.domain.common.Distance;
import com.sap.sailing.domain.common.LegType;
import com.sap.sailing.domain.common.NoWindException;
import com.sap.sailing.domain.common.Wind;
import com.sap.sse.common.Duration;
import com.sap.sse.common.TimePoint;
import com.sap.sse.datamining.annotations.Connector;
import com.sap.sse.datamining.annotations.Dimension;
import com.sap.sse.datamining.annotations.Statistic;
import com.sap.sse.datamining.shared.impl.dto.ClusterDTO;
import com.sap.sse.i18n.ResourceBundleStringMessages;
public interface HasFoilingSegmentContext {
@Connector(scanForStatistics=false)
HasBravoFixTrackContext getBravoFixTrackContext();
TimePoint getStartOfFoilingSegment();
TimePoint getEndOfFoilingSegment();
@Statistic(messageKey="FoilingDuration")
Duration getDuration();
@Statistic(messageKey="FoilingDistance")
Distance getDistance();
@Statistic(messageKey="TakeoffSpeedInKnotsInKnots", resultDecimals=1)
Double getTakeoffSpeedInKnots();
@Statistic(messageKey="LandingSpeedInKnots", resultDecimals=1)
Double getLandingSpeedInKnots();
@Statistic(messageKey="AbsoluteTrueWindAngleAtTakeoff", resultDecimals=1)
Bearing getAbsoluteTrueWindAngleAtTakeoffInDegrees() throws NoWindException;
@Statistic(messageKey="AbsoluteTrueWindAngleAtLanding", resultDecimals=1)
Bearing getAbsoluteTrueWindAngleAtLandingInDegrees() throws NoWindException;
@Statistic(messageKey="AverageAbsoluteTrueWindAngle", resultDecimals=1)
Bearing getAverageAbsoluteTrueWindAngle() throws NoWindException;
@Dimension(messageKey="WindStrengthInBeaufortAtTakeoff")
ClusterDTO getWindStrengthAsBeaufortClusterAtTakeoff(Locale locale, ResourceBundleStringMessages stringMessages);
@Dimension(messageKey="WindStrengthInBeaufortAtLanding")
ClusterDTO getWindStrengthAsBeaufortClusterAtLanding(Locale locale, ResourceBundleStringMessages stringMessages);
@Connector(messageKey="WindAtTakeoff")
Wind getWindAtTakeoff();
@Connector(messageKey="WindAtLanding")
Wind getWindAtLanding();
@Dimension(messageKey="StartsOnLegType")
LegType getStartsOnLegType() throws NoWindException;
@Dimension(messageKey="EndsOnLegType")
LegType getEndsOnLegType() throws NoWindException;
}
@@ -9,6 +9,6 @@ public interface HasLeaderboardContext {
PolarDataService getPolarDataService();
@Dimension(messageKey="Leaderboard")
@Dimension(messageKey="Leaderboard", ordinal=1)
String getName();
}
@@ -20,6 +20,9 @@ public interface HasManeuverContext extends HasWindOnTrackedLeg, HasManeuver, Ha
@Dimension(messageKey="Tack", ordinal=13)
Tack getTack();
@Dimension(messageKey="ToSide")
NauticalSide getToSide();
@Connector(messageKey="SpeedBefore", ordinal=0)
SpeedWithBearing getSpeedBefore();
@@ -28,14 +31,10 @@ public interface HasManeuverContext extends HasWindOnTrackedLeg, HasManeuver, Ha
@Statistic(messageKey="DirectionChange", resultDecimals=2, ordinal=2)
Double getDirectionChangeInDegrees();
@Statistic(messageKey="AbsoluteDirectionChange", resultDecimals=2, ordinal=2)
@Statistic(messageKey="AbsoluteDirectionChange", resultDecimals=2, ordinal=3)
Double getAbsoluteDirectionChangeInDegrees();
@Dimension(messageKey="ToSide")
NauticalSide getToSide();
@Statistic(messageKey="ManeuverLoss", resultDecimals=0, ordinal=3)
@Statistic(messageKey="ManeuverLoss", resultDecimals=0, ordinal=4)
Distance getManeuverLoss();
}
@@ -5,25 +5,29 @@ import com.sap.sailing.domain.base.Competitor;
import com.sap.sse.datamining.annotations.Connector;
import com.sap.sse.datamining.annotations.Dimension;
import com.sap.sse.datamining.annotations.Statistic;
import com.sap.sse.datamining.shared.impl.dto.ClusterDTO;
public interface HasRaceResultOfCompetitorContext {
@Connector(scanForStatistics=false)
public HasLeaderboardContext getLeaderboardContext();
@Connector(messageKey="Competitor")
@Connector(messageKey="Competitor", ordinal=2)
public Competitor getCompetitor();
@Connector(messageKey="BoatClass")
@Connector(messageKey="BoatClass", ordinal=3)
BoatClass getBoatClass();
@Dimension(messageKey="Regatta")
@Dimension(messageKey="Regatta", ordinal=4)
String getRegattaName();
@Dimension(messageKey="CompetitorSearchTag", ordinal=11) // TODO Clean me: Move Dimension to Competitor when possible
@Dimension(messageKey="CompetitorSearchTag", ordinal=5) // TODO Clean me: Move Dimension to Competitor when possible
public String getCompetitorSearchTag();
@Dimension(messageKey="RelativeScoreInPercent", ordinal=6)
public ClusterDTO getPercentageClusterForRelativeScore();
@Dimension(messageKey="WindSpeedInBeaufort")
@Dimension(messageKey="WindSpeedInBeaufort", ordinal=7)
int getAverageWindSpeedInRoundedBeaufort();
/**
@@ -17,7 +17,7 @@ public interface HasWind extends Positioned, Timed {
@Dimension(messageKey="WindStrengthInBeaufort", ordinal=11)
default ClusterDTO getWindStrengthAsBeaufortCluster(Locale locale, ResourceBundleStringMessages stringMessages) {
Wind wind = getWind();
Cluster<?> cluster = Activator.getClusterGroups().getWindStrengthInBeaufortClusterGroup().getClusterFor(wind);
return new ClusterDTO(cluster.asLocalizedString(locale, stringMessages));
final Cluster<?> cluster = Activator.getClusterGroups().getWindStrengthInBeaufortClusterGroup().getClusterFor(wind);
return new ClusterDTO(cluster.toString(), ()->cluster.asLocalizedString(locale, stringMessages));
}
}
@@ -11,13 +11,13 @@ public interface HasWindFixContext extends HasWind {
@Connector(scanForStatistics=false)
public HasTrackedRaceContext getTrackedRaceContext();
@Statistic(messageKey="")
@Statistic(messageKey="", ordinal=0)
public Wind getWind();
@Statistic(messageKey="windFrom", resultDecimals=1)
@Statistic(messageKey="windFrom", resultDecimals=1, ordinal=1)
double getWindFromDegrees();
@Statistic(messageKey="windSpeedKnots", resultDecimals=1)
@Statistic(messageKey="windSpeedKnots", resultDecimals=1, ordinal=2)
double getWindSpeedInKnots();
@Override
@@ -6,7 +6,7 @@ import java.util.concurrent.ExecutorService;
import com.sap.sailing.datamining.data.HasBravoFixTrackContext;
import com.sap.sailing.datamining.data.HasRaceOfCompetitorContext;
import com.sap.sailing.datamining.impl.data.BravoTrackWithContext;
import com.sap.sailing.datamining.impl.data.BravoFixTrackWithContext;
import com.sap.sailing.domain.base.Competitor;
import com.sap.sailing.domain.tracking.BravoFixTrack;
import com.sap.sailing.domain.tracking.TrackedRace;
@@ -32,7 +32,7 @@ public class BravoFixTrackRetrievalProcessor extends AbstractRetrievalProcessor<
final TrackedRace trackedRace = element.getTrackedRaceContext().getTrackedRace();
final BravoFixTrack<Competitor> bravoFixTrack = trackedRace.getSensorTrack(element.getCompetitor(), BravoFixTrack.TRACK_NAME);
if (bravoFixTrack != null) {
bravoTracksWithContext.add(new BravoTrackWithContext(element, bravoFixTrack));
bravoTracksWithContext.add(new BravoFixTrackWithContext(element, bravoFixTrack));
}
return bravoTracksWithContext;
}
@@ -0,0 +1,76 @@
package com.sap.sailing.datamining.impl.components;
import java.util.ArrayList;
import java.util.Collection;
import java.util.concurrent.ExecutorService;
import com.sap.sailing.datamining.data.HasFoilingSegmentContext;
import com.sap.sailing.datamining.data.HasRaceOfCompetitorContext;
import com.sap.sailing.datamining.impl.data.BravoFixTrackWithContext;
import com.sap.sailing.datamining.impl.data.FoilingSegmentWithContext;
import com.sap.sailing.domain.base.Competitor;
import com.sap.sailing.domain.common.tracking.BravoFix;
import com.sap.sailing.domain.tracking.BravoFixTrack;
import com.sap.sailing.domain.tracking.TrackedRace;
import com.sap.sse.common.TimePoint;
import com.sap.sse.common.impl.MillisecondsTimePoint;
import com.sap.sse.datamining.components.Processor;
import com.sap.sse.datamining.impl.components.AbstractRetrievalProcessor;
public class FoilingSegmentRetrievalProcessor extends AbstractRetrievalProcessor<HasRaceOfCompetitorContext, HasFoilingSegmentContext> {
public FoilingSegmentRetrievalProcessor(ExecutorService executor, Collection<Processor<HasFoilingSegmentContext, ?>> resultReceivers, int retrievalLevel) {
super(HasRaceOfCompetitorContext.class, HasFoilingSegmentContext.class, executor, resultReceivers, retrievalLevel);
}
@Override
protected Iterable<HasFoilingSegmentContext> retrieveData(HasRaceOfCompetitorContext element) {
Collection<HasFoilingSegmentContext> foilingSegments = new ArrayList<>();
final TrackedRace trackedRace = element.getTrackedRaceContext().getTrackedRace();
final TimePoint startOfRace = element.getTrackedRaceContext().getTrackedRace().getStartOfRace();
if (startOfRace != null) {
final TimePoint endOfRace = element.getTrackedRaceContext().getTrackedRace().getEndOfRace();
final TimePoint end;
if (endOfRace == null) {
final TimePoint endOfTracking = element.getTrackedRaceContext().getTrackedRace().getEndOfTracking();
end = endOfTracking == null ? MillisecondsTimePoint.now() : endOfTracking;
} else {
end = endOfRace;
}
final BravoFixTrack<Competitor> bravoFixTrack = trackedRace.getSensorTrack(element.getCompetitor(), BravoFixTrack.TRACK_NAME);
if (bravoFixTrack != null) {
boolean isFoiling = false;
TimePoint startOfSegment = null;
bravoFixTrack.lockForRead();
try {
for (final BravoFix bravoFix : bravoFixTrack.getFixes(startOfRace, /* fromInclusive */ true, end, /* toInclusive */ false)) {
if (isFoiling) {
if (!bravoFix.isFoiling()) {
isFoiling = false;
foilingSegments.add(createFoilingSegment(startOfSegment, bravoFix.getTimePoint(), element, bravoFixTrack));
startOfSegment = null;
}
} else {
if (bravoFix.isFoiling()) {
isFoiling = true;
startOfSegment = bravoFix.getTimePoint();
}
}
}
} finally {
bravoFixTrack.unlockAfterRead();
}
if (isFoiling) {
foilingSegments.add(createFoilingSegment(startOfSegment, end, element, bravoFixTrack));
}
}
}
return foilingSegments;
}
private HasFoilingSegmentContext createFoilingSegment(TimePoint startOfSegment, TimePoint endOfSegment,
HasRaceOfCompetitorContext raceOfCompetitorContext, BravoFixTrack<Competitor> bravoFixTrack) {
return new FoilingSegmentWithContext(new BravoFixTrackWithContext(raceOfCompetitorContext, bravoFixTrack), startOfSegment, endOfSegment);
}
}
@@ -0,0 +1,29 @@
package com.sap.sailing.datamining.impl.components.aggregators;
import java.util.Collection;
import java.util.Map;
import java.util.concurrent.ExecutorService;
import com.sap.sailing.domain.common.Bearing;
import com.sap.sse.datamining.components.AggregationProcessorDefinition;
import com.sap.sse.datamining.components.Processor;
import com.sap.sse.datamining.impl.components.SimpleAggregationProcessorDefinition;
import com.sap.sse.datamining.impl.components.aggregators.AbstractParallelComparableMaxAggregationProcessor;
import com.sap.sse.datamining.shared.GroupKey;
public class ParallelBearingMaxAggregationProcessor extends
AbstractParallelComparableMaxAggregationProcessor<Bearing> {
private static final AggregationProcessorDefinition<Bearing, Bearing> DEFINITION =
new SimpleAggregationProcessorDefinition<>(Bearing.class, Bearing.class, "Maximum", ParallelBearingMaxAggregationProcessor.class);
public static AggregationProcessorDefinition<Bearing, Bearing> getDefinition() {
return DEFINITION;
}
public ParallelBearingMaxAggregationProcessor(ExecutorService executor,
Collection<Processor<Map<GroupKey, Bearing>, ?>> resultReceivers) {
super(executor, resultReceivers);
}
}
@@ -0,0 +1,29 @@
package com.sap.sailing.datamining.impl.components.aggregators;
import java.util.Collection;
import java.util.Map;
import java.util.concurrent.ExecutorService;
import com.sap.sailing.domain.common.Bearing;
import com.sap.sse.datamining.components.AggregationProcessorDefinition;
import com.sap.sse.datamining.components.Processor;
import com.sap.sse.datamining.impl.components.SimpleAggregationProcessorDefinition;
import com.sap.sse.datamining.impl.components.aggregators.AbstractParallelComparableMaxAggregationProcessor;
import com.sap.sse.datamining.shared.GroupKey;
public class ParallelBearingMinAggregationProcessor extends
AbstractParallelComparableMaxAggregationProcessor<Bearing> {
private static final AggregationProcessorDefinition<Bearing, Bearing> DEFINITION =
new SimpleAggregationProcessorDefinition<>(Bearing.class, Bearing.class, "Minimum", ParallelBearingMinAggregationProcessor.class);
public static AggregationProcessorDefinition<Bearing, Bearing> getDefinition() {
return DEFINITION;
}
public ParallelBearingMinAggregationProcessor(ExecutorService executor,
Collection<Processor<Map<GroupKey, Bearing>, ?>> resultReceivers) {
super(executor, resultReceivers);
}
}
@@ -8,11 +8,11 @@ import com.sap.sailing.domain.common.Distance;
import com.sap.sse.datamining.components.AggregationProcessorDefinition;
import com.sap.sse.datamining.components.Processor;
import com.sap.sse.datamining.impl.components.SimpleAggregationProcessorDefinition;
import com.sap.sse.datamining.impl.components.aggregators.AbstractParallelSingleGroupedValueAggregationProcessor;
import com.sap.sse.datamining.impl.components.aggregators.AbstractParallelComparableMaxAggregationProcessor;
import com.sap.sse.datamining.shared.GroupKey;
public class ParallelDistanceMaxAggregationProcessor extends
AbstractParallelSingleGroupedValueAggregationProcessor<Distance> {
AbstractParallelComparableMaxAggregationProcessor<Distance> {
private static final AggregationProcessorDefinition<Distance, Distance> DEFINITION =
new SimpleAggregationProcessorDefinition<>(Distance.class, Distance.class, "Maximum", ParallelDistanceMaxAggregationProcessor.class);
@@ -20,16 +20,9 @@ public class ParallelDistanceMaxAggregationProcessor extends
public static AggregationProcessorDefinition<Distance, Distance> getDefinition() {
return DEFINITION;
}
public ParallelDistanceMaxAggregationProcessor(ExecutorService executor,
Collection<Processor<Map<GroupKey, Distance>, ?>> resultReceivers) {
super(executor, resultReceivers, "Maximum");
super(executor, resultReceivers);
}
@Override
protected Distance compareValuesAndReturnNewResult(Distance currentResult, Distance newValue) {
return currentResult.getMeters() >= newValue.getMeters() ? currentResult : newValue;
}
}
@@ -8,11 +8,11 @@ import com.sap.sailing.domain.common.Distance;
import com.sap.sse.datamining.components.AggregationProcessorDefinition;
import com.sap.sse.datamining.components.Processor;
import com.sap.sse.datamining.impl.components.SimpleAggregationProcessorDefinition;
import com.sap.sse.datamining.impl.components.aggregators.AbstractParallelSingleGroupedValueAggregationProcessor;
import com.sap.sse.datamining.impl.components.aggregators.AbstractParallelComparableMinAggregationProcessor;
import com.sap.sse.datamining.shared.GroupKey;
public class ParallelDistanceMinAggregationProcessor extends
AbstractParallelSingleGroupedValueAggregationProcessor<Distance> {
AbstractParallelComparableMinAggregationProcessor<Distance> {
private static final AggregationProcessorDefinition<Distance, Distance> DEFINITION =
new SimpleAggregationProcessorDefinition<>(Distance.class, Distance.class, "Minimum", ParallelDistanceMinAggregationProcessor.class);
@@ -24,12 +24,6 @@ public class ParallelDistanceMinAggregationProcessor extends
public ParallelDistanceMinAggregationProcessor(ExecutorService executor,
Collection<Processor<Map<GroupKey, Distance>, ?>> resultReceivers) {
super(executor, resultReceivers, "Minimum");
super(executor, resultReceivers);
}
@Override
protected Distance compareValuesAndReturnNewResult(Distance currentResult, Distance newValue) {
return currentResult.getMeters() <= newValue.getMeters() ? currentResult : newValue;
}
}
@@ -8,13 +8,13 @@ import com.sap.sse.common.Duration;
import com.sap.sse.common.TimePoint;
import com.sap.sse.common.impl.MillisecondsTimePoint;
public class BravoTrackWithContext implements HasBravoFixTrackContext {
public class BravoFixTrackWithContext implements HasBravoFixTrackContext {
private final HasRaceOfCompetitorContext raceOfCompetitorContext;
private final BravoFixTrack<Competitor> bravoFixTrack;
public BravoTrackWithContext(HasRaceOfCompetitorContext raceOfCompetitorContext, BravoFixTrack<Competitor> bravoFixTrack) {
public BravoFixTrackWithContext(HasRaceOfCompetitorContext raceOfCompetitorContext, BravoFixTrack<Competitor> bravoFixTrack) {
this.raceOfCompetitorContext = raceOfCompetitorContext;
this.bravoFixTrack = bravoFixTrack;
}
@@ -2,9 +2,16 @@ package com.sap.sailing.datamining.impl.data;
import com.sap.sailing.datamining.data.HasBravoFixContext;
import com.sap.sailing.datamining.data.HasTrackedLegOfCompetitorContext;
import com.sap.sailing.domain.base.Competitor;
import com.sap.sailing.domain.common.Bearing;
import com.sap.sailing.domain.common.NoWindException;
import com.sap.sailing.domain.common.Position;
import com.sap.sailing.domain.common.SpeedWithBearing;
import com.sap.sailing.domain.common.Wind;
import com.sap.sailing.domain.common.tracking.BravoFix;
import com.sap.sailing.domain.common.tracking.GPSFixMoving;
import com.sap.sailing.domain.tracking.GPSFixTrack;
import com.sap.sailing.domain.tracking.TrackedRace;
public class BravoFixWithContext implements HasBravoFixContext {
private static final long serialVersionUID = -4537126043228674949L;
@@ -39,10 +46,35 @@ public class BravoFixWithContext implements HasBravoFixContext {
this.wind = wind;
}
@Override
public SpeedWithBearing getSpeed() {
return getGpsFixTrack().getEstimatedSpeed(getTimePoint());
}
@Override
public Wind getWind() {
return getTrackedRace().getWind(getGpsFixTrack().getEstimatedPosition(getTimePoint(), /* extrapolate */ true), getTimePoint());
}
@Override
public Bearing getAbsoluteTrueWindAngle() throws NoWindException {
return getTrackedRace().getTrackedLeg(getCompetitor(), getTimePoint()).getBeatAngle(getTimePoint()).abs();
}
private Competitor getCompetitor() {
return getTrackedLegOfCompetitorContext().getCompetitor();
}
@Override
public Position getPosition() {
return getTrackedLegOfCompetitorContext().getTrackedLegOfCompetitor().getTrackedLeg().getTrackedRace()
.getTrack(getTrackedLegOfCompetitorContext().getCompetitor())
.getEstimatedPosition(getTimePoint(), /* extrapolate */ true);
return getGpsFixTrack().getEstimatedPosition(getTimePoint(), /* extrapolate */ true);
}
private GPSFixTrack<Competitor, GPSFixMoving> getGpsFixTrack() {
return getTrackedRace().getTrack(getTrackedLegOfCompetitorContext().getCompetitor());
}
private TrackedRace getTrackedRace() {
return getTrackedLegOfCompetitorContext().getTrackedLegOfCompetitor().getTrackedLeg().getTrackedRace();
}
}
@@ -0,0 +1,164 @@
package com.sap.sailing.datamining.impl.data;
import java.util.Locale;
import com.sap.sailing.datamining.Activator;
import com.sap.sailing.datamining.data.HasBravoFixTrackContext;
import com.sap.sailing.datamining.data.HasFoilingSegmentContext;
import com.sap.sailing.domain.base.Competitor;
import com.sap.sailing.domain.common.Bearing;
import com.sap.sailing.domain.common.BearingCluster;
import com.sap.sailing.domain.common.Distance;
import com.sap.sailing.domain.common.LegType;
import com.sap.sailing.domain.common.NoWindException;
import com.sap.sailing.domain.common.SpeedWithBearing;
import com.sap.sailing.domain.common.Wind;
import com.sap.sailing.domain.common.tracking.BravoFix;
import com.sap.sailing.domain.common.tracking.GPSFixMoving;
import com.sap.sailing.domain.tracking.BravoFixTrack;
import com.sap.sailing.domain.tracking.GPSFixTrack;
import com.sap.sailing.domain.tracking.TrackedRace;
import com.sap.sse.common.Duration;
import com.sap.sse.common.TimePoint;
import com.sap.sse.datamining.data.Cluster;
import com.sap.sse.datamining.shared.impl.dto.ClusterDTO;
import com.sap.sse.i18n.ResourceBundleStringMessages;
public class FoilingSegmentWithContext implements HasFoilingSegmentContext {
private final HasBravoFixTrackContext bravoFixTrackContext;
private final TimePoint startOfFoilingSegment;
private final TimePoint endOfFoilingSegment;
public FoilingSegmentWithContext(HasBravoFixTrackContext bravoFixTrackContext, TimePoint startOfFoilingSegment,
TimePoint endOfFoilingSegment) {
super();
this.bravoFixTrackContext = bravoFixTrackContext;
this.startOfFoilingSegment = startOfFoilingSegment;
this.endOfFoilingSegment = endOfFoilingSegment;
}
@Override
public HasBravoFixTrackContext getBravoFixTrackContext() {
return bravoFixTrackContext;
}
@Override
public TimePoint getStartOfFoilingSegment() {
return startOfFoilingSegment;
}
@Override
public TimePoint getEndOfFoilingSegment() {
return endOfFoilingSegment;
}
@Override
public Duration getDuration() {
return getStartOfFoilingSegment().until(getEndOfFoilingSegment());
}
@Override
public Distance getDistance() {
return getGpsFixTrack().
getDistanceTraveled(getStartOfFoilingSegment(), getEndOfFoilingSegment());
}
private GPSFixTrack<Competitor, GPSFixMoving> getGpsFixTrack() {
return getTrackedRace().getTrack(getCompetitor());
}
private Competitor getCompetitor() {
return getBravoFixTrackContext().getRaceOfCompetitorContext().getCompetitor();
}
private TrackedRace getTrackedRace() {
return getBravoFixTrackContext().getRaceOfCompetitorContext().getTrackedRaceContext().getTrackedRace();
}
@Override
public Double getTakeoffSpeedInKnots() {
final SpeedWithBearing estimatedSpeed = getGpsFixTrack().getEstimatedSpeed(getStartOfFoilingSegment());
return estimatedSpeed==null?null:estimatedSpeed.getKnots();
}
@Override
public Double getLandingSpeedInKnots() {
final SpeedWithBearing estimatedSpeed = getGpsFixTrack().getEstimatedSpeed(getEndOfFoilingSegment());
return estimatedSpeed==null?null:estimatedSpeed.getKnots();
}
@Override
public Bearing getAbsoluteTrueWindAngleAtTakeoffInDegrees() throws NoWindException {
return getAbsoluteTrueWindAngle(getStartOfFoilingSegment());
}
@Override
public Bearing getAbsoluteTrueWindAngleAtLandingInDegrees() throws NoWindException {
final TimePoint timePoint = getEndOfFoilingSegment();
return getAbsoluteTrueWindAngle(timePoint);
}
private Bearing getAbsoluteTrueWindAngle(final TimePoint timePoint) throws NoWindException {
return getTrackedRace().getTrackedLeg(getCompetitor(), timePoint).getBeatAngle(timePoint).abs();
}
@Override
public Bearing getAverageAbsoluteTrueWindAngle() throws NoWindException {
final BearingCluster bearingCluster = new BearingCluster();
final BravoFixTrack<Competitor> bravoFixTrack = getBravoFixTrackContext().getBravoFixTrack();
bravoFixTrack.lockForRead();
try {
for (final BravoFix bravoFix : bravoFixTrack.getFixes(getStartOfFoilingSegment(), /* fromInclusive */ true, getEndOfFoilingSegment(), /* toInclusive */ false)) {
bearingCluster.add(getAbsoluteTrueWindAngle(bravoFix.getTimePoint()));
}
} finally {
bravoFixTrack.unlockAfterRead();
}
return bearingCluster.getAverage();
}
@Override
public ClusterDTO getWindStrengthAsBeaufortClusterAtTakeoff(Locale locale,
ResourceBundleStringMessages stringMessages) {
return getWindStrengthAsBeaufortCluster(locale, stringMessages, getWindAtTakeoff());
}
@Override
public ClusterDTO getWindStrengthAsBeaufortClusterAtLanding(Locale locale,
ResourceBundleStringMessages stringMessages) {
return getWindStrengthAsBeaufortCluster(locale, stringMessages, getWindAtLanding());
}
private Wind getWind(TimePoint timePoint) {
return getTrackedRace().getWind(getGpsFixTrack().getEstimatedPosition(timePoint, /* extrapolate */ true), timePoint);
}
@Override
public Wind getWindAtTakeoff() {
return getWind(getStartOfFoilingSegment());
}
@Override
public Wind getWindAtLanding() {
return getWind(getEndOfFoilingSegment());
}
private ClusterDTO getWindStrengthAsBeaufortCluster(Locale locale, ResourceBundleStringMessages stringMessages, Wind wind) {
Cluster<?> cluster = Activator.getClusterGroups().getWindStrengthInBeaufortClusterGroup().getClusterFor(wind);
return new ClusterDTO(cluster.toString(), ()->cluster.asLocalizedString(locale, stringMessages));
}
@Override
public LegType getStartsOnLegType() throws NoWindException {
return getLegType(getStartOfFoilingSegment());
}
private LegType getLegType(final TimePoint timePoint) throws NoWindException {
return getTrackedRace().getTrackedLeg(getCompetitor(), timePoint).getTrackedLeg().getLegType(timePoint);
}
@Override
public LegType getEndsOnLegType() throws NoWindException {
return getLegType(getEndOfFoilingSegment());
}
}
@@ -5,6 +5,8 @@ import java.util.Set;
import java.util.logging.Level;
import java.util.logging.Logger;
import com.sap.sailing.datamining.Activator;
import com.sap.sailing.datamining.SailingClusterGroups;
import com.sap.sailing.datamining.data.HasLeaderboardContext;
import com.sap.sailing.datamining.data.HasRaceResultOfCompetitorContext;
import com.sap.sailing.domain.base.BoatClass;
@@ -31,6 +33,8 @@ import com.sap.sse.common.TimePoint;
import com.sap.sse.common.Util;
import com.sap.sse.common.Util.Pair;
import com.sap.sse.common.impl.MillisecondsTimePoint;
import com.sap.sse.datamining.data.Cluster;
import com.sap.sse.datamining.shared.impl.dto.ClusterDTO;
public class RaceResultOfCompetitorWithContext implements HasRaceResultOfCompetitorContext {
private final static Logger logger = Logger.getLogger(RaceResultOfCompetitorWithContext.class.getName());
@@ -78,6 +82,18 @@ public class RaceResultOfCompetitorWithContext implements HasRaceResultOfCompeti
public String getCompetitorSearchTag() {
return getCompetitor().getSearchTag();
}
@Override
public ClusterDTO getPercentageClusterForRelativeScore() {
Double relativeScore = getRelativeRank();
if (relativeScore == null) {
return null;
}
SailingClusterGroups clusterGroups = Activator.getClusterGroups();
Cluster<Double> cluster = clusterGroups.getPercentageClusterGroup().getClusterFor(relativeScore);
return new ClusterDTO(clusterGroups.getPercentageClusterFormatter().format(cluster));
}
@Override
public int getAverageWindSpeedInRoundedBeaufort() {
@@ -5,6 +5,11 @@ import com.sap.sailing.domain.common.impl.DegreeBearingImpl;
public abstract class AbstractBearing implements Bearing {
private static final long serialVersionUID = 1968420344627864784L;
@Override
public int compareTo(Bearing o) {
return this==o?0:getDegrees() > o.getDegrees() ? 1 : getDegrees()==o.getDegrees()?0:-1;
}
@Override
public Bearing reverse() {
if (getDegrees() >= 180) {
@@ -69,5 +74,8 @@ public abstract class AbstractBearing implements Bearing {
return getDegrees() / 180. * Math.PI;
}
@Override
public Bearing abs() {
return getDegrees()>=0?this:new DegreeBearingImpl(-getDegrees());
}
}
@@ -4,7 +4,7 @@ import java.io.Serializable;
import com.sap.sailing.domain.common.impl.DegreeBearingImpl;
public interface Bearing extends Serializable {
public interface Bearing extends Serializable, Comparable<Bearing> {
Bearing NORTH = new DegreeBearingImpl(0);
Bearing EAST = new DegreeBearingImpl(90);
Bearing SOUTH = new DegreeBearingImpl(180);
@@ -42,4 +42,9 @@ public interface Bearing extends Serializable {
*/
Bearing middle(Bearing other);
/**
* If this bearing has a negative signum, reverts the signum. For example, {@code new DegreeBearingImpl(-10).abs().equals(new DegreeBearingImpl(10)}.
*/
Bearing abs();
}
@@ -11,7 +11,7 @@ import com.sap.sse.datamining.annotations.Statistic;
* <p><b>NOTE:</b> This fix type is currently used to track ESS foiling data, only.</p>
*/
public interface BravoFix extends SensorFix {
static final Distance MIN_FOILING_HEIGHT_THRESHOLD = new MeterDistance(0.2);
static final Distance MIN_FOILING_HEIGHT_THRESHOLD = new MeterDistance(0.1);
/**
* Gets the ride height (foiling) for this fix.
@@ -36,7 +36,7 @@ public class BravoFixImpl implements BravoFix {
@Override
public Distance getRideHeight() {
return new MeterDistance(fix.get(BravoSensorDataMetadata.INSTANCE.rideHeightColumn));
return Util.min(getRideHeightPortHull(), getRideHeightStarboardHull());
}
@Override
@@ -51,7 +51,7 @@ public class BravoFixImpl implements BravoFix {
@Override
public boolean isFoiling() {
return Util.min(getRideHeightPortHull(), getRideHeightStarboardHull()).compareTo(MIN_FOILING_HEIGHT_THRESHOLD) >= 0;
return getRideHeight().compareTo(MIN_FOILING_HEIGHT_THRESHOLD) >= 0;
}
@Override
@@ -515,6 +515,9 @@ public class SensorFixStoreAndLoadTest {
private DoubleVectorFix createBravoDoubleVectorFixWithRideHeight(long timestamp, double rideHeight) {
double[] fixData = new double[BravoSensorDataMetadata.INSTANCE.columnCount];
fixData[BravoSensorDataMetadata.INSTANCE.rideHeightColumn] = rideHeight;
// fill the port/starboard columns as well because their minimum defines the true ride height
fixData[BravoSensorDataMetadata.INSTANCE.rideHeightPortHullColumn] = rideHeight;
fixData[BravoSensorDataMetadata.INSTANCE.rideHeightStarboardHullColumn] = rideHeight;
return new DoubleVectorFixImpl(new MillisecondsTimePoint(timestamp), fixData);
}
@@ -118,6 +118,9 @@ public class BravoFixTrackSerializationTest {
private void addOrReplaceBravoFixToTrack(boolean replace) {
double[] fixData = new double[BravoSensorDataMetadata.INSTANCE.columnCount];
fixData[BravoSensorDataMetadata.INSTANCE.rideHeightColumn] = rideHeight;
// fill the port/starboard columns as well because their minimum defines the true ride height
fixData[BravoSensorDataMetadata.INSTANCE.rideHeightPortHullColumn] = rideHeight;
fixData[BravoSensorDataMetadata.INSTANCE.rideHeightStarboardHullColumn] = rideHeight;
track.add(new BravoFixImpl(new DoubleVectorFixImpl(timePoint, fixData)), replace);
}
}
@@ -60,7 +60,7 @@
<booleanAttribute key="org.eclipse.jdt.launching.DEFAULT_CLASSPATH" value="false"/>
<stringAttribute key="org.eclipse.jdt.launching.JRE_CONTAINER" value="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8"/>
<stringAttribute key="org.eclipse.jdt.launching.MAIN_TYPE" value="com.google.gwt.dev.DevMode"/>
<stringAttribute key="org.eclipse.jdt.launching.PROGRAM_ARGUMENTS" value="-incremental -workDir &quot;${project_loc:com.sap.sailing.gwt.ui}/.tmp/gwt-work&quot; -war &quot;${project_loc:com.sap.sailing.gwt.ui}&quot; -noserver -remoteUI &quot;${gwt_remote_ui_server_port}:${unique_id}&quot; -logLevel INFO -codeServerPort 9876 -startupUrl /gwt/Home.html com.sap.sailing.gwt.home.Home -startupUrl /gwt/AdminConsole.html com.sap.sailing.gwt.ui.AdminConsole -startupUrl /gwt/LeaderboardEditing.html com.sap.sailing.gwt.ui.LeaderboardEditing -startupUrl /gwt/Leaderboard.html com.sap.sailing.gwt.ui.Leaderboard -startupUrl /gwt/Spectator.html com.sap.sailing.gwt.ui.Spectator -startupUrl /gwt/EmbeddedMapAndWindChart com.sap.sailing.gwt.ui.EmbeddedMapAndWindChart -startupUrl /gwt/RaceBoard.html com.sap.sailing.gwt.ui.RaceBoard -startupUrl /gwt/RegattaOverview.html com.sap.sailing.gwt.regattaoverview.RegattaOverview -startupUrl /gwt/DataMining.html com.sap.sailing.gwt.ui.DataMining -startupUrl /gwt/Simulator.html com.sap.sailing.gwt.ui.Simulator -startupUrl /gwt/VideoPopup.html com.sap.sailing.gwt.ui.VideoPopup -startupUrl /gwt/AutoPlay.html com.sap.sailing.gwt.AutoPlay com.sap.sailing.gwt.home.Home com.sap.sailing.gwt.ui.AdminConsole com.sap.sailing.gwt.AutoPlay com.sap.sailing.gwt.ui.YoutubePopup com.sap.sailing.gwt.ui.Simulator com.sap.sailing.gwt.ui.Leaderboard com.sap.sailing.gwt.regattaoverview.RegattaOverview com.sap.sailing.gwt.ui.Spectator com.sap.sailing.gwt.ui.LeaderboardEditing com.sap.sailing.gwt.ui.DataMining com.sap.sailing.gwt.ui.RaceBoard com.sap.sailing.gwt.ui.EmbeddedMapAndWindChart"/>
<stringAttribute key="org.eclipse.jdt.launching.PROGRAM_ARGUMENTS" value="-incremental -workDir &quot;${project_loc:com.sap.sailing.gwt.ui}/.tmp/gwt-work&quot; -war &quot;${project_loc:com.sap.sailing.gwt.ui}&quot; -noserver -remoteUI &quot;${gwt_remote_ui_server_port}:${unique_id}&quot; -logLevel INFO -codeServerPort 9876 -startupUrl /gwt/Home.html com.sap.sailing.gwt.home.Home -startupUrl /gwt/AdminConsole.html com.sap.sailing.gwt.ui.AdminConsole -startupUrl /gwt/LeaderboardEditing.html com.sap.sailing.gwt.ui.LeaderboardEditing -startupUrl /gwt/Leaderboard.html com.sap.sailing.gwt.ui.Leaderboard -startupUrl /gwt/Spectator.html com.sap.sailing.gwt.ui.Spectator -startupUrl /gwt/EmbeddedMapAndWindChart com.sap.sailing.gwt.ui.EmbeddedMapAndWindChart -startupUrl /gwt/RaceBoard.html com.sap.sailing.gwt.ui.RaceBoard -startupUrl /gwt/RegattaOverview.html com.sap.sailing.gwt.regattaoverview.RegattaOverview -startupUrl /gwt/DataMining.html com.sap.sailing.gwt.ui.DataMining -startupUrl /gwt/Simulator.html com.sap.sailing.gwt.ui.Simulator -startupUrl /gwt/VideoPopup.html com.sap.sailing.gwt.ui.VideoPopup -startupUrl /gwt/AutoPlay.html com.sap.sailing.gwt.AutoPlay com.sap.sailing.gwt.AutoPlay"/>
<stringAttribute key="org.eclipse.jdt.launching.PROJECT_ATTR" value="com.sap.sailing.gwt.ui"/>
<stringAttribute key="org.eclipse.jdt.launching.VM_ARGUMENTS" value="-Xms1024m -Xmx3072m -Dgwt.watchFileChanges=false"/>
</launchConfiguration>
@@ -69,7 +69,7 @@
<booleanAttribute key="org.eclipse.jdt.launching.DEFAULT_CLASSPATH" value="false"/>
<stringAttribute key="org.eclipse.jdt.launching.JRE_CONTAINER" value="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8"/>
<stringAttribute key="org.eclipse.jdt.launching.MAIN_TYPE" value="com.google.gwt.dev.DevMode"/>
<stringAttribute key="org.eclipse.jdt.launching.PROGRAM_ARGUMENTS" value="-nosuperDevMode -incremental -war &quot;${project_loc:com.sap.sailing.gwt.ui}&quot; -noserver -remoteUI &quot;${gwt_remote_ui_server_port}:${unique_id}&quot; -logLevel INFO -codeServerPort auto -startupUrl /gwt/Home.html com.sap.sailing.gwt.home.Home -startupUrl /gwt/AdminConsole.html com.sap.sailing.gwt.ui.AdminConsole -startupUrl /gwt/LeaderboardEditing.html com.sap.sailing.gwt.ui.LeaderboardEditing -startupUrl /gwt/Leaderboard.html com.sap.sailing.gwt.ui.Leaderboard -startupUrl /gwt/Spectator.html com.sap.sailing.gwt.ui.Spectator -startupUrl /gwt/RaceBoard.html com.sap.sailing.gwt.ui.RaceBoard -startupUrl /gwt/RegattaOverview.html com.sap.sailing.gwt.regattaoverview.RegattaOverview -startupUrl /gwt/DataMining.html com.sap.sailing.gwt.ui.DataMining -startupUrl /gwt/Simulator.html com.sap.sailing.gwt.ui.Simulator -startupUrl /gwt/VideoPopup.html com.sap.sailing.gwt.ui.VideoPopup -startupUrl /gwt/AutoPlay.html com.sap.sailing.gwt.AutoPlay com.sap.sailing.gwt.home.Home com.sap.sailing.gwt.ui.AdminConsole com.sap.sailing.gwt.AutoPlay com.sap.sailing.gwt.ui.YoutubePopup com.sap.sailing.gwt.ui.Simulator com.sap.sailing.gwt.ui.Leaderboard com.sap.sailing.gwt.regattaoverview.RegattaOverview com.sap.sailing.gwt.ui.Spectator com.sap.sailing.gwt.ui.LeaderboardEditing com.sap.sailing.gwt.ui.DataMining com.sap.sailing.gwt.ui.RaceBoard"/>
<stringAttribute key="org.eclipse.jdt.launching.PROGRAM_ARGUMENTS" value="-incremental -war &quot;${project_loc:com.sap.sailing.gwt.ui}&quot; -noserver -remoteUI &quot;${gwt_remote_ui_server_port}:${unique_id}&quot; -logLevel INFO -codeServerPort auto -startupUrl /gwt/Home.html com.sap.sailing.gwt.home.Home -startupUrl /gwt/AdminConsole.html com.sap.sailing.gwt.ui.AdminConsole -startupUrl /gwt/LeaderboardEditing.html com.sap.sailing.gwt.ui.LeaderboardEditing -startupUrl /gwt/Leaderboard.html com.sap.sailing.gwt.ui.Leaderboard -startupUrl /gwt/Spectator.html com.sap.sailing.gwt.ui.Spectator -startupUrl /gwt/RaceBoard.html com.sap.sailing.gwt.ui.RaceBoard -startupUrl /gwt/RegattaOverview.html com.sap.sailing.gwt.regattaoverview.RegattaOverview -startupUrl /gwt/DataMining.html com.sap.sailing.gwt.ui.DataMining -startupUrl /gwt/Simulator.html com.sap.sailing.gwt.ui.Simulator -startupUrl /gwt/VideoPopup.html com.sap.sailing.gwt.ui.VideoPopup -startupUrl /gwt/AutoPlay.html com.sap.sailing.gwt.AutoPlay com.sap.sailing.gwt.home.Home com.sap.sailing.gwt.ui.AdminConsole com.sap.sailing.gwt.AutoPlay com.sap.sailing.gwt.ui.YoutubePopup com.sap.sailing.gwt.ui.Simulator com.sap.sailing.gwt.ui.Leaderboard com.sap.sailing.gwt.regattaoverview.RegattaOverview com.sap.sailing.gwt.ui.Spectator com.sap.sailing.gwt.ui.LeaderboardEditing com.sap.sailing.gwt.ui.DataMining com.sap.sailing.gwt.ui.RaceBoard"/>
<stringAttribute key="org.eclipse.jdt.launching.PROJECT_ATTR" value="com.sap.sailing.gwt.ui"/>
<stringAttribute key="org.eclipse.jdt.launching.VM_ARGUMENTS" value="-Xmx2048m -Dgwt-usearchives=false -Dgwt.persistentunitcache=false -Dgwt.watchFileChanges=false"/>
</launchConfiguration>
@@ -0,0 +1,48 @@
package com.google.gwt.user.client.rpc.core.com.sap.sailing.domain.common.impl;
import com.google.gwt.user.client.rpc.CustomFieldSerializer;
import com.google.gwt.user.client.rpc.SerializationException;
import com.google.gwt.user.client.rpc.SerializationStreamReader;
import com.google.gwt.user.client.rpc.SerializationStreamWriter;
import com.sap.sailing.domain.common.impl.DegreeBearingImpl;
public class DegreeBearingImpl_CustomFieldSerializer extends CustomFieldSerializer<DegreeBearingImpl> {
@Override
public void serializeInstance(SerializationStreamWriter streamWriter, DegreeBearingImpl instance)
throws SerializationException {
serialize(streamWriter, instance);
}
public static void serialize(SerializationStreamWriter streamWriter, DegreeBearingImpl instance)
throws SerializationException {
streamWriter.writeDouble(instance.getDegrees());
}
@Override
public boolean hasCustomInstantiateInstance() {
return true;
}
@Override
public DegreeBearingImpl instantiateInstance(SerializationStreamReader streamReader)
throws SerializationException {
return instantiate(streamReader);
}
public static DegreeBearingImpl instantiate(SerializationStreamReader streamReader)
throws SerializationException {
return new DegreeBearingImpl(streamReader.readDouble());
}
@Override
public void deserializeInstance(SerializationStreamReader streamReader, DegreeBearingImpl instance)
throws SerializationException {
deserialize(streamReader, instance);
}
public static void deserialize(SerializationStreamReader streamReader, DegreeBearingImpl instance) {
// Done by instantiateInstance
}
}
@@ -0,0 +1,48 @@
package com.google.gwt.user.client.rpc.core.com.sap.sailing.domain.common.impl;
import com.google.gwt.user.client.rpc.CustomFieldSerializer;
import com.google.gwt.user.client.rpc.SerializationException;
import com.google.gwt.user.client.rpc.SerializationStreamReader;
import com.google.gwt.user.client.rpc.SerializationStreamWriter;
import com.sap.sailing.domain.common.impl.RadianBearingImpl;
public class RadianBearingImpl_CustomFieldSerializer extends CustomFieldSerializer<RadianBearingImpl> {
@Override
public void serializeInstance(SerializationStreamWriter streamWriter, RadianBearingImpl instance)
throws SerializationException {
serialize(streamWriter, instance);
}
public static void serialize(SerializationStreamWriter streamWriter, RadianBearingImpl instance)
throws SerializationException {
streamWriter.writeDouble(instance.getRadians());
}
@Override
public boolean hasCustomInstantiateInstance() {
return true;
}
@Override
public RadianBearingImpl instantiateInstance(SerializationStreamReader streamReader)
throws SerializationException {
return instantiate(streamReader);
}
public static RadianBearingImpl instantiate(SerializationStreamReader streamReader)
throws SerializationException {
return new RadianBearingImpl(streamReader.readDouble());
}
@Override
public void deserializeInstance(SerializationStreamReader streamReader, RadianBearingImpl instance)
throws SerializationException {
deserialize(streamReader, instance);
}
public static void deserialize(SerializationStreamReader streamReader, RadianBearingImpl instance) {
// Done by instantiateInstance
}
}
@@ -0,0 +1,57 @@
package com.google.gwt.user.client.rpc.core.com.sap.sse.datamining.shared.impl.dto;
import com.google.gwt.user.client.rpc.CustomFieldSerializer;
import com.google.gwt.user.client.rpc.SerializationException;
import com.google.gwt.user.client.rpc.SerializationStreamReader;
import com.google.gwt.user.client.rpc.SerializationStreamWriter;
import com.sap.sse.datamining.shared.impl.dto.ClusterDTO;
/**
* Ensures that the {@link ClusterDTO#getLocalizedName() localizedName} field is serialized by
* really evaluating it eagerly now; this way, an optional lazy evaluation function does not need
* to be serialized.
*
* @author Axel Uhl (d043530)
*
*/
public class ClusterDTO_CustomFieldSerializer extends CustomFieldSerializer<ClusterDTO> {
@Override
public void serializeInstance(SerializationStreamWriter streamWriter, ClusterDTO instance)
throws SerializationException {
serialize(streamWriter, instance);
}
public static void serialize(SerializationStreamWriter streamWriter, ClusterDTO instance)
throws SerializationException {
streamWriter.writeString(instance.getSignifier());
streamWriter.writeString(instance.getLocalizedName());
}
@Override
public boolean hasCustomInstantiateInstance() {
return true;
}
@Override
public ClusterDTO instantiateInstance(SerializationStreamReader streamReader)
throws SerializationException {
return instantiate(streamReader);
}
public static ClusterDTO instantiate(SerializationStreamReader streamReader)
throws SerializationException {
return new ClusterDTO(streamReader.readString(), streamReader.readString());
}
@Override
public void deserializeInstance(SerializationStreamReader streamReader, ClusterDTO instance)
throws SerializationException {
deserialize(streamReader, instance);
}
public static void deserialize(SerializationStreamReader streamReader, ClusterDTO instance) {
// Done by instantiateInstance
}
}
@@ -0,0 +1,68 @@
package com.google.gwt.user.client.rpc.core.com.sap.sse.datamining.shared.impl.dto;
import java.util.List;
import com.google.gwt.user.client.rpc.CustomFieldSerializer;
import com.google.gwt.user.client.rpc.SerializationException;
import com.google.gwt.user.client.rpc.SerializationStreamReader;
import com.google.gwt.user.client.rpc.SerializationStreamWriter;
import com.sap.sse.datamining.shared.impl.dto.FunctionDTO;
/**
* Ensures that the {@link FunctionDTO#getLocalizedName() localizedName} field is serialized by
* really evaluating it eagerly now; this way, an optional lazy evaluation function does not need
* to be serialized.
*
* @author Axel Uhl (d043530)
*
*/
public class FunctionDTO_CustomFieldSerializer extends CustomFieldSerializer<FunctionDTO> {
@Override
public void serializeInstance(SerializationStreamWriter streamWriter, FunctionDTO instance)
throws SerializationException {
serialize(streamWriter, instance);
}
public static void serialize(SerializationStreamWriter streamWriter, FunctionDTO instance)
throws SerializationException {
streamWriter.writeBoolean(instance.isDimension());
streamWriter.writeString(instance.getFunctionName());
streamWriter.writeString(instance.getSourceTypeName());
streamWriter.writeString(instance.getReturnTypeName());
streamWriter.writeObject(instance.getParameterTypeNames());
streamWriter.writeString(instance.getDisplayName());
streamWriter.writeInt(instance.getOrdinal());
}
@Override
public boolean hasCustomInstantiateInstance() {
return true;
}
@Override
public FunctionDTO instantiateInstance(SerializationStreamReader streamReader)
throws SerializationException {
return instantiate(streamReader);
}
@SuppressWarnings("unchecked") // the cast to List<String> is the problem here
public static FunctionDTO instantiate(SerializationStreamReader streamReader)
throws SerializationException {
return new FunctionDTO(/* isDimension */ streamReader.readBoolean(), /* function name */ streamReader.readString(),
/* source type name */ streamReader.readString(), /* return type name */ streamReader.readString(),
/* parameter type names */ (List<String>) streamReader.readObject(), /* display name */ streamReader.readString(),
/* ordinal */ streamReader.readInt());
}
@Override
public void deserializeInstance(SerializationStreamReader streamReader, FunctionDTO instance)
throws SerializationException {
deserialize(streamReader, instance);
}
public static void deserialize(SerializationStreamReader streamReader, FunctionDTO instance) {
// Done by instantiateInstance
}
}
@@ -16,7 +16,7 @@ import com.sap.sailing.gwt.ui.client.AbstractSailingEntryPoint;
import com.sap.sailing.gwt.ui.client.RemoteServiceMappingConstants;
import com.sap.sailing.gwt.ui.datamining.execution.SimpleQueryRunner;
import com.sap.sailing.gwt.ui.datamining.presentation.TabbedResultsPresenter;
import com.sap.sailing.gwt.ui.datamining.selection.BufferingQueryDefinitionProviderWithControls;
import com.sap.sailing.gwt.ui.datamining.selection.QueryDefinitionProviderWithControls;
import com.sap.sse.datamining.shared.DataMiningSession;
import com.sap.sse.datamining.shared.impl.UUIDDataMiningSession;
import com.sap.sse.gwt.client.EntryPointHelper;
@@ -58,8 +58,8 @@ public class DataMiningEntryPoint extends AbstractSailingEntryPoint {
ResultsPresenter<?> resultsPresenter = new TabbedResultsPresenter(null, null, getStringMessages());
DockLayoutPanel selectionDockPanel = new DockLayoutPanel(Unit.PX);
BufferingQueryDefinitionProviderWithControls queryDefinitionProviderWithControls =
new BufferingQueryDefinitionProviderWithControls(null, null, session, getStringMessages(),
QueryDefinitionProviderWithControls queryDefinitionProviderWithControls =
new QueryDefinitionProviderWithControls(null, null, session, getStringMessages(),
dataMiningService, DataMiningEntryPoint.this, settingsControl, resultsPresenter);
queryDefinitionProviderWithControls.getEntryWidget().addStyleName("dataMiningPanel");
selectionDockPanel.add(queryDefinitionProviderWithControls.getEntryWidget());
@@ -68,7 +68,11 @@ public class DataMiningEntryPoint extends AbstractSailingEntryPoint {
dataMiningService,
DataMiningEntryPoint.this, queryDefinitionProviderWithControls, resultsPresenter);
queryDefinitionProviderWithControls.addControl(queryRunner.getEntryWidget());
settingsControl.addSettingsComponent(queryRunner);
/* Running queries automatically when they've been changed is currently unnecessary, if not even counterproductive.
* This removes the query runner settings to prevent that the user can enable the automatic execution of queries.
* Re-enable this, when this functionality is desired again.
*/
// settingsControl.addSettingsComponent(queryRunner);
SplitLayoutPanel splitPanel = new SplitLayoutPanel(15);
splitPanel.addSouth(resultsPresenter.getEntryWidget(), 350);
@@ -84,4 +88,4 @@ public class DataMiningEntryPoint extends AbstractSailingEntryPoint {
rootPanel.add(panel);
}
}
}
@@ -26,8 +26,8 @@ public interface DataMiningService extends RemoteService {
HashSet<FunctionDTO> getStatisticsFor(DataRetrieverChainDefinitionDTO retrieverChainDefinition, String localeInfoName);
HashSet<AggregationProcessorDefinitionDTO> getAggregatorDefinitionsFor(FunctionDTO extractionFunction, String localeInfoName);
HashSet<FunctionDTO> getDimensionsFor(FunctionDTO statisticToCalculate, String localeInfoName);
HashSet<FunctionDTO> getDimensionsFor(DataRetrieverChainDefinitionDTO dataRetrieverChainDefinitionDTO, String localeInfoName);
HashMap<DataRetrieverLevelDTO, HashSet<FunctionDTO>> getDimensionsMappedByLevelFor(
DataRetrieverChainDefinitionDTO dataRetrieverChainDefinitionDTO, String localeInfoName);
HashMap<DataRetrieverLevelDTO, HashSet<FunctionDTO>> getReducedDimensionsMappedByLevelFor(
@@ -30,7 +30,7 @@ public interface DataMiningServiceAsync {
void getAggregatorDefinitionsFor(FunctionDTO extractionFunction, String localeInfoName,
AsyncCallback<HashSet<AggregationProcessorDefinitionDTO>> asyncCallback);
void getDimensionsFor(FunctionDTO statisticToCalculate, String localeInfoName, AsyncCallback<HashSet<FunctionDTO>> callback);
void getDimensionsFor(DataRetrieverChainDefinitionDTO dataRetrieverChainDefinitionDTO, String localeInfoName, AsyncCallback<HashSet<FunctionDTO>> callback);
void getDimensionsMappedByLevelFor(DataRetrieverChainDefinitionDTO dataRetrieverChainDefinitionDTO, String localeInfoName,
AsyncCallback<HashMap<DataRetrieverLevelDTO, HashSet<FunctionDTO>>> callback);
public void getReducedDimensionsMappedByLevelFor(DataRetrieverChainDefinitionDTO dataRetrieverChainDefinitionDTO, String localeInfoName,
@@ -6,7 +6,7 @@ import com.sap.sse.common.settings.SerializableSettings;
import com.sap.sse.datamining.shared.dto.StatisticQueryDefinitionDTO;
import com.sap.sse.datamining.shared.impl.dto.FunctionDTO;
public interface GroupingProvider extends DataMiningComponentProvider<SerializableSettings>, StatisticChangedListener{
public interface GroupingProvider extends DataMiningComponentProvider<SerializableSettings>, DataRetrieverChainDefinitionChangedListener {
public Collection<FunctionDTO> getDimensionsToGroupBy();
public String getCustomGrouperScriptText();
@@ -2,9 +2,11 @@ package com.sap.sailing.gwt.ui.datamining.execution;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.user.client.Timer;
import com.google.gwt.user.client.ui.Button;
import com.google.gwt.user.client.ui.Widget;
import com.sap.sailing.gwt.ui.client.StringMessages;
import com.sap.sailing.gwt.ui.datamining.DataMiningService;
import com.sap.sailing.gwt.ui.datamining.DataMiningServiceAsync;
import com.sap.sailing.gwt.ui.datamining.ManagedDataMiningQueriesCounter;
import com.sap.sailing.gwt.ui.datamining.QueryDefinitionProvider;
@@ -23,12 +25,29 @@ import com.sap.sse.gwt.client.shared.perspective.ComponentContext;
public class SimpleQueryRunner extends AbstractComponent<QueryRunnerSettings> implements QueryRunner {
/**
* The delay before a query is sent to the {@link DataMiningService}.
*
* @see #queryReleaseTimer
*/
private static final int queryBufferTimeInMillis = 200;
private final DataMiningSession session;
private final StringMessages stringMessages;
private final DataMiningServiceAsync dataMiningService;
private final ErrorReporter errorReporter;
private final ManagedDataMiningQueriesCounter counter;
/**
* Timer to prevent the execution of unnecessary queries, when they're run
* automatically (see {@link QueryRunnerSettings}). This can be caused by
* a change of the used data type, that then causes a change of the
* dimension to group by and the data retriever chain. Or caused by quick
* changes of the filter selection.
*
* @see #queryBufferTimeInMillis
*/
private final Timer queryReleaseTimer;
private QueryRunnerSettings settings;
private final QueryDefinitionProvider<?> queryDefinitionProvider;
private final ResultsPresenter<?> resultsPresenter;
@@ -56,7 +75,13 @@ public class SimpleQueryRunner extends AbstractComponent<QueryRunnerSettings> im
run(SimpleQueryRunner.this.queryDefinitionProvider.getQueryDefinition());
}
});
queryReleaseTimer = new Timer() {
@Override
public void run() {
SimpleQueryRunner.this.run(queryDefinitionProvider.getQueryDefinition());
}
};
if (this.settings.isRunAutomatically()) {
queryDefinitionProvider.addQueryDefinitionChangedListener(this);
}
@@ -98,7 +123,8 @@ public class SimpleQueryRunner extends AbstractComponent<QueryRunnerSettings> im
@Override
public void queryDefinitionChanged(StatisticQueryDefinitionDTO newQueryDefinition) {
run(newQueryDefinition);
// See javadoc of queryReleaseTimer
queryReleaseTimer.schedule(queryBufferTimeInMillis);
}
@Override
@@ -7,9 +7,11 @@ import java.util.Map;
import com.google.gwt.core.client.Scheduler;
import com.google.gwt.core.client.Scheduler.ScheduledCommand;
import com.sap.sailing.domain.common.Bearing;
import com.sap.sailing.domain.common.Distance;
import com.sap.sailing.gwt.ui.client.StringMessages;
import com.sap.sailing.gwt.ui.datamining.presentation.dataproviders.AbstractResultDataProvider;
import com.sap.sailing.gwt.ui.datamining.presentation.dataproviders.BearingDataProvider;
import com.sap.sailing.gwt.ui.datamining.presentation.dataproviders.DistanceDataProvider;
import com.sap.sailing.gwt.ui.datamining.presentation.dataproviders.DurationDataProvider;
import com.sap.sailing.gwt.ui.datamining.presentation.dataproviders.NumberDataProvider;
@@ -35,6 +37,8 @@ public abstract class AbstractResultsPresenterWithDataProviders<SettingsType ext
dataProviders.put(distanceDataProvider.getResultType().getName(), distanceDataProvider);
AbstractResultDataProvider<Duration> durationDataProvider = new DurationDataProvider();
dataProviders.put(durationDataProvider.getResultType().getName(), durationDataProvider);
AbstractResultDataProvider<Bearing> bearingDataProvider = new BearingDataProvider();
dataProviders.put(bearingDataProvider.getResultType().getName(), bearingDataProvider);
}
protected void internalShowResults(QueryResultDTO<?> result) {
@@ -0,0 +1,29 @@
package com.sap.sailing.gwt.ui.datamining.presentation.dataproviders;
import java.util.LinkedHashMap;
import java.util.function.Function;
import com.sap.sailing.domain.common.Bearing;
import com.sap.sse.datamining.shared.impl.dto.QueryResultDTO;
public class BearingDataProvider extends AbstractDataProvider<Bearing> {
private static final String DEGREES = "Angle in Degrees";
private static final String RADIANS = "Angle in Radians";
public BearingDataProvider() {
super(Bearing.class, getMappings());
}
private static LinkedHashMap<String, Function<Bearing, Number>> getMappings() {
LinkedHashMap<String, Function<Bearing, Number>> mappings = new LinkedHashMap<>();
mappings.put(DEGREES, bearing->bearing.getDegrees());
mappings.put(RADIANS, bearing->bearing.getRadians());
return mappings;
}
@Override
public String getDefaultDataKeyFor(QueryResultDTO<?> result) {
return DEGREES;
}
}
@@ -4,22 +4,36 @@ import java.util.LinkedHashMap;
import java.util.function.Function;
import com.sap.sailing.domain.common.Distance;
import com.sap.sse.datamining.shared.impl.dto.QueryResultDTO;
public class DistanceDataProvider extends AbstractDataProvider<Distance> {
private static final String CENTRAL_ANGLE_RADIAN = "Central Angle Radian";
private static final String CENTRAL_ANGLE_DEGREE = "Central Angle Degree";
private static final String KILOMETERS = "Kilometers";
private static final String METERS = "Meters";
private static final String NAUTICAL_MILES = "Nautical Miles";
private static final String SEA_MILES = "Sea Miles";
private static final String GEOGRAPHICAL_MILES = "Geographical Miles";
public DistanceDataProvider() {
super(Distance.class, getMappings());
}
private static LinkedHashMap<String, Function<Distance, Number>> getMappings() {
LinkedHashMap<String, Function<Distance, Number>> mappings = new LinkedHashMap<>();
mappings.put("Geographical Miles", distance->distance.getGeographicalMiles());
mappings.put("Sea Miles", distance->distance.getSeaMiles());
mappings.put("Nautical Miles", distance->distance.getNauticalMiles());
mappings.put("Meters", distance->distance.getMeters());
mappings.put("Kilometers", distance->distance.getKilometers());
mappings.put("Central Angle Degree", distance->distance.getCentralAngleDeg());
mappings.put("Central Angle Radian", distance->distance.getCentralAngleRad());
mappings.put(GEOGRAPHICAL_MILES, distance->distance.getGeographicalMiles());
mappings.put(SEA_MILES, distance->distance.getSeaMiles());
mappings.put(NAUTICAL_MILES, distance->distance.getNauticalMiles());
mappings.put(METERS, distance->distance.getMeters());
mappings.put(KILOMETERS, distance->distance.getKilometers());
mappings.put(CENTRAL_ANGLE_DEGREE, distance->distance.getCentralAngleDeg());
mappings.put(CENTRAL_ANGLE_RADIAN, distance->distance.getCentralAngleRad());
return mappings;
}
@Override
public String getDefaultDataKeyFor(QueryResultDTO<?> result) {
return METERS;
}
}
@@ -1,280 +1,279 @@
package com.sap.sailing.gwt.ui.datamining.selection;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Objects;
import java.util.Set;
import com.google.gwt.event.logical.shared.ValueChangeEvent;
import com.google.gwt.event.logical.shared.ValueChangeHandler;
import com.google.gwt.i18n.client.LocaleInfo;
import com.google.gwt.user.client.rpc.AsyncCallback;
import com.google.gwt.user.client.ui.FlowPanel;
import com.google.gwt.user.client.ui.Label;
import com.google.gwt.user.client.ui.ValueListBox;
import com.google.gwt.user.client.ui.Widget;
import com.sap.sailing.gwt.ui.client.StringMessages;
import com.sap.sailing.gwt.ui.client.shared.controls.AbstractObjectRenderer;
import com.sap.sailing.gwt.ui.datamining.DataMiningServiceAsync;
import com.sap.sailing.gwt.ui.datamining.GroupingChangedListener;
import com.sap.sailing.gwt.ui.datamining.GroupingProvider;
import com.sap.sailing.gwt.ui.datamining.StatisticProvider;
import com.sap.sse.common.settings.SerializableSettings;
import com.sap.sse.datamining.shared.dto.StatisticQueryDefinitionDTO;
import com.sap.sse.datamining.shared.impl.dto.AggregationProcessorDefinitionDTO;
import com.sap.sse.datamining.shared.impl.dto.FunctionDTO;
import com.sap.sse.gwt.client.ErrorReporter;
import com.sap.sse.gwt.client.shared.components.AbstractComponent;
import com.sap.sse.gwt.client.shared.components.Component;
import com.sap.sse.gwt.client.shared.components.SettingsDialogComponent;
import com.sap.sse.gwt.client.shared.perspective.ComponentContext;
public class MultiDimensionalGroupingProvider extends AbstractComponent<SerializableSettings> implements GroupingProvider {
private static final String GROUPING_PROVIDER_ELEMENT_STYLE = "groupingProviderElement";
private final StringMessages stringMessages;
private final DataMiningServiceAsync dataMiningService;
private final ErrorReporter errorReporter;
private final Set<GroupingChangedListener> listeners;
private final FlowPanel mainPanel;
private final List<ValueListBox<FunctionDTO>> dimensionToGroupByBoxes;
private boolean isAwaitingReload;
private FunctionDTO currentStatisticToCalculate;
private final List<FunctionDTO> availableDimensions;
public MultiDimensionalGroupingProvider(Component<?> parent, ComponentContext<?, ?> context,
StringMessages stringMessages,
DataMiningServiceAsync dataMiningService, ErrorReporter errorReporter,
StatisticProvider statisticProvider) {
super(parent, context);
this.stringMessages = stringMessages;
this.dataMiningService = dataMiningService;
this.errorReporter = errorReporter;
listeners = new HashSet<GroupingChangedListener>();
currentStatisticToCalculate = null;
availableDimensions = new ArrayList<>();
isAwaitingReload = false;
dimensionToGroupByBoxes = new ArrayList<ValueListBox<FunctionDTO>>();
mainPanel = new FlowPanel();
Label groupByLabel = new Label(this.stringMessages.groupBy());
groupByLabel.addStyleName(GROUPING_PROVIDER_ELEMENT_STYLE);
mainPanel.add(groupByLabel);
ValueListBox<FunctionDTO> firstDimensionToGroupByBox = createDimensionToGroupByBox();
addDimensionToGroupByBoxAndUpdateAcceptableValues(firstDimensionToGroupByBox);
statisticProvider.addStatisticChangedListener(this);
}
@Override
public void awaitReloadComponents() {
isAwaitingReload = true;
}
@Override
public boolean isAwatingReload() {
return isAwaitingReload;
}
@Override
public void reloadComponents() {
isAwaitingReload = false;
updateAvailableDimensions();
}
@Override
public void statisticChanged(FunctionDTO newStatisticToCalculate, AggregationProcessorDefinitionDTO newAggregatorDefinition) {
if (!Objects.equals(currentStatisticToCalculate, newStatisticToCalculate)) {
currentStatisticToCalculate = newStatisticToCalculate;
if (!isAwaitingReload) {
updateAvailableDimensions();
}
}
}
private void updateAvailableDimensions() {
if (currentStatisticToCalculate != null) {
dataMiningService.getDimensionsFor(currentStatisticToCalculate, LocaleInfo.getCurrentLocale()
.getLocaleName(), new AsyncCallback<HashSet<FunctionDTO>>() {
@Override
public void onSuccess(HashSet<FunctionDTO> dimensions) {
clearAvailableDimensionsAndGroupByBoxes();
for (FunctionDTO dimension : dimensions) {
availableDimensions.add(dimension);
}
ValueListBox<FunctionDTO> firstDimensionToGroupByBox = createDimensionToGroupByBox();
addDimensionToGroupByBoxAndUpdateAcceptableValues(firstDimensionToGroupByBox);
if (!availableDimensions.isEmpty()) {
Collections.sort(availableDimensions);
firstDimensionToGroupByBox.setValue(availableDimensions.iterator().next(), true);
} else {
notifyListeners();
}
}
@Override
public void onFailure(Throwable caught) {
errorReporter.reportError("Error fetching the dimensions from the server: " + caught.getMessage());
}
});
} else {
clearAvailableDimensionsAndGroupByBoxes();
ValueListBox<FunctionDTO> firstDimensionToGroupByBox = createDimensionToGroupByBox();
addDimensionToGroupByBoxAndUpdateAcceptableValues(firstDimensionToGroupByBox);
}
}
private void clearAvailableDimensionsAndGroupByBoxes() {
for (ValueListBox<FunctionDTO> dimensionToGroupByBox : dimensionToGroupByBoxes) {
mainPanel.remove(dimensionToGroupByBox);
}
dimensionToGroupByBoxes.clear();
availableDimensions.clear();
}
private ValueListBox<FunctionDTO> createDimensionToGroupByBox() {
ValueListBox<FunctionDTO> dimensionToGroupByBox = new ValueListBox<FunctionDTO>(new AbstractObjectRenderer<FunctionDTO>() {
@Override
protected String convertObjectToString(FunctionDTO function) {
return function.getDisplayName();
}
});
dimensionToGroupByBox.addStyleName(GROUPING_PROVIDER_ELEMENT_STYLE);
dimensionToGroupByBox.addValueChangeHandler(new ValueChangeHandler<FunctionDTO>() {
private boolean firstChange = true;
@Override
public void onValueChange(ValueChangeEvent<FunctionDTO> event) {
if (firstChange && event.getValue() != null) {
ValueListBox<FunctionDTO> newDimensionToGroupByBox = createDimensionToGroupByBox();
addDimensionToGroupByBox(newDimensionToGroupByBox);
firstChange = false;
} else if (event.getValue() == null) {
Widget changedDimensionToGroupByBox = (Widget) event.getSource();
mainPanel.remove(changedDimensionToGroupByBox);
dimensionToGroupByBoxes.remove(changedDimensionToGroupByBox);
}
updateAcceptableValues();
notifyListeners();
}
});
return dimensionToGroupByBox;
}
private void addDimensionToGroupByBoxAndUpdateAcceptableValues(ValueListBox<FunctionDTO> dimensionToGroupByBox) {
addDimensionToGroupByBox(dimensionToGroupByBox);
updateAcceptableValues();
}
private void addDimensionToGroupByBox(ValueListBox<FunctionDTO> dimensionToGroupByBox) {
mainPanel.add(dimensionToGroupByBox);
dimensionToGroupByBoxes.add(dimensionToGroupByBox);
}
private void updateAcceptableValues() {
for (ValueListBox<FunctionDTO> dimensionToGroupByBox : dimensionToGroupByBoxes) {
List<FunctionDTO> acceptableValues = new ArrayList<FunctionDTO>(availableDimensions);
acceptableValues.removeAll(getDimensionsToGroupBy());
if (dimensionToGroupByBox.getValue() != null) {
acceptableValues.add(dimensionToGroupByBox.getValue());
}
Collections.sort(acceptableValues);
acceptableValues.add(null);
dimensionToGroupByBox.setAcceptableValues(acceptableValues);
}
}
@Override
public Collection<FunctionDTO> getDimensionsToGroupBy() {
Collection<FunctionDTO> dimensionsToGroupBy = new ArrayList<FunctionDTO>();
for (ValueListBox<FunctionDTO> dimensionListBox : dimensionToGroupByBoxes) {
if (dimensionListBox.getValue() != null) {
dimensionsToGroupBy.add(dimensionListBox.getValue());
}
}
return dimensionsToGroupBy;
}
@Override
public String getCustomGrouperScriptText() {
return "";
}
@Override
public void applyQueryDefinition(StatisticQueryDefinitionDTO queryDefinition) {
int index = 0;
for (FunctionDTO dimension : queryDefinition.getDimensionsToGroupBy()) {
dimensionToGroupByBoxes.get(index).setValue(dimension, true);
index++;
}
}
@Override
public void addGroupingChangedListener(GroupingChangedListener listener) {
listeners.add(listener);
}
private void notifyListeners() {
for (GroupingChangedListener listener : listeners) {
listener.groupingChanged();
}
}
@Override
public String getLocalizedShortName() {
return stringMessages.groupingProvider();
}
@Override
public Widget getEntryWidget() {
return mainPanel;
}
@Override
public boolean isVisible() {
return mainPanel.isVisible();
}
@Override
public void setVisible(boolean visibility) {
mainPanel.setVisible(visibility);
}
@Override
public boolean hasSettings() {
return false;
}
@Override
public SettingsDialogComponent<SerializableSettings> getSettingsDialogComponent() {
return null;
}
@Override
public void updateSettings(SerializableSettings newSettings) {
// no-op
}
@Override
public String getDependentCssClassName() {
return "multiDimensionalGroupingProvider";
}
@Override
public SerializableSettings getSettings() {
return null;
}
@Override
public String getId() {
return "MultiDimensionalGroupingProvider";
}
}
package com.sap.sailing.gwt.ui.datamining.selection;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Objects;
import java.util.Set;
import com.google.gwt.event.logical.shared.ValueChangeEvent;
import com.google.gwt.event.logical.shared.ValueChangeHandler;
import com.google.gwt.i18n.client.LocaleInfo;
import com.google.gwt.user.client.rpc.AsyncCallback;
import com.google.gwt.user.client.ui.FlowPanel;
import com.google.gwt.user.client.ui.Label;
import com.google.gwt.user.client.ui.ValueListBox;
import com.google.gwt.user.client.ui.Widget;
import com.sap.sailing.gwt.ui.client.StringMessages;
import com.sap.sailing.gwt.ui.client.shared.controls.AbstractObjectRenderer;
import com.sap.sailing.gwt.ui.datamining.DataMiningServiceAsync;
import com.sap.sailing.gwt.ui.datamining.DataRetrieverChainDefinitionProvider;
import com.sap.sailing.gwt.ui.datamining.GroupingChangedListener;
import com.sap.sailing.gwt.ui.datamining.GroupingProvider;
import com.sap.sse.common.settings.SerializableSettings;
import com.sap.sse.datamining.shared.dto.StatisticQueryDefinitionDTO;
import com.sap.sse.datamining.shared.impl.dto.DataRetrieverChainDefinitionDTO;
import com.sap.sse.datamining.shared.impl.dto.FunctionDTO;
import com.sap.sse.gwt.client.ErrorReporter;
import com.sap.sse.gwt.client.shared.components.AbstractComponent;
import com.sap.sse.gwt.client.shared.components.Component;
import com.sap.sse.gwt.client.shared.components.SettingsDialogComponent;
import com.sap.sse.gwt.client.shared.perspective.ComponentContext;
public class MultiDimensionalGroupingProvider extends AbstractComponent<SerializableSettings>
implements GroupingProvider {
private static final String GROUPING_PROVIDER_ELEMENT_STYLE = "groupingProviderElement";
private final StringMessages stringMessages;
private final DataMiningServiceAsync dataMiningService;
private final ErrorReporter errorReporter;
private final Set<GroupingChangedListener> listeners;
private final FlowPanel mainPanel;
private final List<ValueListBox<FunctionDTO>> dimensionToGroupByBoxes;
private boolean isAwaitingReload;
private DataRetrieverChainDefinitionDTO currentRetrieverChainDefinition;
private final List<FunctionDTO> availableDimensions;
public MultiDimensionalGroupingProvider(Component<?> parent, ComponentContext<?, ?> context,StringMessages stringMessages, DataMiningServiceAsync dataMiningService, ErrorReporter errorReporter,
DataRetrieverChainDefinitionProvider retrieverChainProvider) {
super(parent, context);
this.stringMessages = stringMessages;
this.dataMiningService = dataMiningService;
this.errorReporter = errorReporter;
listeners = new HashSet<GroupingChangedListener>();
currentRetrieverChainDefinition = null;
availableDimensions = new ArrayList<>();
isAwaitingReload = false;
dimensionToGroupByBoxes = new ArrayList<ValueListBox<FunctionDTO>>();
mainPanel = new FlowPanel();
Label groupByLabel = new Label(this.stringMessages.groupBy());
groupByLabel.addStyleName(GROUPING_PROVIDER_ELEMENT_STYLE);
mainPanel.add(groupByLabel);
ValueListBox<FunctionDTO> firstDimensionToGroupByBox = createDimensionToGroupByBox();
addDimensionToGroupByBoxAndUpdateAcceptableValues(firstDimensionToGroupByBox);
retrieverChainProvider.addDataRetrieverChainDefinitionChangedListener(this);
}
@Override
public void awaitReloadComponents() {
isAwaitingReload = true;
}
@Override
public boolean isAwatingReload() {
return isAwaitingReload;
}
@Override
public void reloadComponents() {
isAwaitingReload = false;
updateAvailableDimensions();
}
@Override
public void dataRetrieverChainDefinitionChanged(DataRetrieverChainDefinitionDTO newRetrieverChainDefinition) {
if (!Objects.equals(currentRetrieverChainDefinition, newRetrieverChainDefinition)) {
currentRetrieverChainDefinition = newRetrieverChainDefinition;
if (!isAwaitingReload) {
updateAvailableDimensions();
}
}
}
private void updateAvailableDimensions() {
if (currentRetrieverChainDefinition != null) {
dataMiningService.getDimensionsFor(currentRetrieverChainDefinition, LocaleInfo.getCurrentLocale()
.getLocaleName(), new AsyncCallback<HashSet<FunctionDTO>>() {
@Override
public void onSuccess(HashSet<FunctionDTO> dimensions) {
clearAvailableDimensionsAndGroupByBoxes();
for (FunctionDTO dimension : dimensions) {
availableDimensions.add(dimension);
}
ValueListBox<FunctionDTO> firstDimensionToGroupByBox = createDimensionToGroupByBox();
addDimensionToGroupByBoxAndUpdateAcceptableValues(firstDimensionToGroupByBox);
if (!availableDimensions.isEmpty()) {
Collections.sort(availableDimensions);
firstDimensionToGroupByBox.setValue(availableDimensions.iterator().next(), true);
} else {
notifyListeners();
}
}
@Override
public void onFailure(Throwable caught) {
errorReporter.reportError("Error fetching the dimensions from the server: " + caught.getMessage());
}
});
} else {
clearAvailableDimensionsAndGroupByBoxes();
ValueListBox<FunctionDTO> firstDimensionToGroupByBox = createDimensionToGroupByBox();
addDimensionToGroupByBoxAndUpdateAcceptableValues(firstDimensionToGroupByBox);
}
}
private void clearAvailableDimensionsAndGroupByBoxes() {
for (ValueListBox<FunctionDTO> dimensionToGroupByBox : dimensionToGroupByBoxes) {
mainPanel.remove(dimensionToGroupByBox);
}
dimensionToGroupByBoxes.clear();
availableDimensions.clear();
}
private ValueListBox<FunctionDTO> createDimensionToGroupByBox() {
ValueListBox<FunctionDTO> dimensionToGroupByBox = new ValueListBox<FunctionDTO>(new AbstractObjectRenderer<FunctionDTO>() {
@Override
protected String convertObjectToString(FunctionDTO function) {
return function.getDisplayName();
}
});
dimensionToGroupByBox.addStyleName(GROUPING_PROVIDER_ELEMENT_STYLE);
dimensionToGroupByBox.addValueChangeHandler(new ValueChangeHandler<FunctionDTO>() {
private boolean firstChange = true;
@Override
public void onValueChange(ValueChangeEvent<FunctionDTO> event) {
if (firstChange && event.getValue() != null) {
ValueListBox<FunctionDTO> newDimensionToGroupByBox = createDimensionToGroupByBox();
addDimensionToGroupByBox(newDimensionToGroupByBox);
firstChange = false;
} else if (event.getValue() == null) {
Widget changedDimensionToGroupByBox = (Widget) event.getSource();
mainPanel.remove(changedDimensionToGroupByBox);
dimensionToGroupByBoxes.remove(changedDimensionToGroupByBox);
}
updateAcceptableValues();
notifyListeners();
}
});
return dimensionToGroupByBox;
}
private void addDimensionToGroupByBoxAndUpdateAcceptableValues(ValueListBox<FunctionDTO> dimensionToGroupByBox) {
addDimensionToGroupByBox(dimensionToGroupByBox);
updateAcceptableValues();
}
private void addDimensionToGroupByBox(ValueListBox<FunctionDTO> dimensionToGroupByBox) {
mainPanel.add(dimensionToGroupByBox);
dimensionToGroupByBoxes.add(dimensionToGroupByBox);
}
private void updateAcceptableValues() {
for (ValueListBox<FunctionDTO> dimensionToGroupByBox : dimensionToGroupByBoxes) {
List<FunctionDTO> acceptableValues = new ArrayList<FunctionDTO>(availableDimensions);
acceptableValues.removeAll(getDimensionsToGroupBy());
if (dimensionToGroupByBox.getValue() != null) {
acceptableValues.add(dimensionToGroupByBox.getValue());
}
Collections.sort(acceptableValues);
acceptableValues.add(null);
dimensionToGroupByBox.setAcceptableValues(acceptableValues);
}
}
@Override
public Collection<FunctionDTO> getDimensionsToGroupBy() {
Collection<FunctionDTO> dimensionsToGroupBy = new ArrayList<FunctionDTO>();
for (ValueListBox<FunctionDTO> dimensionListBox : dimensionToGroupByBoxes) {
if (dimensionListBox.getValue() != null) {
dimensionsToGroupBy.add(dimensionListBox.getValue());
}
}
return dimensionsToGroupBy;
}
@Override
public String getCustomGrouperScriptText() {
return "";
}
@Override
public void applyQueryDefinition(StatisticQueryDefinitionDTO queryDefinition) {
int index = 0;
for (FunctionDTO dimension : queryDefinition.getDimensionsToGroupBy()) {
dimensionToGroupByBoxes.get(index).setValue(dimension, true);
index++;
}
}
@Override
public void addGroupingChangedListener(GroupingChangedListener listener) {
listeners.add(listener);
}
private void notifyListeners() {
for (GroupingChangedListener listener : listeners) {
listener.groupingChanged();
}
}
@Override
public String getLocalizedShortName() {
return stringMessages.groupingProvider();
}
@Override
public Widget getEntryWidget() {
return mainPanel;
}
@Override
public boolean isVisible() {
return mainPanel.isVisible();
}
@Override
public void setVisible(boolean visibility) {
mainPanel.setVisible(visibility);
}
@Override
public boolean hasSettings() {
return false;
}
@Override
public SettingsDialogComponent<SerializableSettings> getSettingsDialogComponent() {
return null;
}
@Override
public void updateSettings(SerializableSettings newSettings) {
// no-op
}
@Override
public String getDependentCssClassName() {
return "multiDimensionalGroupingProvider";
}
@Override
public SerializableSettings getSettings() {
return null;
}
@Override
public String getId() {
return "MultiDimensionalGroupingProvider";
}
}
@@ -11,7 +11,6 @@ import com.google.gwt.dom.client.Style.Unit;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.i18n.client.LocaleInfo;
import com.google.gwt.user.client.Timer;
import com.google.gwt.user.client.ui.Button;
import com.google.gwt.user.client.ui.DockLayoutPanel;
import com.google.gwt.user.client.ui.FlowPanel;
@@ -51,21 +50,11 @@ import com.sap.sse.gwt.client.shared.components.Component;
import com.sap.sse.gwt.client.shared.components.SettingsDialogComponent;
import com.sap.sse.gwt.client.shared.perspective.ComponentContext;
public class BufferingQueryDefinitionProviderWithControls extends AbstractQueryDefinitionProvider<AdvancedDataMiningSettings> implements WithControls {
/**
* The delay before a changed query definition is submitted to the listeners.
* This prevents unnecessary queries caused by a change of the used data type, that then causes
* a change of the dimension to group by and the data retriever chain.
* Or caused by quick changes of the filter selection.
*/
private static final int queryBufferTimeInMillis = 200;
public class QueryDefinitionProviderWithControls extends AbstractQueryDefinitionProvider<AdvancedDataMiningSettings> implements WithControls {
private static final double headerPanelHeight = 45;
private static final double footerPanelHeight = 50;
private final Timer queryDefinitionReleaseTimer;
private final DockLayoutPanel mainPanel;
private final FlowPanel controlsPanel;
private final ToggleButton queryDefinitionViewerToggleButton;
@@ -82,19 +71,12 @@ public class BufferingQueryDefinitionProviderWithControls extends AbstractQueryD
private final SplitLayoutPanel filterSplitPanel;
private final FilterSelectionProvider filterSelectionProvider;
public BufferingQueryDefinitionProviderWithControls(Component<?> parent, ComponentContext<?, ?> context,
DataMiningSession session,
StringMessages stringMessages,
public QueryDefinitionProviderWithControls(Component<?> parent, ComponentContext<?, ?> context,
DataMiningSession session, StringMessages stringMessages,
DataMiningServiceAsync dataMiningService, ErrorReporter errorReporter, DataMiningSettingsControl settingsControl,
ResultsPresenter<?> resultsPresenter) {
super(parent, context, stringMessages, dataMiningService, errorReporter);
providerListener = new ProviderListener();
queryDefinitionReleaseTimer = new Timer() {
@Override
public void run() {
notifyQueryDefinitionChanged();
}
};
// Creating the header panel, that contains the retriever chain provider and the controls
controlsPanel = new FlowPanel();
@@ -111,11 +93,10 @@ public class BufferingQueryDefinitionProviderWithControls extends AbstractQueryD
filterSplitPanel.setWidgetHidden(queryDefinitionViewer.getEntryWidget(), !queryDefinitionViewerToggleButton.getValue());
}
});
queryDefinitionViewer = new QueryDefinitionViewer(this, context, getStringMessages());
queryDefinitionViewer = new QueryDefinitionViewer(parent, context, getStringMessages());
addQueryDefinitionChangedListener(queryDefinitionViewer);
predefinedQueryRunner = new PredefinedQueryRunner(this, context, session, getStringMessages(),
dataMiningService,
errorReporter, resultsPresenter);
predefinedQueryRunner = new PredefinedQueryRunner(parent, context, session, getStringMessages(),
dataMiningService, errorReporter, resultsPresenter);
Button clearSelectionButton = new Button(this.getStringMessages().clearSelection());
clearSelectionButton.addClickHandler(new ClickHandler() {
@@ -140,7 +121,7 @@ public class BufferingQueryDefinitionProviderWithControls extends AbstractQueryD
addControl(predefinedQueryRunner.getEntryWidget());
}
retrieverChainProvider = new SimpleDataRetrieverChainDefinitionProvider(this, context, getStringMessages(),
retrieverChainProvider = new SimpleDataRetrieverChainDefinitionProvider(parent, context, getStringMessages(),
getDataMiningService(), getErrorReporter(), settingsControl);
retrieverChainProvider.addDataRetrieverChainDefinitionChangedListener(providerListener);
@@ -149,13 +130,12 @@ public class BufferingQueryDefinitionProviderWithControls extends AbstractQueryD
headerPanel.add(controlsPanel);
// Creating the footer panel, that contains the statistic provider and the grouping provider
statisticProvider = new SimpleStatisticProvider(this, context, getStringMessages(), getDataMiningService(),
statisticProvider = new SimpleStatisticProvider(parent, context, getStringMessages(), getDataMiningService(),
getErrorReporter(), retrieverChainProvider);
statisticProvider.addStatisticChangedListener(providerListener);
groupingProvider = new MultiDimensionalGroupingProvider(this, context, getStringMessages(),
getDataMiningService(),
getErrorReporter(), statisticProvider);
groupingProvider = new MultiDimensionalGroupingProvider(parent, context, getStringMessages(),
getDataMiningService(), getErrorReporter(), retrieverChainProvider);
groupingProvider.addGroupingChangedListener(providerListener);
SplitLayoutPanel footerPanel = new SplitLayoutPanel(15);
@@ -167,8 +147,8 @@ public class BufferingQueryDefinitionProviderWithControls extends AbstractQueryD
filterSplitPanel.addSouth(footerPanel, footerPanelHeight);
filterSplitPanel.addEast(queryDefinitionViewer.getEntryWidget(), 600);
filterSplitPanel.setWidgetHidden(queryDefinitionViewer.getEntryWidget(), true);
filterSelectionProvider = new ListRetrieverChainFilterSelectionProvider(this, context, session, stringMessages,
dataMiningService, errorReporter, retrieverChainProvider);
filterSelectionProvider = new ListRetrieverChainFilterSelectionProvider(parent, context, session,
stringMessages, dataMiningService, errorReporter, retrieverChainProvider);
filterSelectionProvider.addSelectionChangedListener(providerListener);
filterSplitPanel.add(filterSelectionProvider.getEntryWidget());
@@ -182,10 +162,9 @@ public class BufferingQueryDefinitionProviderWithControls extends AbstractQueryD
providers.add(statisticProvider);
providers.add(groupingProvider);
providers.add(filterSelectionProvider);
}
private void scheduleQueryDefinitionChanged() {
queryDefinitionReleaseTimer.schedule(queryBufferTimeInMillis);
// Set await reload flag to initialize the components, when the retriever chains have been loaded
providers.forEach(provider -> provider.awaitReloadComponents());
}
@Override
@@ -241,7 +220,7 @@ public class BufferingQueryDefinitionProviderWithControls extends AbstractQueryD
filterSelectionProvider.applySelection(queryDefinition);
setBlockChangeNotification(false);
scheduleQueryDefinitionChanged();
notifyQueryDefinitionChanged();
}
@Override
@@ -316,38 +295,40 @@ public class BufferingQueryDefinitionProviderWithControls extends AbstractQueryD
@Override
public void statisticChanged(FunctionDTO newStatisticToCalculate, AggregationProcessorDefinitionDTO newAggregatorDefinition) {
if (isAwatingReload()) {
groupingProvider.statisticChanged(statisticProvider.getStatisticToCalculate(), statisticProvider.getAggregatorDefinition());
groupingProvider.reloadComponents();
} else {
scheduleQueryDefinitionChanged();
if (!isAwatingReload()) {
notifyQueryDefinitionChanged();
}
}
@Override
public void groupingChanged() {
if (!isAwatingReload()) {
scheduleQueryDefinitionChanged();
notifyQueryDefinitionChanged();
}
}
@Override
public void dataRetrieverChainDefinitionChanged(DataRetrieverChainDefinitionDTO newDataRetrieverChainDefinition) {
if (isAwatingReload()) {
statisticProvider.dataRetrieverChainDefinitionChanged(retrieverChainProvider.getDataRetrieverChainDefinition());
statisticProvider.reloadComponents();
DataRetrieverChainDefinitionDTO retrieverChainDefinition = retrieverChainProvider.getDataRetrieverChainDefinition();
filterSelectionProvider.dataRetrieverChainDefinitionChanged(retrieverChainProvider.getDataRetrieverChainDefinition());
groupingProvider.dataRetrieverChainDefinitionChanged(retrieverChainDefinition);
groupingProvider.reloadComponents();
filterSelectionProvider.dataRetrieverChainDefinitionChanged(retrieverChainDefinition);
filterSelectionProvider.reloadComponents();
statisticProvider.dataRetrieverChainDefinitionChanged(retrieverChainDefinition);
statisticProvider.reloadComponents();
} else {
scheduleQueryDefinitionChanged();
notifyQueryDefinitionChanged();
}
}
@Override
public void selectionChanged() {
if (!isAwatingReload()) {
scheduleQueryDefinitionChanged();
notifyQueryDefinitionChanged();
}
}
@@ -355,7 +336,7 @@ public class BufferingQueryDefinitionProviderWithControls extends AbstractQueryD
@Override
public String getId() {
return "BufferingQueryDefinitionProviderWithControls";
return "QueryDefinitionProviderWithControls";
}
}
@@ -131,8 +131,6 @@ public class ListRetrieverChainFilterSelectionProvider extends AbstractComponent
} else if (!isAwaitingReload) {
clearContent();
}
} else if (retrieverChain != null && !isAwaitingReload) {
updateRetrievalLevels();
}
}
@@ -4,6 +4,8 @@ import java.util.Comparator;
import com.google.gwt.safehtml.shared.SafeHtmlBuilder;
import com.sap.sailing.domain.common.dto.LeaderboardRowDTO;
import com.sap.sailing.domain.common.impl.MeterDistance;
import com.sap.sailing.domain.common.tracking.BravoFix;
public class RideHeightQualityMinMaxRender extends MinMaxRenderer {
@@ -12,19 +14,23 @@ public class RideHeightQualityMinMaxRender extends MinMaxRenderer {
}
/**
* Renders the value of a {@link LeaderboardRowDTO}. Values greater than 1.26 are considered good,
* values lower than 0.74 are considered bad; anything in between is "OK".
* Renders the value of a {@link LeaderboardRowDTO}. Values greater than
* {@link BravoFix#MIN_FOILING_HEIGHT_THRESHOLD} are considered OK, values greater than that plus 0.2m are considered good,
* values below {@link BravoFix#MIN_FOILING_HEIGHT_THRESHOLD} are considered bad.
*/
@Override
protected void render(LeaderboardRowDTO row, String nullSafeValue, String nullSafeTitle, SafeHtmlBuilder sb) {
Double doubleValue = getValueProvider().getDoubleValue(row);
if (doubleValue != null) {
final String barStyle;
if (doubleValue > 1.26) barStyle = BACKGROUND_BAR_STYLE_GOOD;
else if (doubleValue >= 0.74) barStyle = BACKGROUND_BAR_STYLE_OK;
else barStyle = BACKGROUND_BAR_STYLE_BAD;
if (doubleValue > BravoFix.MIN_FOILING_HEIGHT_THRESHOLD.add(new MeterDistance(0.2)).getMeters()) {
barStyle = BACKGROUND_BAR_STYLE_GOOD;
} else if (doubleValue >= BravoFix.MIN_FOILING_HEIGHT_THRESHOLD.getMeters()) {
barStyle = BACKGROUND_BAR_STYLE_OK;
} else {
barStyle = BACKGROUND_BAR_STYLE_BAD;
}
sb.append(TEMPLATES.render(nullSafeValue, barStyle, nullSafeTitle, 100));
}
}
}
@@ -2,10 +2,13 @@ package com.sap.sailing.gwt.ui.server;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Locale;
import java.util.Map;
@@ -26,13 +29,18 @@ import com.sap.sse.datamining.Query;
import com.sap.sse.datamining.StatisticQueryDefinition;
import com.sap.sse.datamining.components.AggregationProcessorDefinition;
import com.sap.sse.datamining.components.DataRetrieverChainDefinition;
import com.sap.sse.datamining.data.ExtensibleQueryResult;
import com.sap.sse.datamining.data.QueryResult;
import com.sap.sse.datamining.factories.DataMiningDTOFactory;
import com.sap.sse.datamining.functions.Function;
import com.sap.sse.datamining.impl.components.DataRetrieverLevel;
import com.sap.sse.datamining.impl.data.QueryResultImpl;
import com.sap.sse.datamining.shared.DataMiningSession;
import com.sap.sse.datamining.shared.GroupKey;
import com.sap.sse.datamining.shared.SerializationDummy;
import com.sap.sse.datamining.shared.data.QueryResultState;
import com.sap.sse.datamining.shared.dto.StatisticQueryDefinitionDTO;
import com.sap.sse.datamining.shared.impl.GenericGroupKey;
import com.sap.sse.datamining.shared.impl.PredefinedQueryIdentifier;
import com.sap.sse.datamining.shared.impl.dto.AggregationProcessorDefinitionDTO;
import com.sap.sse.datamining.shared.impl.dto.DataRetrieverChainDefinitionDTO;
@@ -117,17 +125,12 @@ public class DataMiningServiceImpl extends RemoteServiceServlet implements DataM
}
@Override
public HashSet<FunctionDTO> getDimensionsFor(FunctionDTO statisticToCalculate, String localeInfoName) {
SecurityUtils.getSubject().checkPermission(Permission.DATA_MINING.getStringPermissionForObjects(Mode.READ, statisticToCalculate.getFunctionName()));
Class<?> baseDataType = getBaseDataType(statisticToCalculate);
Iterable<Function<?>> dimensions = getDataMiningServer().getDimensionsFor(baseDataType);
public HashSet<FunctionDTO> getDimensionsFor(DataRetrieverChainDefinitionDTO dataRetrieverChainDefinitionDTO, String localeInfoName) {
SecurityUtils.getSubject().checkPermission(Permission.DATA_MINING.getStringPermissionForObjects(Mode.READ, dataRetrieverChainDefinitionDTO.getName()));
Class<?> retrievedType = getDataMiningServer().getDataRetrieverChainDefinitionForDTO(dataRetrieverChainDefinitionDTO).getRetrievedDataType();
Iterable<Function<?>> dimensions = getDataMiningServer().getDimensionsFor(retrievedType);
return functionsAsDTOs(dimensions, localeInfoName);
}
private Class<?> getBaseDataType(FunctionDTO statisticToCalculate) {
Function<?> function = getDataMiningServer().getFunctionForDTO(statisticToCalculate);
return function.getDeclaringType();
}
@Override
public HashMap<DataRetrieverLevelDTO, HashSet<FunctionDTO>> getDimensionsMappedByLevelFor(DataRetrieverChainDefinitionDTO dataRetrieverChainDefinitionDTO, String localeInfoName) {
@@ -186,6 +189,11 @@ public class DataMiningServiceImpl extends RemoteServiceServlet implements DataM
Iterable<DataRetrieverChainDefinition<?, ?>> dataRetrieverChainDefinitions = (Iterable<DataRetrieverChainDefinition<?, ?>>)(Iterable<?>) getDataMiningServer().getDataRetrieverChainDefinitionsByDataType(baseDataType);
return dataRetrieverChainDefinitionsAsDTOs(dataRetrieverChainDefinitions, localeInfoName);
}
private Class<?> getBaseDataType(FunctionDTO statisticToCalculate) {
Function<?> function = getDataMiningServer().getFunctionForDTO(statisticToCalculate);
return function.getDeclaringType();
}
private ArrayList<DataRetrieverChainDefinitionDTO> dataRetrieverChainDefinitionsAsDTOs(
Iterable<DataRetrieverChainDefinition<?, ?>> dataRetrieverChainDefinitions, String localeInfoName) {
@@ -209,11 +217,34 @@ public class DataMiningServiceImpl extends RemoteServiceServlet implements DataM
DataRetrieverChainDefinition<RacingEventService, ?> retrieverChainDefinition = dataMiningServer.getDataRetrieverChainDefinitionForDTO(dataRetrieverChainDefinitionDTO);
DataRetrieverLevel<?, ?> retrieverLevel = retrieverChainDefinition.getDataRetrieverLevel(retrieverLevelDTO.getLevel());
Iterable<Function<?>> dimensions = functionDTOsAsFunctions(dimensionDTOs);
Map<DataRetrieverLevel<?, ?>, SerializableSettings> retrieverSettings = retrieverSettingsDTOAsRetrieverSettings(retrieverSettingsDTO, retrieverChainDefinition);
Map<DataRetrieverLevel<?, ?>, Map<Function<?>, Collection<?>>> filterSelection = filterSelectionDTOAsFilterSelection(filterSelectionDTO, retrieverChainDefinition);
Locale locale = ResourceBundleStringMessages.Util.getLocaleFor(localeInfoName);
Query<HashSet<Object>> dimensionValuesQuery = dataMiningServer.createDimensionValuesQuery(retrieverChainDefinition, retrieverLevel, dimensions, retrieverSettings, filterSelection, locale);
QueryResult<HashSet<Object>> result = dataMiningServer.runNewQueryAndAbortPreviousQueries(session, dimensionValuesQuery);
// split up between boolean/enum dimensions and others; for the bool/enums we'll
// simply enumerate all values instead of retrieving all objects
List<Function<?>> nonBoolNonEnumResultDimensions = new ArrayList<>();
LinkedHashMap<Function<?>, List<?>> boolOrEnumResultDimensionsWithValues = new LinkedHashMap<>();
for (final Function<?> dimensionFunction : dimensions) {
if (dimensionFunction.getReturnType() == boolean.class || dimensionFunction.getReturnType() == Boolean.class) {
boolOrEnumResultDimensionsWithValues.put(dimensionFunction, Arrays.asList(true, false));
} else if (dimensionFunction.getReturnType().isEnum()) {
boolOrEnumResultDimensionsWithValues.put(dimensionFunction, Arrays.asList(dimensionFunction.getReturnType().getEnumConstants()));
} else {
nonBoolNonEnumResultDimensions.add(dimensionFunction);
}
}
final ExtensibleQueryResult<HashSet<Object>> result;
final Locale locale = ResourceBundleStringMessages.Util.getLocaleFor(localeInfoName);
if (!nonBoolNonEnumResultDimensions.isEmpty()) {
Map<DataRetrieverLevel<?, ?>, SerializableSettings> retrieverSettings = retrieverSettingsDTOAsRetrieverSettings(retrieverSettingsDTO, retrieverChainDefinition);
Map<DataRetrieverLevel<?, ?>, Map<Function<?>, Collection<?>>> filterSelection = filterSelectionDTOAsFilterSelection(filterSelectionDTO, retrieverChainDefinition);
Query<HashSet<Object>> dimensionValuesQuery = dataMiningServer.createDimensionValuesQuery(retrieverChainDefinition, retrieverLevel, nonBoolNonEnumResultDimensions, retrieverSettings, filterSelection, locale);
result = (ExtensibleQueryResult<HashSet<Object>>) dataMiningServer.runNewQueryAndAbortPreviousQueries(session, dimensionValuesQuery);
} else {
@SuppressWarnings("unchecked")
final Class<HashSet<Object>> clazz = (Class<HashSet<Object>>) new HashSet<Object>().getClass();
result = new QueryResultImpl<HashSet<Object>>(QueryResultState.NORMAL, clazz, new HashMap<GroupKey, HashSet<Object>>());
}
for (final Entry<Function<?>, List<?>> e : boolOrEnumResultDimensionsWithValues.entrySet()) {
result.addResult(new GenericGroupKey<>(dtoFactory.createFunctionDTO(e.getKey(), getDataMiningServer().getStringMessages(), locale)), new LinkedHashSet<>(e.getValue()));
}
return dtoFactory.createResultDTO(result);
}
@@ -4,6 +4,15 @@
<div id="mainContent">
<h4 class="articleHeadline">What's New - SAP Sailing Analytics</h4>
<div class="innerContent">
<h5 class="articleSubheadline">February 2017</h5>
<ul class="bulletList">
<li>The definition of "ride height" for foiling sensors has been changed. Instead of showing
the ride height calculated by the sensor we are now showing the minimum of the port and
starboard ride heights. Therefore, this new definition of ride height can be seen as the
distance of lowest hull part from the water.
</li>
</ul>
<h5 class="articleSubheadline">January 2017</h5>
<ul class="bulletList">
<li>An issue with wind-up map rotation which sometimes left the map centered over the African continent has been fixed.
@@ -60,7 +60,9 @@ public class BravoDataImportTest {
}
private enum ImportData {
FILE_UNDEFINED_RACE_BRAVO(870, 0.77176) {
// find out the number of fixes using the following bash line:
// tail -n +5 Undefined\ Race\ -\ BRAVO.txt | awk '{if ($5<$6) print v=$5; else v=$6; sum+=v; count++; } END {print "Sum: ", sum, "Count: ", count, "Average:", sum/count;}'
FILE_UNDEFINED_RACE_BRAVO(870, 0.661037) {
@Override
protected InputStream getInputStream() {
return getClass().getResourceAsStream("/Undefined Race - BRAVO.txt");
@@ -72,13 +74,13 @@ public class BravoDataImportTest {
return new ByteArrayInputStream(HEADER_ORDER_DEFAULT.getBytes(StandardCharsets.UTF_8));
}
},
DUMMY_DEAFULT_HEADER_ONE_LINE(1, 0.77151) {
DUMMY_DEAFULT_HEADER_ONE_LINE(1, 0.661044) {
@Override
protected InputStream getInputStream() {
return new ByteArrayInputStream((HEADER_ORDER_DEFAULT + DUMMY_CONTENT).getBytes(StandardCharsets.UTF_8));
}
},
DUMMY_RANDOM_HAEDER_ONE_LINE(1, 0.01346) {
DUMMY_RANDOM_HAEDER_ONE_LINE(1, 0.092727) {
@Override
protected InputStream getInputStream() {
return new ByteArrayInputStream((HEADER_ORDER_RANDOM + DUMMY_CONTENT).getBytes(StandardCharsets.UTF_8));
@@ -104,10 +104,6 @@ public class BravoDataImporterImpl implements DoubleVectorFixImporter {
/**
* Parses the CSV line and reads the double data values in the order defined by the col enums.
*
* @param line
* @param colIndices
* @return
*/
private DoubleVectorFixImpl parseLine(long lineNr, String filename, String line, Map<String, Integer> colIndices) {
try {
@@ -119,7 +115,7 @@ public class BravoDataImporterImpl implements DoubleVectorFixImporter {
long epoch = Long.parseLong(epochColValue);
fixTp = new MillisecondsTimePoint(epoch);
} else {
String jjLDATE = contentTokens[0].substring(0, 9);
String jjLDATE = contentTokens[0].substring(0, contentTokens[0].indexOf("."));
StringBuilder dtb = new StringBuilder(jjLDATE);
String jjlTIME = contentTokens[1];
int offset = 6 - jjlTIME.indexOf(".");
@@ -27,5 +27,5 @@
<booleanAttribute key="tracing" value="false"/>
<booleanAttribute key="useCustomFeatures" value="false"/>
<booleanAttribute key="useDefaultConfigArea" value="true"/>
<stringAttribute key="workspace_bundles" value="com.google.gwt.servlet@default:default,com.googlecode.java-diff-utils@default:default,com.googlecode.mgwt@default:default,com.sap.sailing.barbados.resultimport@default:default,com.sap.sailing.competitorimport@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.polars.datamining.shared@default:default,com.sap.sailing.polars.datamining@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.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@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.sailing.yachtscoring.resultimport@default:default,com.sap.sse.common@default:default,com.sap.sse.datamining.annotations@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,org.json.simple@default:default,org.moxieapps.gwt.highcharts@default:default"/>
<stringAttribute key="workspace_bundles" value="com.google.gwt.servlet@default:default,com.googlecode.java-diff-utils@default:default,com.googlecode.mgwt@default:default,com.sap.sailing.barbados.resultimport@default:default,com.sap.sailing.competitorimport@default:default,com.sap.sailing.dashboards.gwt@5:true,com.sap.sailing.datamining.provider@default:default,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.polars.datamining.shared@default:default,com.sap.sailing.polars.datamining@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.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@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.sailing.yachtscoring.resultimport@default:default,com.sap.sse.common@default:default,com.sap.sse.datamining.annotations@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,org.json.simple@default:default,org.moxieapps.gwt.highcharts@default:default"/>
</launchConfiguration>
@@ -666,9 +666,11 @@ public class RacingEventServiceImpl implements RacingEventService, ClearStateTes
private void restoreTrackedRaces() {
final ScheduledExecutorService backgroundExecutor = ThreadPoolUtil.INSTANCE.getDefaultBackgroundTaskThreadPoolExecutor();
try {
numberOfTrackedRacesToRestore = getDomainObjectFactory().loadConnectivityParametersForRacesToRestore(params -> {
backgroundExecutor.execute(()->{
// restore the races by calling addRace one by one, but in a background thread, therefore concurrent to any remaining
// server startup activities happening
backgroundExecutor.execute(()->{
try {
numberOfTrackedRacesToRestore = getDomainObjectFactory().loadConnectivityParametersForRacesToRestore(params -> {
try {
addRace(/* addToRegatta==null means "default regatta" */ null, params, /* no timeout during mass loading */ -1);
numberOfTrackedRacesRestored.incrementAndGet();
@@ -676,10 +678,10 @@ public class RacingEventServiceImpl implements RacingEventService, ClearStateTes
logger.log(Level.SEVERE, "Exception trying to restore race"+params, e);
}
});
});
} catch (MalformedURLException | URISyntaxException e) {
logger.log(Level.SEVERE, "Exception trying to obtain connectivity parameters for restoring tracked races", e);
}
} catch (MalformedURLException | URISyntaxException e) {
logger.log(Level.SEVERE, "Exception trying to obtain connectivity parameters for restoring tracked races", e);
}
});
}
@Override
@@ -2,19 +2,64 @@ package com.sap.sse.datamining.shared.impl.dto;
import java.io.Serializable;
/**
* The {@link #signifier} is relevant for the {@link #equals(Object)} and {@link #hashCode()} implementations.
* Optionally, a {@link #localizedName} can be provided at construction time, e.g., as a localized, human-readable
* version of the {@link #signifier}. If not, the {@link #localizedName} will be assigned from the {@link #signifier}.
* <p>
*
* The {@link #signifier} must be set explicitly at construction time. The {@link #localizedName} can optionally
* be provided as a {@link LocalizedNameProvider} through which it will be evaluated lazily, particularly during
* serialization with the custom field serializer.
*
* @author Lennart Hensler
* @author Axel Uhl (d043530)
*
*/
public class ClusterDTO implements Serializable {
private static final long serialVersionUID = -2962035066215989018L;
private String signifier;
private final String signifier;
/**
* <b>Constructor for the GWT-Serialization. Don't use this!</b>
* If {@code null}, the {@link #signifier} will be returned by {@link #toString} instead.
*/
@Deprecated
ClusterDTO() { }
private String localizedName;
/**
* Upon serialization the {@link #signifier} must be obtained from a {@link #localizedNameProvider} and
* cached in the object serialized.
*/
private transient LocalizedNameProvider localizedNameProvider;
public ClusterDTO(String signifier) {
this(signifier, signifier);
}
public ClusterDTO(String signifier, String localizedName) {
this.signifier = signifier;
this.localizedName = localizedName;
}
/**
* Can be used for lazy initialization of objects of this type. As long as the {@link ClusterDTO}
* object is only passed around and not treated with {@link #hashCode} or {@link #equals} or the
* {@link #getLocalizedName()} method is called explicitly then the signifier string is not calculated.
*
* @author Axel Uhl (d043530)
*
*/
public static interface LocalizedNameProvider {
String getLocalizedName();
}
/**
* A possibility to initialize the {@link #getSignifier() signifier} lazily so that the providing function is
* called only when the signifier is really asked for.
*/
public ClusterDTO(String signifier, LocalizedNameProvider localizedNameProvider) {
this(signifier, /* toStringResult */ (String) null);
this.localizedNameProvider = localizedNameProvider;
}
public String getSignifier() {
@@ -23,14 +68,21 @@ public class ClusterDTO implements Serializable {
@Override
public String toString() {
return getSignifier();
return getLocalizedName();
}
public String getLocalizedName() {
if (localizedName == null && localizedNameProvider != null) {
localizedName = localizedNameProvider.getLocalizedName();
}
return localizedName;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((signifier == null) ? 0 : signifier.hashCode());
result = prime * result + ((getSignifier() == null) ? 0 : getSignifier().hashCode());
return result;
}
@@ -43,10 +95,10 @@ public class ClusterDTO implements Serializable {
if (getClass() != obj.getClass())
return false;
ClusterDTO other = (ClusterDTO) obj;
if (signifier == null) {
if (other.signifier != null)
if (getSignifier() == null) {
if (other.getSignifier() != null)
return false;
} else if (!signifier.equals(other.signifier))
} else if (!getSignifier().equals(other.getSignifier()))
return false;
return true;
}
@@ -7,20 +7,30 @@ import java.util.List;
public class FunctionDTO implements Serializable, Comparable<FunctionDTO> {
private static final long serialVersionUID = 4587389541910498505L;
private boolean isDimension;
private String functionName;
private String sourceTypeName;
private String returnTypeName;
private List<String> parameterTypeNames;
private final boolean isDimension;
private final String functionName;
private final String sourceTypeName;
private final String returnTypeName;
private final List<String> parameterTypeNames;
private final int ordinal;
private String displayName;
private int ordinal;
/**
* Constructor for the GWT-Serialization. Don't use this!
* If the {@link #displayName} is not set and this provider is valid, the {@F
*/
@Deprecated
FunctionDTO() {
private transient DisplayNameProvider displayNameProvider;
public static interface DisplayNameProvider {
String getDisplayName();
}
/**
* Makes the construction of the {@link #displayName} lazy, using the {@code displayNameProvider}.
*/
public FunctionDTO(boolean isDimension, String functionName, String sourceTypeName, String returnTypeName,
List<String> parameterTypeNames, DisplayNameProvider displayNameProvider, int ordinal) {
this(isDimension, functionName, sourceTypeName, returnTypeName, parameterTypeNames,
/* displayName is constructed lazily using the displayNameProvider */ (String) null, ordinal);
this.displayNameProvider = displayNameProvider;
}
public FunctionDTO(boolean isDimension, String functionName, String sourceTypeName, String returnTypeName,
@@ -52,6 +62,9 @@ public class FunctionDTO implements Serializable, Comparable<FunctionDTO> {
}
public String getDisplayName() {
if (displayName == null && displayNameProvider != null) {
displayName = displayNameProvider.getDisplayName();
}
return displayName;
}
@@ -0,0 +1,7 @@
package com.sap.sse.datamining.data;
import com.sap.sse.datamining.shared.GroupKey;
public interface ExtensibleQueryResult<ResultType> extends QueryResult<ResultType> {
void addResult(GroupKey key, ResultType result);
}
@@ -26,7 +26,7 @@ public class DataMiningDTOFactory {
* The display name of the resulting DTO is the {@link Function#getSimpleName() simple name} of the given function.
*/
public FunctionDTO createFunctionDTO(Function<?> function) {
return createFunctionDTO(function, function.getSimpleName());
return createFunctionDTO(function, ()->function.getSimpleName());
}
/**
@@ -36,15 +36,16 @@ public class DataMiningDTOFactory {
* If the function has no message key, the function name is used as display name.
*/
public FunctionDTO createFunctionDTO(Function<?> function, ResourceBundleStringMessages stringMessages, Locale locale) {
return createFunctionDTO(function, function.getLocalizedName(locale, stringMessages));
return createFunctionDTO(function, ()->function.getLocalizedName(locale, stringMessages));
}
private FunctionDTO createFunctionDTO(Function<?> function, String displayName) {
private FunctionDTO createFunctionDTO(Function<?> function, FunctionDTO.DisplayNameProvider displayNameProvider) {
String functionName = function.getSimpleName();
String sourceTypeName = function.getDeclaringType().getName();
String returnTypeName = function.getReturnType().getName();
List<String> parameterTypeNames = getParameterTypeNames(function);
return new FunctionDTO(function.isDimension(), functionName, sourceTypeName, returnTypeName, parameterTypeNames, displayName, function.getOrdinal());
return new FunctionDTO(function.isDimension(), functionName, sourceTypeName, returnTypeName, parameterTypeNames,
displayNameProvider, function.getOrdinal());
}
private List<String> getParameterTypeNames(Function<?> function) {
@@ -121,14 +121,11 @@ public class QueryFactory {
@Override
protected Processor<DataSourceType, ?> createChainAndReturnFirstProcessor(Processor<Map<GroupKey, HashSet<Object>>, Void> resultReceiver) {
ProcessorFactory processorFactory = new ProcessorFactory(executor);
Processor<GroupedDataEntry<Object>, Map<GroupKey, HashSet<Object>>> valueCollector = processorFactory.createGroupedDataCollectingAsSetProcessor(/*query*/ this);
Map<DataRetrieverLevel<?, ?>, FilterCriterion<?>> criteriaMappedByRetrieverLevel = createFilterCriteria(filterSelection);
DataRetrieverChainBuilder<DataSourceType> chainBuilder = dataRetrieverChainDefinition.startBuilding(executor);
while (!chainBuilder.hasBeenInitialized() || chainBuilder.getCurrentRetrieverLevel().getLevel() < retrieverLevel.getLevel()) {
chainBuilder.stepFurther();
DataRetrieverLevel<?, ?> currentLevel = chainBuilder.getCurrentRetrieverLevel();
if (settings.containsKey(currentLevel)) {
chainBuilder.setSettings(settings.get(currentLevel));
@@ -141,7 +138,6 @@ public class QueryFactory {
chainBuilder.getCurrentRetrievedDataType(), valueCollector, getParameterProvidersFor(dimensions, stringMessages, locale), stringMessages, locale)) {
chainBuilder.addResultReceiver(groupingExtractor);
}
return chainBuilder.build();
}
};
@@ -40,7 +40,7 @@ public abstract class AbstractParallelAggregationProcessor<InputType, Aggregated
/**
* Method to handle the element. This method is only called in a way, that is thread safe, so
* Method to handle the element. This method is only called in a way that is thread safe so
* that multiple threads can't corrupt the data.
*/
protected abstract void handleElement(InputType element);
@@ -30,13 +30,20 @@ public abstract class AbstractParallelSingleGroupedValueAggregationProcessor<Val
protected void handleElement(GroupedDataEntry<ValueType> element) {
GroupKey key = element.getKey();
ValueType value = element.getDataEntry();
if (!valueMap.containsKey(key)) {
valueMap.put(key, value);
} else {
valueMap.put(key, compareValuesAndReturnNewResult(valueMap.get(key), value));
if (value != null) {
if (!valueMap.containsKey(key)) {
valueMap.put(key, value);
} else {
valueMap.put(key, compareValuesAndReturnNewResult(valueMap.get(key), value));
}
}
}
/**
* @param currentResult not {@code null}
* @param newValue not {@code null}
* @return not {@code null}
*/
protected abstract ValueType compareValuesAndReturnNewResult(ValueType currentResult, ValueType newValue);
@Override
@@ -36,13 +36,15 @@ public class ParallelGroupedNumberDataAverageAggregationProcessor
@Override
protected void storeElement(GroupedDataEntry<Number> element) {
incrementElementAmount(element);
DoubleHolder aggregate = sumPerKey.get(element.getKey());
if (aggregate == null) {
aggregate = new DoubleHolder(element.getDataEntry().doubleValue());
sumPerKey.put(element.getKey(), aggregate);
} else {
aggregate.value += element.getDataEntry().doubleValue();
if (element.getDataEntry() != null) {
incrementElementAmount(element);
DoubleHolder aggregate = sumPerKey.get(element.getKey());
if (aggregate == null) {
aggregate = new DoubleHolder(element.getDataEntry().doubleValue());
sumPerKey.put(element.getKey(), aggregate);
} else {
aggregate.value += element.getDataEntry().doubleValue();
}
}
}
@@ -19,13 +19,11 @@ public class ParallelGroupedNumberDataMinAggregationProcessor
return DEFINITION;
}
public ParallelGroupedNumberDataMinAggregationProcessor(ExecutorService executor,
Collection<Processor<Map<GroupKey, Number>, ?>> resultReceivers) {
super(executor, resultReceivers, "Minimum");
}
@Override
protected Number compareValuesAndReturnNewResult(Number currentResult, Number newValue) {
return currentResult.doubleValue() <= newValue.doubleValue() ? currentResult : newValue;
@@ -2,14 +2,14 @@ package com.sap.sse.datamining.impl.data;
import java.util.Map;
import com.sap.sse.datamining.data.QueryResult;
import com.sap.sse.datamining.data.ExtensibleQueryResult;
import com.sap.sse.datamining.shared.AdditionalResultData;
import com.sap.sse.datamining.shared.GroupKey;
import com.sap.sse.datamining.shared.data.QueryResultState;
import com.sap.sse.datamining.shared.impl.NullAdditionalResultData;
import com.sap.sse.datamining.shared.impl.QueryResultBaseImpl;
public class QueryResultImpl<ResultType> extends QueryResultBaseImpl<ResultType> implements QueryResult<ResultType> {
public class QueryResultImpl<ResultType> extends QueryResultBaseImpl<ResultType> implements ExtensibleQueryResult<ResultType> {
private static final long serialVersionUID = 5173796619174827696L;
private Class<ResultType> resultType;
@@ -40,5 +40,4 @@ public class QueryResultImpl<ResultType> extends QueryResultBaseImpl<ResultType>
public AdditionalResultData getAdditionalData() {
return super.getAdditionalData();
}
}