diff --git a/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/Duration.java b/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/Duration.java new file mode 100755 index 00000000000..6ff5ab37a71 --- /dev/null +++ b/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/Duration.java @@ -0,0 +1,17 @@ +package com.sap.sailing.domain.common; + +import java.io.Serializable; + +/** + * A time duration that can be converted to various time units and that interoperates with {@link TimePoint}. + * + * @author Axel Uhl (D043530) + * + */ +public interface Duration extends Serializable { + long asMillis(); + + double asSeconds(); + + Duration divide(long divisor); +} diff --git a/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/TimePoint.java b/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/TimePoint.java index 4b715f65792..22af26ad0bb 100755 --- a/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/TimePoint.java +++ b/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/TimePoint.java @@ -10,8 +10,14 @@ public interface TimePoint extends Comparable, Serializable { TimePoint plus(long milliseconds); + TimePoint plus(Duration duration); + TimePoint minus(long milliseconds); + TimePoint minus(Duration duration); + + Duration until(TimePoint later); + boolean after(TimePoint other); boolean before(TimePoint other); diff --git a/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/dto/LeaderboardEntryDTO.java b/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/dto/LeaderboardEntryDTO.java index f260462a32e..b5531ace848 100755 --- a/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/dto/LeaderboardEntryDTO.java +++ b/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/dto/LeaderboardEntryDTO.java @@ -1,9 +1,9 @@ package com.sap.sailing.domain.common.dto; import java.io.Serializable; -import java.util.Date; import java.util.List; +import com.sap.sailing.domain.common.Duration; import com.sap.sailing.domain.common.MaxPointsReason; import com.sap.sailing.domain.common.RaceIdentifier; import com.sap.sailing.domain.common.Tack; @@ -61,13 +61,18 @@ public class LeaderboardEntryDTO implements Serializable { public Tack startTack; /** - * If we have GPS data for the competitor for whom this is a leaderboard entry, tells the time point of the last + * If we have GPS data for the competitor for whom this is a leaderboard entry, tells the time since the last * non-extrapolated GPS fix that was really received from the tracking device at or before the time point for which * the leaderboard was queried. The user interface may---particularly in live mode---choose to visualize the time * that passed between the last fix and the query time point for which this entry was created. */ - public Date timePointOfLastPositionFixAtOrBeforeQueryTimePoint; public Double timeSinceLastPositionFixInSeconds; + + /** + * For the competitor's track in the race represented by this object, if a track is present and the track has more + * than one fix, this field tells the average duration between two fixes on the competitor's track. + */ + public Duration averageSamplingInterval; /** * If null, no leg details are known yet, the race is not being tracked or the details @@ -117,7 +122,7 @@ public class LeaderboardEntryDTO implements Serializable { result = prime * result + ((speedOverGroundAtStartOfRaceInKnots == null) ? 0 : speedOverGroundAtStartOfRaceInKnots.hashCode()); result = prime * result + ((startTack == null) ? 0 : startTack.hashCode()); - result = prime * result + ((timePointOfLastPositionFixAtOrBeforeQueryTimePoint == null) ? 0 : timePointOfLastPositionFixAtOrBeforeQueryTimePoint.hashCode()); + result = prime * result + ((averageSamplingInterval == null) ? 0 : averageSamplingInterval.hashCode()); result = prime * result + ((timeSinceLastPositionFixInSeconds == null) ? 0 : timeSinceLastPositionFixInSeconds.hashCode()); result = prime * result + ((totalPoints == null) ? 0 : totalPoints.hashCode()); result = prime @@ -190,10 +195,10 @@ public class LeaderboardEntryDTO implements Serializable { return false; if (startTack != other.startTack) return false; - if (timePointOfLastPositionFixAtOrBeforeQueryTimePoint == null) { - if (other.timePointOfLastPositionFixAtOrBeforeQueryTimePoint != null) + if (averageSamplingInterval == null) { + if (other.averageSamplingInterval != null) return false; - } else if (!timePointOfLastPositionFixAtOrBeforeQueryTimePoint.equals(other.timePointOfLastPositionFixAtOrBeforeQueryTimePoint)) + } else if (!averageSamplingInterval.equals(other.averageSamplingInterval)) return false; if (timeSinceLastPositionFixInSeconds == null) { if (other.timeSinceLastPositionFixInSeconds != null) diff --git a/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/dto/SeriesCreationParametersDTO.java b/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/dto/SeriesCreationParametersDTO.java index 668027d32c3..94ba4e935b4 100755 --- a/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/dto/SeriesCreationParametersDTO.java +++ b/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/dto/SeriesCreationParametersDTO.java @@ -15,15 +15,18 @@ public class SeriesCreationParametersDTO implements Serializable { private boolean firstColumnIsNonDiscardableCarryForward; private int[] discardingThresholds; + + private boolean hasSplitFleetContiguousScoring; SeriesCreationParametersDTO() {} public SeriesCreationParametersDTO(List fleets, boolean medal, boolean startsWithZero, boolean firstColumnIsNonDiscardableCarryForward, - int[] discardingThresholds) { + int[] discardingThresholds, boolean hasSplitFleetContiguousScoring) { super(); this.fleets = fleets; this.medal = medal; this.startsWithZero = startsWithZero; + this.hasSplitFleetContiguousScoring = hasSplitFleetContiguousScoring; this.firstColumnIsNonDiscardableCarryForward = firstColumnIsNonDiscardableCarryForward; this.discardingThresholds = discardingThresholds; } @@ -40,6 +43,10 @@ public class SeriesCreationParametersDTO implements Serializable { return startsWithZero; } + public boolean hasSplitFleetContiguousScoring() { + return hasSplitFleetContiguousScoring; + } + public int[] getDiscardingThresholds() { return discardingThresholds; } diff --git a/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/impl/AbstractTimePoint.java b/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/impl/AbstractTimePoint.java index 72a9c8307ea..55cd7b7a998 100644 --- a/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/impl/AbstractTimePoint.java +++ b/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/impl/AbstractTimePoint.java @@ -3,6 +3,7 @@ package com.sap.sailing.domain.common.impl; import java.util.Comparator; import java.util.Date; +import com.sap.sailing.domain.common.Duration; import com.sap.sailing.domain.common.TimePoint; public abstract class AbstractTimePoint implements TimePoint { @@ -33,6 +34,21 @@ public abstract class AbstractTimePoint implements TimePoint { return result; } + @Override + public TimePoint plus(Duration duration) { + return plus(duration.asMillis()); + } + + @Override + public TimePoint minus(Duration duration) { + return minus(duration.asMillis()); + } + + @Override + public Duration until(TimePoint later) { + return new MillisecondsDurationImpl(later.asMillis()-asMillis()); + } + @Override public TimePoint plus(long milliseconds) { return new MillisecondsTimePoint(asMillis()+milliseconds); diff --git a/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/impl/MillisecondsDurationImpl.java b/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/impl/MillisecondsDurationImpl.java new file mode 100755 index 00000000000..e70832109f0 --- /dev/null +++ b/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/impl/MillisecondsDurationImpl.java @@ -0,0 +1,30 @@ +package com.sap.sailing.domain.common.impl; + +import com.sap.sailing.domain.common.Duration; + +public class MillisecondsDurationImpl implements Duration { + private static final long serialVersionUID = -4257982564719184723L; + private long millis; + + MillisecondsDurationImpl() {} // for serialization only + + public MillisecondsDurationImpl(long millis) { + super(); + this.millis = millis; + } + + @Override + public long asMillis() { + return millis; + } + + @Override + public double asSeconds() { + return ((double) asMillis()) / 1000.; + } + + @Override + public Duration divide(long divisor) { + return new MillisecondsDurationImpl(asMillis() / divisor); + } +} diff --git a/java/com.sap.sailing.domain.persistence/src/com/sap/sailing/domain/persistence/impl/DomainObjectFactoryImpl.java b/java/com.sap.sailing.domain.persistence/src/com/sap/sailing/domain/persistence/impl/DomainObjectFactoryImpl.java index 1cddb0567fe..d4dcb41fe7b 100755 --- a/java/com.sap.sailing.domain.persistence/src/com/sap/sailing/domain/persistence/impl/DomainObjectFactoryImpl.java +++ b/java/com.sap.sailing.domain.persistence/src/com/sap/sailing/domain/persistence/impl/DomainObjectFactoryImpl.java @@ -96,6 +96,7 @@ import com.sap.sailing.domain.leaderboard.RegattaLeaderboard; import com.sap.sailing.domain.leaderboard.ScoringScheme; import com.sap.sailing.domain.leaderboard.SettableScoreCorrection; import com.sap.sailing.domain.leaderboard.ThresholdBasedResultDiscardingRule; +import com.sap.sailing.domain.leaderboard.impl.DelayedLeaderboardCorrectionsImpl; import com.sap.sailing.domain.leaderboard.impl.FlexibleLeaderboardImpl; import com.sap.sailing.domain.leaderboard.impl.LeaderboardGroupImpl; import com.sap.sailing.domain.leaderboard.impl.RegattaLeaderboardImpl; @@ -983,6 +984,7 @@ public class DomainObjectFactoryImpl implements DomainObjectFactory { String name = (String) dbSeries.get(FieldNames.SERIES_NAME.name()); boolean isMedal = (Boolean) dbSeries.get(FieldNames.SERIES_IS_MEDAL.name()); Boolean startsWithZeroScore = (Boolean) dbSeries.get(FieldNames.SERIES_STARTS_WITH_ZERO_SCORE.name()); + Boolean hasSplitFleetContiguousScoring = (Boolean) dbSeries.get(FieldNames.SERIES_HAS_SPLIT_FLEET_CONTIGUOUS_SCORING.name()); Boolean firstColumnIsNonDiscardableCarryForward = (Boolean) dbSeries.get(FieldNames.SERIES_STARTS_WITH_NON_DISCARDABLE_CARRY_FORWARD.name()); final BasicDBList dbFleets = (BasicDBList) dbSeries.get(FieldNames.SERIES_FLEETS.name()); Map fleetsByName = loadFleets(dbFleets); @@ -996,6 +998,9 @@ public class DomainObjectFactoryImpl implements DomainObjectFactory { if (startsWithZeroScore != null) { series.setStartsWithZeroScore(startsWithZeroScore); } + if (hasSplitFleetContiguousScoring != null) { + series.setSplitFleetContiguousScoring(hasSplitFleetContiguousScoring); + } if (firstColumnIsNonDiscardableCarryForward != null) { series.setFirstColumnIsNonDiscardableCarryForward(firstColumnIsNonDiscardableCarryForward); } diff --git a/java/com.sap.sailing.domain.persistence/src/com/sap/sailing/domain/persistence/impl/FieldNames.java b/java/com.sap.sailing.domain.persistence/src/com/sap/sailing/domain/persistence/impl/FieldNames.java index 1e450f0e026..4f1d429b2e6 100755 --- a/java/com.sap.sailing.domain.persistence/src/com/sap/sailing/domain/persistence/impl/FieldNames.java +++ b/java/com.sap.sailing.domain.persistence/src/com/sap/sailing/domain/persistence/impl/FieldNames.java @@ -22,6 +22,7 @@ public enum FieldNames { SERIES_NAME, SERIES_IS_MEDAL, SERIES_STARTS_WITH_ZERO_SCORE, + SERIES_HAS_SPLIT_FLEET_CONTIGUOUS_SCORING, SERIES_STARTS_WITH_NON_DISCARDABLE_CARRY_FORWARD, SERIES_FLEETS, SERIES_RACE_COLUMNS, diff --git a/java/com.sap.sailing.domain.persistence/src/com/sap/sailing/domain/persistence/impl/MongoObjectFactoryImpl.java b/java/com.sap.sailing.domain.persistence/src/com/sap/sailing/domain/persistence/impl/MongoObjectFactoryImpl.java index a94443ac385..391cc73cb3c 100755 --- a/java/com.sap.sailing.domain.persistence/src/com/sap/sailing/domain/persistence/impl/MongoObjectFactoryImpl.java +++ b/java/com.sap.sailing.domain.persistence/src/com/sap/sailing/domain/persistence/impl/MongoObjectFactoryImpl.java @@ -540,6 +540,7 @@ public class MongoObjectFactoryImpl implements MongoObjectFactory { DBObject dbSeries = new BasicDBObject(); dbSeries.put(FieldNames.SERIES_NAME.name(), s.getName()); dbSeries.put(FieldNames.SERIES_IS_MEDAL.name(), s.isMedal()); + dbSeries.put(FieldNames.SERIES_HAS_SPLIT_FLEET_CONTIGUOUS_SCORING.name(), s.hasSplitFleetContiguousScoring()); dbSeries.put(FieldNames.SERIES_STARTS_WITH_ZERO_SCORE.name(), s.isStartsWithZeroScore()); dbSeries.put(FieldNames.SERIES_STARTS_WITH_NON_DISCARDABLE_CARRY_FORWARD.name(), s.isFirstColumnIsNonDiscardableCarryForward()); BasicDBList dbFleets = new BasicDBList(); diff --git a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/racelog/impl/NoAddingRaceLogWrapper.java b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/racelog/impl/NoAddingRaceLogWrapper.java index 88a74d33259..6728eb53f99 100755 --- a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/racelog/impl/NoAddingRaceLogWrapper.java +++ b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/racelog/impl/NoAddingRaceLogWrapper.java @@ -9,6 +9,7 @@ import java.util.UUID; import java.util.logging.Level; import java.util.logging.Logger; +import com.sap.sailing.domain.common.Duration; import com.sap.sailing.domain.common.TimePoint; import com.sap.sailing.domain.racelog.RaceLog; import com.sap.sailing.domain.racelog.RaceLogEvent; @@ -208,19 +209,29 @@ public class NoAddingRaceLogWrapper implements RaceLog { @Override public void removeTrackListener(TrackListener listener) {} - - @Override - public RaceLogEvent getEventById(Serializable id) { - return innerRaceLog.getEventById(id); - } - - @Override - public boolean isEventRevokedBy(RevokeEvent revokeEvent) { - return innerRaceLog.isEventRevokedBy(revokeEvent); - } - - @Override - public NavigableSet getUnrevokedEvents() { - return innerRaceLog.getUnrevokedEvents(); - } -} \ No newline at end of file + + @Override + public RaceLogEvent getEventById(Serializable id) { + return innerRaceLog.getEventById(id); + } + + @Override + public boolean isEventRevokedBy(RevokeEvent revokeEvent) { + return innerRaceLog.isEventRevokedBy(revokeEvent); + } + + @Override + public NavigableSet getUnrevokedEvents() { + return innerRaceLog.getUnrevokedEvents(); + } + + @Override + public Duration getAverageIntervalBetweenFixes() { + return innerRaceLog.getAverageIntervalBetweenFixes(); + } + + @Override + public Duration getAverageIntervalBetweenRawFixes() { + return innerRaceLog.getAverageIntervalBetweenRawFixes(); + } +} diff --git a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/tracking/Track.java b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/tracking/Track.java index 22ec9b25810..e268413a2a4 100644 --- a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/tracking/Track.java +++ b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/tracking/Track.java @@ -1,137 +1,150 @@ -package com.sap.sailing.domain.tracking; - -import java.io.Serializable; -import java.util.Iterator; -import java.util.concurrent.locks.ReadWriteLock; - -import com.sap.sailing.domain.base.Timed; -import com.sap.sailing.domain.common.TimePoint; - -/** - * A track records {@link Timed} items for an object of type ItemType. It allows clients to ask for a value - * close to a given {@link TimePoint}. The track manages a time-based set of raw fixes. An implementation may have an - * understanding of how to eliminate outliers. For example, if a track implementation knows it's tracking boats, it may - * consider fixes that the boat cannot possibly have reached due to its speed and direction change limitations as - * outliers. The set of fixes with outliers filtered out can be obtained using {@link #getFixes} whereas - * {@link #getRawFixes()} returns the unfiltered, raw fixes. If an implementation has no idea what an outlier is, - * both methods will return the same fix sequence.

- * - * With tracks, concurrency is an important issue. Threads may want to modify a track while other threads may want to - * read from it. Several methods such as {@link #getLastFixAtOrBefore(TimePoint)} return a single fix and can manage - * concurrency internally. However, those methods returning a collection of fixes, such as {@link #getFixes()} or an - * iterator over a collection of fixes, such as {@link #getFixesIterator(TimePoint, boolean)}, need special treatment. - * Until we internalize such iterations (see bug 824, http://bugzilla.sapsailing.com/bugzilla/show_bug.cgi?id=824), - * callers need to manage a read lock which is part of a {@link ReadWriteLock} managed by this track. Callers do so - * by calling {@link #lockForRead} and {@link #unlockAfterRead}. - * - * @author Axel Uhl (d043530) - */ -public interface Track extends Serializable { - /** - * Locks this track for reading by the calling thread. If the thread already holds the lock for this track, - * the hold count will be incremented. Make sure to call {@link #unlockAfterRead()} in a finally - * block to release the lock under all possible circumstances. Failure to do so will inevitably lead to - * deadlocks! - */ - void lockForRead(); - - /** - * Decrements the hold count for this track's read lock for the calling thread. If it goes to zero, the lock will be - * released and other readers or a writer can obtain the lock. Make sure to call this method in a - * finally block for each {@link #lockForRead()} invocation. - */ - void unlockAfterRead(); - - /** - * Callers must have called {@link #lockForRead()} before calling this method. This will be checked, and an exception - * will be thrown in case the caller has failed to do so. - * - * @return the smoothened fixes - */ - Iterable getFixes(); - - /** - * Callers must have called {@link #lockForRead()} before calling this method. This will be checked, and an exception - * will be thrown in case the caller has failed to do so. - * - * @return The smoothened fixes between from and to. - */ - Iterable getFixes(TimePoint from, boolean fromInclusive, TimePoint to, boolean toInclusive); - - /** - * Callers must have called {@link #lockForRead()} before calling this method. This will be checked, and an exception - * will be thrown in case the caller has failed to do so. - */ - Iterable getRawFixes(); - - FixType getLastFixAtOrBefore(TimePoint timePoint); - - FixType getLastFixBefore(TimePoint timePoint); - - FixType getLastRawFixAtOrBefore(TimePoint timePoint); - - FixType getFirstFixAtOrAfter(TimePoint timePoint); - - FixType getFirstRawFixAtOrAfter(TimePoint timePoint); - - FixType getLastRawFixBefore(TimePoint timePoint); - - FixType getFirstRawFixAfter(TimePoint timePoint); - - FixType getFirstFixAfter(TimePoint timePoint); - - /** - * The first fix in this track or null if the track is empty. The fix returned may - * be an outlier that is not returned by calls operating on the smoothened version of the track. - */ - FixType getFirstRawFix(); - - /** - * The last fix in this track or null if the track is empty. The fix returned may - * be an outlier that is not returned by calls operating on the smoothened version of the track. - */ - FixType getLastRawFix(); - - /** - * Returns an iterator starting at the first fix after startingAt (or "at or after" in case - * inclusive is true). The fixes returned by the iterator are the smoothened fixes (see - * also {@link #getFixes()}, without any smoothening or dampening applied. - * - * Callers must have called {@link #lockForRead()} before calling this method. This will be checked, and an exception - * will be thrown in case the caller has failed to do so. - */ - Iterator getFixesIterator(TimePoint startingAt, boolean inclusive); - - /** - * Returns an iterator starting at the first raw fix after startingAt (or "at or after" in case - * inclusive is true). The fixes returned by the iterator are the raw fixes (see also - * {@link #getRawFixes()}, without any smoothening or dampening applied. - * - * Callers must have called {@link #lockForRead()} before calling this method. This will be checked, and an exception - * will be thrown in case the caller has failed to do so. - */ - Iterator getRawFixesIterator(TimePoint startingAt, boolean inclusive); - - /** - * Returns a descending iterator starting at the first fix before startingAt (or "at or before" in case - * inclusive is true). The fixes returned by the iterator are the smoothened fixes (see - * also {@link #getFixes()}, without any smoothening or dampening applied. - * - * Callers must have called {@link #lockForRead()} before calling this method. This will be checked, and an exception - * will be thrown in case the caller has failed to do so. - */ - Iterator getFixesDescendingIterator(TimePoint startingAt, boolean inclusive); - - /** - * Returns a descending iterator starting at the first raw fix before startingAt (or "at or before" in case - * inclusive is true). The fixes returned by the iterator are the raw fixes (see also - * {@link #getRawFixes()}, without any smoothening or dampening applied. - * - * Callers must have called {@link #lockForRead()} before calling this method. This will be checked, and an exception - * will be thrown in case the caller has failed to do so. - */ - Iterator getRawFixesDescendingIterator(TimePoint startingAt, boolean inclusive); - - void addTrackListener(TrackListener listener); - void removeTrackListener(TrackListener listener); -} +package com.sap.sailing.domain.tracking; + +import java.io.Serializable; +import java.util.Iterator; +import java.util.concurrent.locks.ReadWriteLock; + +import com.sap.sailing.domain.base.Timed; +import com.sap.sailing.domain.common.Duration; +import com.sap.sailing.domain.common.TimePoint; + +/** + * A track records {@link Timed} items for an object of type ItemType. It allows clients to ask for a value + * close to a given {@link TimePoint}. The track manages a time-based set of raw fixes. An implementation may have an + * understanding of how to eliminate outliers. For example, if a track implementation knows it's tracking boats, it may + * consider fixes that the boat cannot possibly have reached due to its speed and direction change limitations as + * outliers. The set of fixes with outliers filtered out can be obtained using {@link #getFixes} whereas + * {@link #getRawFixes()} returns the unfiltered, raw fixes. If an implementation has no idea what an outlier is, + * both methods will return the same fix sequence.

+ * + * With tracks, concurrency is an important issue. Threads may want to modify a track while other threads may want to + * read from it. Several methods such as {@link #getLastFixAtOrBefore(TimePoint)} return a single fix and can manage + * concurrency internally. However, those methods returning a collection of fixes, such as {@link #getFixes()} or an + * iterator over a collection of fixes, such as {@link #getFixesIterator(TimePoint, boolean)}, need special treatment. + * Until we internalize such iterations (see bug 824, http://bugzilla.sapsailing.com/bugzilla/show_bug.cgi?id=824), + * callers need to manage a read lock which is part of a {@link ReadWriteLock} managed by this track. Callers do so + * by calling {@link #lockForRead} and {@link #unlockAfterRead}. + * + * @author Axel Uhl (d043530) + */ +public interface Track extends Serializable { + /** + * Locks this track for reading by the calling thread. If the thread already holds the lock for this track, + * the hold count will be incremented. Make sure to call {@link #unlockAfterRead()} in a finally + * block to release the lock under all possible circumstances. Failure to do so will inevitably lead to + * deadlocks! + */ + void lockForRead(); + + /** + * Decrements the hold count for this track's read lock for the calling thread. If it goes to zero, the lock will be + * released and other readers or a writer can obtain the lock. Make sure to call this method in a + * finally block for each {@link #lockForRead()} invocation. + */ + void unlockAfterRead(); + + /** + * Callers must have called {@link #lockForRead()} before calling this method. This will be checked, and an exception + * will be thrown in case the caller has failed to do so. + * + * @return the smoothened fixes + */ + Iterable getFixes(); + + /** + * Callers must have called {@link #lockForRead()} before calling this method. This will be checked, and an exception + * will be thrown in case the caller has failed to do so. + * + * @return The smoothened fixes between from and to. + */ + Iterable getFixes(TimePoint from, boolean fromInclusive, TimePoint to, boolean toInclusive); + + /** + * Callers must have called {@link #lockForRead()} before calling this method. This will be checked, and an exception + * will be thrown in case the caller has failed to do so. + */ + Iterable getRawFixes(); + + FixType getLastFixAtOrBefore(TimePoint timePoint); + + FixType getLastFixBefore(TimePoint timePoint); + + FixType getLastRawFixAtOrBefore(TimePoint timePoint); + + FixType getFirstFixAtOrAfter(TimePoint timePoint); + + FixType getFirstRawFixAtOrAfter(TimePoint timePoint); + + FixType getLastRawFixBefore(TimePoint timePoint); + + FixType getFirstRawFixAfter(TimePoint timePoint); + + FixType getFirstFixAfter(TimePoint timePoint); + + /** + * The first fix in this track or null if the track is empty. The fix returned may + * be an outlier that is not returned by calls operating on the smoothened version of the track. + */ + FixType getFirstRawFix(); + + /** + * The last fix in this track or null if the track is empty. The fix returned may + * be an outlier that is not returned by calls operating on the smoothened version of the track. + */ + FixType getLastRawFix(); + + /** + * Returns an iterator starting at the first fix after startingAt (or "at or after" in case + * inclusive is true). The fixes returned by the iterator are the smoothened fixes (see + * also {@link #getFixes()}, without any smoothening or dampening applied. + * + * Callers must have called {@link #lockForRead()} before calling this method. This will be checked, and an exception + * will be thrown in case the caller has failed to do so. + */ + Iterator getFixesIterator(TimePoint startingAt, boolean inclusive); + + /** + * Returns an iterator starting at the first raw fix after startingAt (or "at or after" in case + * inclusive is true). The fixes returned by the iterator are the raw fixes (see also + * {@link #getRawFixes()}, without any smoothening or dampening applied. + * + * Callers must have called {@link #lockForRead()} before calling this method. This will be checked, and an exception + * will be thrown in case the caller has failed to do so. + */ + Iterator getRawFixesIterator(TimePoint startingAt, boolean inclusive); + + /** + * Returns a descending iterator starting at the first fix before startingAt (or "at or before" in case + * inclusive is true). The fixes returned by the iterator are the smoothened fixes (see + * also {@link #getFixes()}, without any smoothening or dampening applied. + * + * Callers must have called {@link #lockForRead()} before calling this method. This will be checked, and an exception + * will be thrown in case the caller has failed to do so. + */ + Iterator getFixesDescendingIterator(TimePoint startingAt, boolean inclusive); + + /** + * Returns a descending iterator starting at the first raw fix before startingAt (or "at or before" in case + * inclusive is true). The fixes returned by the iterator are the raw fixes (see also + * {@link #getRawFixes()}, without any smoothening or dampening applied. + * + * Callers must have called {@link #lockForRead()} before calling this method. This will be checked, and an exception + * will be thrown in case the caller has failed to do so. + */ + Iterator getRawFixesDescendingIterator(TimePoint startingAt, boolean inclusive); + + void addTrackListener(TrackListener listener); + void removeTrackListener(TrackListener listener); + + /** + * @return the average duration between two fixes (outliers removed) in this track or null if there is not + * more than one fix in the track + */ + Duration getAverageIntervalBetweenFixes(); + + /** + * @return the average duration between two fixes (outliers not removed) in this track or null if there is not + * more than one raw fix in the track + */ + Duration getAverageIntervalBetweenRawFixes(); +} diff --git a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/tracking/impl/TrackImpl.java b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/tracking/impl/TrackImpl.java index eed2ee5d69d..72ab7a11947 100644 --- a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/tracking/impl/TrackImpl.java +++ b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/tracking/impl/TrackImpl.java @@ -7,6 +7,7 @@ import java.util.Iterator; import java.util.NavigableSet; import com.sap.sailing.domain.base.Timed; +import com.sap.sailing.domain.common.Duration; import com.sap.sailing.domain.common.TimePoint; import com.sap.sailing.domain.tracking.Track; import com.sap.sailing.domain.tracking.TrackListener; @@ -20,7 +21,7 @@ public class TrackImpl implements Track { /** * The fixes, ordered by their time points */ - private final NavigableSet fixes; + private final ArrayListNavigableSet fixes; private final NamedReentrantReadWriteLock readWriteLock; @@ -47,7 +48,7 @@ public class TrackImpl implements Track { this(new ArrayListNavigableSet(TimedComparator.INSTANCE), nameForReadWriteLock); } - protected TrackImpl(NavigableSet fixes, String nameForReadWriteLock) { + protected TrackImpl(ArrayListNavigableSet fixes, String nameForReadWriteLock) { this.readWriteLock = new NamedReentrantReadWriteLock(nameForReadWriteLock, /* fair */ false); this.fixes = fixes; this.listeners = new TrackListeners>(); @@ -323,4 +324,23 @@ public class TrackImpl implements Track { listeners.removeListener(listener); } + @Override + public Duration getAverageIntervalBetweenFixes() { + lockForRead(); + try { + return getFixes().first().getTimePoint().until(getFixes().last().getTimePoint()).divide(getFixes().size()-1); + } finally { + unlockAfterRead(); + } + } + + @Override + public Duration getAverageIntervalBetweenRawFixes() { + lockForRead(); + try { + return getRawFixes().first().getTimePoint().until(getRawFixes().last().getTimePoint()).divide(getRawFixes().size()-1); + } finally { + unlockAfterRead(); + } + } } diff --git a/java/com.sap.sailing.domain.test/resources/04687b2a-9e68-11e0-85be-406186cbf87c.data b/java/com.sap.sailing.domain.test/resources/04687b2a-9e68-11e0-85be-406186cbf87c.data deleted file mode 100755 index 0da57c36f56..00000000000 Binary files a/java/com.sap.sailing.domain.test/resources/04687b2a-9e68-11e0-85be-406186cbf87c.data and /dev/null differ diff --git a/java/com.sap.sailing.domain.test/resources/357c700a-9d9a-11e0-85be-406186cbf87c.data b/java/com.sap.sailing.domain.test/resources/357c700a-9d9a-11e0-85be-406186cbf87c.data deleted file mode 100755 index 05379781b73..00000000000 Binary files a/java/com.sap.sailing.domain.test/resources/357c700a-9d9a-11e0-85be-406186cbf87c.data and /dev/null differ diff --git a/java/com.sap.sailing.domain.test/resources/52697ec0-2dd0-0131-2802-60a44ce903c3.data b/java/com.sap.sailing.domain.test/resources/52697ec0-2dd0-0131-2802-60a44ce903c3.data deleted file mode 100755 index 19269237b4d..00000000000 Binary files a/java/com.sap.sailing.domain.test/resources/52697ec0-2dd0-0131-2802-60a44ce903c3.data and /dev/null differ diff --git a/java/com.sap.sailing.domain.test/resources/528a0f30-2dd0-0131-2819-60a44ce903c3.data b/java/com.sap.sailing.domain.test/resources/528a0f30-2dd0-0131-2819-60a44ce903c3.data deleted file mode 100755 index da67af60559..00000000000 Binary files a/java/com.sap.sailing.domain.test/resources/528a0f30-2dd0-0131-2819-60a44ce903c3.data and /dev/null differ diff --git a/java/com.sap.sailing.domain.test/resources/5291b3ea-9934-11e0-85be-406186cbf87c.data b/java/com.sap.sailing.domain.test/resources/5291b3ea-9934-11e0-85be-406186cbf87c.data deleted file mode 100755 index f2145977f46..00000000000 Binary files a/java/com.sap.sailing.domain.test/resources/5291b3ea-9934-11e0-85be-406186cbf87c.data and /dev/null differ diff --git a/java/com.sap.sailing.domain.test/resources/529a4150-2dd0-0131-2830-60a44ce903c3.data b/java/com.sap.sailing.domain.test/resources/529a4150-2dd0-0131-2830-60a44ce903c3.data deleted file mode 100755 index cdc070b0832..00000000000 Binary files a/java/com.sap.sailing.domain.test/resources/529a4150-2dd0-0131-2830-60a44ce903c3.data and /dev/null differ diff --git a/java/com.sap.sailing.domain.test/resources/65099a64-245d-11e2-9635-10bf48d758ce.data b/java/com.sap.sailing.domain.test/resources/65099a64-245d-11e2-9635-10bf48d758ce.data deleted file mode 100755 index f8e83ac11f6..00000000000 Binary files a/java/com.sap.sailing.domain.test/resources/65099a64-245d-11e2-9635-10bf48d758ce.data and /dev/null differ diff --git a/java/com.sap.sailing.domain.test/resources/92d1755e-9dde-11e0-85be-406186cbf87c.data b/java/com.sap.sailing.domain.test/resources/92d1755e-9dde-11e0-85be-406186cbf87c.data deleted file mode 100755 index 7bc750daa1e..00000000000 Binary files a/java/com.sap.sailing.domain.test/resources/92d1755e-9dde-11e0-85be-406186cbf87c.data and /dev/null differ diff --git a/java/com.sap.sailing.domain.test/resources/bca3b490-2dce-0131-27f0-60a44ce903c3.data b/java/com.sap.sailing.domain.test/resources/bca3b490-2dce-0131-27f0-60a44ce903c3.data deleted file mode 100755 index 9210cc22c2e..00000000000 Binary files a/java/com.sap.sailing.domain.test/resources/bca3b490-2dce-0131-27f0-60a44ce903c3.data and /dev/null differ diff --git a/java/com.sap.sailing.domain.test/resources/cb043bb4-9e92-11e0-85be-406186cbf87c.data b/java/com.sap.sailing.domain.test/resources/cb043bb4-9e92-11e0-85be-406186cbf87c.data deleted file mode 100755 index 0230efa152d..00000000000 Binary files a/java/com.sap.sailing.domain.test/resources/cb043bb4-9e92-11e0-85be-406186cbf87c.data and /dev/null differ diff --git a/java/com.sap.sailing.domain.test/resources/d591d808-9c48-11e0-85be-406186cbf87c.data b/java/com.sap.sailing.domain.test/resources/d591d808-9c48-11e0-85be-406186cbf87c.data deleted file mode 100755 index b8f57f6461f..00000000000 Binary files a/java/com.sap.sailing.domain.test/resources/d591d808-9c48-11e0-85be-406186cbf87c.data and /dev/null differ diff --git a/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/DurationTest.java b/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/DurationTest.java new file mode 100755 index 00000000000..f4e44605c6d --- /dev/null +++ b/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/DurationTest.java @@ -0,0 +1,36 @@ +package com.sap.sailing.domain.test; + +import static org.junit.Assert.assertEquals; + +import org.junit.Test; + +import com.sap.sailing.domain.common.Duration; +import com.sap.sailing.domain.common.TimePoint; +import com.sap.sailing.domain.common.impl.MillisecondsDurationImpl; +import com.sap.sailing.domain.common.impl.MillisecondsTimePoint; + +public class DurationTest { + @Test + public void testDurationPlus() { + TimePoint t1 = new MillisecondsTimePoint(123); + Duration d = new MillisecondsDurationImpl(234); + TimePoint t2 = t1.plus(d); + assertEquals(123+234, t2.asMillis()); + } + + @Test + public void testDurationMinus() { + TimePoint t1 = new MillisecondsTimePoint(234); + Duration d = new MillisecondsDurationImpl(123); + TimePoint t2 = t1.minus(d); + assertEquals(234-123, t2.asMillis()); + } + + @Test + public void testDurationUntil() { + TimePoint t1 = new MillisecondsTimePoint(123); + TimePoint t2 = new MillisecondsTimePoint(234); + Duration d = t1.until(t2); + assertEquals(234-123, d.asMillis()); + } +} diff --git a/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/LeaderboardScoringAndRankingTest.java b/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/LeaderboardScoringAndRankingTest.java index 986e837e7e5..3f0daa9a470 100644 --- a/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/LeaderboardScoringAndRankingTest.java +++ b/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/LeaderboardScoringAndRankingTest.java @@ -10,9 +10,11 @@ import java.util.Arrays; import java.util.Collections; import java.util.HashMap; import java.util.Iterator; +import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.NavigableSet; +import java.util.Set; import org.junit.Test; @@ -24,8 +26,8 @@ import com.sap.sailing.domain.base.RaceColumn; import com.sap.sailing.domain.base.Regatta; import com.sap.sailing.domain.base.Series; import com.sap.sailing.domain.base.Waypoint; -import com.sap.sailing.domain.base.impl.FleetImpl; import com.sap.sailing.domain.base.impl.ControlPointWithTwoMarksImpl; +import com.sap.sailing.domain.base.impl.FleetImpl; import com.sap.sailing.domain.base.impl.MarkImpl; import com.sap.sailing.domain.base.impl.RegattaImpl; import com.sap.sailing.domain.base.impl.SeriesImpl; @@ -43,6 +45,7 @@ import com.sap.sailing.domain.leaderboard.ScoringScheme; import com.sap.sailing.domain.leaderboard.impl.FlexibleLeaderboardImpl; import com.sap.sailing.domain.leaderboard.impl.HighPoint; import com.sap.sailing.domain.leaderboard.impl.HighPointExtremeSailingSeriesOverall; +import com.sap.sailing.domain.leaderboard.impl.HighPointFirstGets10LastBreaksTie; import com.sap.sailing.domain.leaderboard.impl.LeaderboardGroupImpl; import com.sap.sailing.domain.leaderboard.impl.LowPoint; import com.sap.sailing.domain.leaderboard.impl.RegattaLeaderboardImpl; @@ -764,7 +767,7 @@ public class LeaderboardScoringAndRankingTest extends AbstractLeaderboardTest { assertEquals(leaderboard.getTotalPoints(c[0], later), leaderboard.getTotalPoints(c[1], later), 0.000000001); assertEquals(rankedCompetitors.indexOf(c[0]), rankedCompetitors.indexOf(c[1])-1); } - + @Test public void testTieBreakWithEqualWinsAndTwoVersusOneSecondsWithHighPointScoringScheme() throws NoWindException { Competitor[] c = createCompetitors(4).toArray(new Competitor[0]); @@ -785,6 +788,46 @@ public class LeaderboardScoringAndRankingTest extends AbstractLeaderboardTest { assertEquals(rankedCompetitors.indexOf(c[0]), rankedCompetitors.indexOf(c[1])-1); } + @Test + public void testCompetitorsRankedEleventhOrLowerGetOnePointScore() throws NoWindException { + Competitor[] competitors = createCompetitors(16).toArray(new Competitor[0]); + TimePoint now = MillisecondsTimePoint.now(); + TimePoint later = new MillisecondsTimePoint(now.asMillis()+1000); + FlexibleLeaderboard leaderboardHighPoint10LastBreaksTie = new FlexibleLeaderboardImpl("Test ESS Highpoint 10LastBreaksTie", new ThresholdBasedResultDiscardingRuleImpl(/* discarding thresholds */ new int[0]), + new HighPointFirstGets10LastBreaksTie(), null); + leaderboardHighPoint10LastBreaksTie.addRace(new MockedTrackedRaceWithStartTimeAndRanks(now, Arrays.asList(competitors)), "R1", /* medalRace */ false, + leaderboardHighPoint10LastBreaksTie.getFleet(null)); + assertTrue(leaderboardHighPoint10LastBreaksTie.getScoringScheme().getScoreComparator(/* nullScoresAreBetter */ false).compare( + leaderboardHighPoint10LastBreaksTie.getTotalPoints(competitors[0], later), leaderboardHighPoint10LastBreaksTie.getTotalPoints(competitors[3], later)) < 0); // c0 better than c3 + assertEquals(16, leaderboardHighPoint10LastBreaksTie.getCompetitorsFromBestToWorst(later).size()); + assertEquals(new Double(10), leaderboardHighPoint10LastBreaksTie.getTotalPoints(competitors[0], later)); + assertEquals(new Double(1), leaderboardHighPoint10LastBreaksTie.getTotalPoints(competitors[15], later)); + // Normal HighPoint leaderboard has no max so that winner gets as many points as there are competitors + FlexibleLeaderboard leaderboardHighPoint = new FlexibleLeaderboardImpl("Test ESS Highpoint", new ThresholdBasedResultDiscardingRuleImpl(/* discarding thresholds */ new int[0]), + new HighPoint(), null); + leaderboardHighPoint.addRace(new MockedTrackedRaceWithStartTimeAndRanks(now, Arrays.asList(competitors)), "R1", /* medalRace */ false, + leaderboardHighPoint.getFleet(null)); + assertEquals(16, leaderboardHighPoint.getCompetitorsFromBestToWorst(later).size()); + assertEquals(new Double(16), leaderboardHighPoint.getTotalPoints(competitors[0], later)); + FlexibleLeaderboard leaderboardHighPointESSOverall = new FlexibleLeaderboardImpl("Test ESS Highpoint Overall", new ThresholdBasedResultDiscardingRuleImpl(/* discarding thresholds */ new int[0]), + new HighPointExtremeSailingSeriesOverall(), null); + leaderboardHighPointESSOverall.addRace(new MockedTrackedRaceWithStartTimeAndRanks(now, Arrays.asList(competitors)), "R1", /* medalRace */ false, + leaderboardHighPointESSOverall.getFleet(null)); + assertEquals(16, leaderboardHighPointESSOverall.getCompetitorsFromBestToWorst(later).size()); + assertEquals(new Double(10), leaderboardHighPointESSOverall.getTotalPoints(competitors[0], later)); + assertEquals(new Double(9), leaderboardHighPointESSOverall.getTotalPoints(competitors[1], later)); + assertEquals(new Double(8), leaderboardHighPointESSOverall.getTotalPoints(competitors[2], later)); + assertEquals(new Double(7), leaderboardHighPointESSOverall.getTotalPoints(competitors[3], later)); + assertEquals(new Double(6), leaderboardHighPointESSOverall.getTotalPoints(competitors[4], later)); + assertEquals(new Double(5), leaderboardHighPointESSOverall.getTotalPoints(competitors[5], later)); + assertEquals(new Double(4), leaderboardHighPointESSOverall.getTotalPoints(competitors[6], later)); + assertEquals(new Double(3), leaderboardHighPointESSOverall.getTotalPoints(competitors[7], later)); + assertEquals(new Double(2), leaderboardHighPointESSOverall.getTotalPoints(competitors[8], later)); + assertEquals(new Double(1), leaderboardHighPointESSOverall.getTotalPoints(competitors[9], later)); + assertEquals(new Double(1), leaderboardHighPointESSOverall.getTotalPoints(competitors[14], later)); + assertEquals(new Double(1), leaderboardHighPointESSOverall.getTotalPoints(competitors[15], later)); + } + @Test public void testOverallLeaderboardWithESSHighPointScoring() throws NoWindException { // Let c0 lead the series, c3 trail it, c1 and c2 are one-time competitors which are then suppressed in the @@ -1024,4 +1067,126 @@ public class LeaderboardScoringAndRankingTest extends AbstractLeaderboardTest { Regatta regatta = new RegattaImpl(regattaBaseName, boatClass, series, /* persistent */ false, scoringScheme, "123", null); return regatta; } + + /** + * See bug 1260. There must be a possibility to have ordered fleets that are scored such that the winner of the race of the best fleet + * gets the best score in that column; and the winner of the second-best fleet gets the n-th best score in the column with n being the + * number of competitors in the best fleet plus one; and so on. At the same time, while for a regular ISAF regatta format the participation + * in a better fleet will always let those competitors rank better than all participants of worse fleets, here the fleet pertinence shall + * not matter for the global ranking. + */ + @Test + public void testTotalRankComparatorForOrderedSplitFleetsWhoseOrderingDoesNotPersist() throws NoWindException { + series = new ArrayList(); + final int numberOfBeforeRaces = 1; + // -------- before series ------------ + { + Set beforeFleets = Collections.singleton(new FleetImpl("Default")); + List beforeRaceColumnNames = new ArrayList(); + for (int i = 1; i <= numberOfBeforeRaces; i++) { + beforeRaceColumnNames.add("R" + i); + } + Series qualifyingSeries = new SeriesImpl("Before", /* isMedal */false, beforeFleets, + beforeRaceColumnNames, /* trackedRegattaRegistry */null); + series.add(qualifyingSeries); + } + // -------- knock-out qualification series ------------ + { + List qualificationFleets = new ArrayList(); + for (String qualificationFleetName : new String[] { "Yellow", "Blue" }) { + qualificationFleets.add(new FleetImpl(qualificationFleetName)); + } + List qualificationRaceColumnNames = new ArrayList(); + qualificationRaceColumnNames.add("Q"); + Series qualificationSeries = new SeriesImpl("Qualification", /* isMedal */false, qualificationFleets, qualificationRaceColumnNames, /* trackedRegattaRegistry */ null); + // discard the one and only qualification race; it doesn't score + qualificationSeries.setResultDiscardingRule(new ThresholdBasedResultDiscardingRuleImpl(new int[] { 1 })); + series.add(qualificationSeries); + } + + // -------- knock-out final series ------------ + { + List finalFleets = new ArrayList(); + int fleetOrdering = 1; + for (String finalFleetName : new String[] { "Gold", "Silver" }) { + finalFleets.add(new FleetImpl(finalFleetName, fleetOrdering++)); + } + List finalRaceColumnNames = new ArrayList(); + finalRaceColumnNames.add("F"); + Series finalSeries = new SeriesImpl("Final", /* isMedal */false, finalFleets, finalRaceColumnNames, /* trackedRegattaRegistry */ null); + finalSeries.setSplitFleetContiguousScoring(true); + series.add(finalSeries); + } + // -------- after series ------------ + { + final int numberOfFinalRaces = 1; + Set afterFleets = Collections.singleton(new FleetImpl("Default")); + List finalRaceColumnNames = new ArrayList(); + for (int i = numberOfBeforeRaces+1; i <= numberOfBeforeRaces+numberOfFinalRaces; i++) { + finalRaceColumnNames.add("R" + i); + } + Series finalSeries = new SeriesImpl("After", /* isMedal */false, afterFleets, finalRaceColumnNames, /* trackedRegattaRegistry */ null); + series.add(finalSeries); + } + Regatta regatta = new RegattaImpl("Test Regatta",DomainFactory.INSTANCE.getOrCreateBoatClass("Extreme40", /* typicallyStartsUpwind */ false), + series, /* persistent */false, DomainFactory.INSTANCE.createScoringScheme(ScoringSchemeType.HIGH_POINT_FIRST_GETS_TEN), "123", /* course area */null); + List competitors = createCompetitors(12); + final int firstYellowCompetitorIndex = 3; + List yellow = new ArrayList<>(competitors.subList(firstYellowCompetitorIndex, firstYellowCompetitorIndex+6)); + List blue = new ArrayList<>(competitors); + blue.removeAll(yellow); + Collections.shuffle(yellow); + Collections.shuffle(blue); + final int firstGoldCompetitorIndex = 5; + List gold = new ArrayList<>(competitors.subList(firstGoldCompetitorIndex, firstGoldCompetitorIndex+6)); + List silver = new ArrayList<>(competitors); + silver.removeAll(gold); + Collections.shuffle(gold); + Collections.shuffle(silver); + + Leaderboard leaderboard = createLeaderboard(regatta, /* discarding thresholds */ new int[0]); + TimePoint now = MillisecondsTimePoint.now(); + TimePoint later = new MillisecondsTimePoint(now.asMillis()+1000); + RaceColumn r1Column = series.get(0).getRaceColumnByName("R1"); + TrackedRace r1Default = new MockedTrackedRaceWithStartTimeAndRanks(now, competitors); + r1Column.setTrackedRace(r1Column.getFleetByName("Default"), r1Default); + RaceColumn qColumn = series.get(1).getRaceColumnByName("Q"); + TrackedRace qYellow = new MockedTrackedRaceWithStartTimeAndRanks(now, yellow); + qColumn.setTrackedRace(qColumn.getFleetByName("Yellow"), qYellow); + TrackedRace qBlue = new MockedTrackedRaceWithStartTimeAndRanks(now, blue); + qColumn.setTrackedRace(qColumn.getFleetByName("Blue"), qBlue); + RaceColumn f1Column = series.get(2).getRaceColumnByName("F"); + TrackedRace f1Gold = new MockedTrackedRaceWithStartTimeAndRanks(now, gold); + f1Column.setTrackedRace(f1Column.getFleetByName("Gold"), f1Gold); + TrackedRace f1Silver = new MockedTrackedRaceWithStartTimeAndRanks(now, silver); + f1Column.setTrackedRace(f1Column.getFleetByName("Silver"), f1Silver); + RaceColumn r2Column = series.get(3).getRaceColumnByName("R2"); + TrackedRace r2Default = new MockedTrackedRaceWithStartTimeAndRanks(now, competitors); + r2Column.setTrackedRace(r2Column.getFleetByName("Default"), r2Default); + + List rankedCompetitors = leaderboard.getCompetitorsFromBestToWorst(later); + Map totalPoints = new LinkedHashMap<>(); + for (Competitor rankedCompetitor : rankedCompetitors) { + totalPoints.put(rankedCompetitor, leaderboard.getTotalPoints(rankedCompetitor, later)); + } + // assert that the final column competitors are ranked from top to bottom: + double scoreInFinalRace = 10.0; + for (Competitor rankedCompetitor : leaderboard.getCompetitorsFromBestToWorst(f1Column, later)) { + assertEquals(scoreInFinalRace, leaderboard.getTotalPoints(rankedCompetitor, f1Column, later), 0.000001); + scoreInFinalRace = Math.max(scoreInFinalRace-1, 1); + } + double lastScore = Double.MAX_VALUE; + // assert that only the points matter for ranking; not the fleet assignment + for (Competitor rankedCompetitor : rankedCompetitors) { + // with a high-point scoring scheme, assert that as competitors get worse, scores get less + double rankedCompetitorScore = totalPoints.get(rankedCompetitor); + assertTrue("Expected " + rankedCompetitor + " with rank " + + (rankedCompetitors.indexOf(rankedCompetitor) + 1) + + " to have worse (lesser) score than its immediate better competitor who scored " + lastScore + + " but was " + rankedCompetitorScore, rankedCompetitorScore <= lastScore); + lastScore = rankedCompetitorScore; + // assert that the qualification race consistently has zero points for all competitors because it is discarded + assertTrue(leaderboard.isDiscarded(rankedCompetitor, qColumn, later)); + } + } } diff --git a/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/MultipleClassesInRegattaTest.java b/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/MultipleClassesInRegattaTest.java index 8c8bb956879..74096a8454c 100755 --- a/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/MultipleClassesInRegattaTest.java +++ b/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/MultipleClassesInRegattaTest.java @@ -55,25 +55,25 @@ public class MultipleClassesInRegattaTest { httpAndHost+"/events/event_20110505_SailingTea/clientparams.php?event=event_20110505_SailingTea&race=cce678c8-97e6-11e0-9aed-406186cbf87c"), new URI(liveURI), new URI(storedURI), new URI(courseDesignUpdateURI), /* startOfTracking */ null, /* endOfTracking */ null, /* delayToLiveInMillis */ 0l, /* simulateWithStartTimeNow */ false, - EmptyRaceLogStore.INSTANCE, EmptyWindStore.INSTANCE, tracTracUsername, tracTracPassword, new DummyTrackedRegattaRegistry()); + EmptyRaceLogStore.INSTANCE, EmptyWindStore.INSTANCE, tracTracUsername, tracTracPassword, TracTracConnectionConstants.ONLINE_STATUS, new DummyTrackedRegattaRegistry()); kiwotest2 = domainFactory .createRaceTracker( new URL( httpAndHost+"/events/event_20110505_SailingTea/clientparams.php?event=event_20110505_SailingTea&race=11290bd6-97e7-11e0-9aed-406186cbf87c"), new URI(liveURI), new URI(storedURI), new URI(courseDesignUpdateURI), - /* startOfTracking */ null, /* endOfTracking */ null, /* delayToLiveInMillis */ 0l, /* simulateWithStartTimeNow */ false, EmptyRaceLogStore.INSTANCE, EmptyWindStore.INSTANCE, tracTracUsername, tracTracPassword, new DummyTrackedRegattaRegistry()); + /* startOfTracking */ null, /* endOfTracking */ null, /* delayToLiveInMillis */ 0l, /* simulateWithStartTimeNow */ false, EmptyRaceLogStore.INSTANCE, EmptyWindStore.INSTANCE, tracTracUsername, tracTracPassword, TracTracConnectionConstants.ONLINE_STATUS, new DummyTrackedRegattaRegistry()); kiwotest3 = domainFactory .createRaceTracker( new URL( httpAndHost+"/events/event_20110505_SailingTea/clientparams.php?event=event_20110505_SailingTea&race=39635b24-97e7-11e0-9aed-406186cbf87c"), new URI(liveURI), new URI(storedURI), new URI(courseDesignUpdateURI), - /* startOfTracking */ null, /* endOfTracking */ null, /* delayToLiveInMillis */ 0l, /* simulateWithStartTimeNow */ false, EmptyRaceLogStore.INSTANCE, EmptyWindStore.INSTANCE, tracTracUsername, tracTracPassword, new DummyTrackedRegattaRegistry()); + /* startOfTracking */ null, /* endOfTracking */ null, /* delayToLiveInMillis */ 0l, /* simulateWithStartTimeNow */ false, EmptyRaceLogStore.INSTANCE, EmptyWindStore.INSTANCE, tracTracUsername, tracTracPassword, TracTracConnectionConstants.ONLINE_STATUS, new DummyTrackedRegattaRegistry()); weym470may112014_2 = domainFactory .createRaceTracker( new URL( httpAndHost+"/events/event_20110505_SailingTea/clientparams.php?event=event_20110505_SailingTea&race=04498426-7dfd-11e0-8236-406186cbf87c"), new URI(liveURI), new URI(storedURI), new URI(courseDesignUpdateURI), - /* startOfTracking */ null, /* endOfTracking */ null, /* delayToLiveInMillis */ 0l, /* simulateWithStartTimeNow */ false, EmptyRaceLogStore.INSTANCE, EmptyWindStore.INSTANCE, tracTracUsername, tracTracPassword, new DummyTrackedRegattaRegistry()); + /* startOfTracking */ null, /* endOfTracking */ null, /* delayToLiveInMillis */ 0l, /* simulateWithStartTimeNow */ false, EmptyRaceLogStore.INSTANCE, EmptyWindStore.INSTANCE, tracTracUsername, tracTracPassword, TracTracConnectionConstants.ONLINE_STATUS, new DummyTrackedRegattaRegistry()); assertEquals("STG", kiwotest1.getRegatta().getBoatClass().getName()); assertEquals("505", kiwotest2.getRegatta().getBoatClass().getName()); diff --git a/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/TrackTest.java b/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/TrackTest.java index 123ab6d83d1..809b4a1d79a 100755 --- a/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/TrackTest.java +++ b/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/TrackTest.java @@ -1049,4 +1049,10 @@ public class TrackTest { GPSFixMoving fix = new GPSFixMovingImpl(position, timePoint, speed); return fix; } + + @Test + public void testFrequency() { + assertEquals(3, track.getAverageIntervalBetweenFixes().asMillis()); + assertEquals(3, track.getAverageIntervalBetweenRawFixes().asMillis()); + } } diff --git a/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/UnicodeCharactersInCompetitorNamesTest.java b/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/UnicodeCharactersInCompetitorNamesTest.java index fb53e2a9f6e..22e6db0c9fc 100755 --- a/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/UnicodeCharactersInCompetitorNamesTest.java +++ b/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/UnicodeCharactersInCompetitorNamesTest.java @@ -55,7 +55,7 @@ public class UnicodeCharactersInCompetitorNamesTest { + TracTracConnectionConstants.PORT_STORED), new URI("http://tracms.traclive.dk/update_course"), /* startOfTracking */null, /* endOfTracking */null, /* delayToLiveInMillis */0l, - /* simulateWithStartTimeNow */ false, EmptyRaceLogStore.INSTANCE, EmptyWindStore.INSTANCE, "tracTest", "tracTest", + /* simulateWithStartTimeNow */ false, EmptyRaceLogStore.INSTANCE, EmptyWindStore.INSTANCE, "tracTest", "tracTest", "", new DummyTrackedRegattaRegistry()); Iterable competitors = fourtyninerYellow_2.getRacesHandle().getRaces().iterator().next() diff --git a/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/markpassing/FlorianopolisMarkPassingTest.java b/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/markpassing/FlorianopolisMarkPassingTest.java index 008908a9915..8f86449e10d 100755 --- a/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/markpassing/FlorianopolisMarkPassingTest.java +++ b/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/markpassing/FlorianopolisMarkPassingTest.java @@ -14,8 +14,6 @@ import java.net.URISyntaxException; import java.util.ArrayList; import java.util.LinkedHashMap; -import org.junit.Test; - import com.sap.sailing.domain.base.Competitor; import com.sap.sailing.domain.base.Waypoint; import com.sap.sailing.domain.common.WindSourceType; @@ -140,22 +138,18 @@ public class FlorianopolisMarkPassingTest extends OnlineTracTracBasedTest { } - @Test public void testRace1() throws IOException, InterruptedException, URISyntaxException { setUp("bca3b490-2dce-0131-27f0-60a44ce903c3"); testRace(); } - @Test public void testRace2() throws IOException, InterruptedException, URISyntaxException { setUp("52697ec0-2dd0-0131-2802-60a44ce903c3"); testRace(); } - @Test public void testRace3() throws IOException, InterruptedException, URISyntaxException { setUp("528a0f30-2dd0-0131-2819-60a44ce903c3"); testRace(); } - @Test public void testRace4() throws IOException, InterruptedException, URISyntaxException { setUp("529a4150-2dd0-0131-2830-60a44ce903c3"); testRace(); diff --git a/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/markpassing/OBMRMarkPassingTest.java b/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/markpassing/OBMRMarkPassingTest.java index a0bee3625da..f5149657862 100755 --- a/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/markpassing/OBMRMarkPassingTest.java +++ b/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/markpassing/OBMRMarkPassingTest.java @@ -14,8 +14,6 @@ import java.net.URISyntaxException; import java.util.ArrayList; import java.util.LinkedHashMap; -import org.junit.Test; - import com.sap.sailing.domain.base.Competitor; import com.sap.sailing.domain.base.Waypoint; import com.sap.sailing.domain.common.WindSourceType; @@ -140,7 +138,6 @@ public class OBMRMarkPassingTest extends OnlineTracTracBasedTest { } - @Test public void testRace1() throws IOException, InterruptedException, URISyntaxException { setUp("65099a64-245d-11e2-9635-10bf48d758ce"); testRace(); diff --git a/java/com.sap.sailing.domain.tractracadapter/src/com/sap/sailing/domain/tractracadapter/DomainFactory.java b/java/com.sap.sailing.domain.tractracadapter/src/com/sap/sailing/domain/tractracadapter/DomainFactory.java index a90d99fadd2..7c8840df88f 100755 --- a/java/com.sap.sailing.domain.tractracadapter/src/com/sap/sailing/domain/tractracadapter/DomainFactory.java +++ b/java/com.sap.sailing.domain.tractracadapter/src/com/sap/sailing/domain/tractracadapter/DomainFactory.java @@ -132,16 +132,17 @@ public interface DomainFactory { */ TracTracRaceTracker createRaceTracker(URL paramURL, URI liveURI, URI storedURI, URI courseDesignUpdateURI, TimePoint startOfTracking, TimePoint endOfTracking, long delayToLiveInMillis, boolean simulateWithStartTimeNow, RaceLogStore raceLogStore, - WindStore windStore, String tracTracUsername, String tracTracPassword, TrackedRegattaRegistry trackedRegattaRegistry) throws MalformedURLException, FileNotFoundException, + WindStore windStore, String tracTracUsername, String tracTracPassword, String raceStatus, TrackedRegattaRegistry trackedRegattaRegistry) throws MalformedURLException, FileNotFoundException, URISyntaxException; /** * Same as {@link #createRaceTracker(URL, URI, URI, URI, TimePoint, TimePoint, WindStore, TrackedRegattaRegistry)}, only that * a predefined {@link Regatta} is used to hold the resulting races. + * @param raceStatus */ RaceTracker createRaceTracker(Regatta regatta, URL paramURL, URI liveURI, URI storedURI, URI courseDesignUpdateURI, TimePoint startOfTracking, TimePoint endOfTracking, long delayToLiveInMillis, boolean simulateWithStartTimeNow, RaceLogStore raceLogStore, - WindStore windStore, String tracTracUsername, String tracTracPassword, TrackedRegattaRegistry trackedRegattaRegistry) throws MalformedURLException, FileNotFoundException, + WindStore windStore, String tracTracUsername, String tracTracPassword, String raceStatus, TrackedRegattaRegistry trackedRegattaRegistry) throws MalformedURLException, FileNotFoundException, URISyntaxException; BoatClass getOrCreateBoatClass(String competitorClassName); @@ -251,7 +252,7 @@ public interface DomainFactory { RaceTrackingConnectivityParameters createTrackingConnectivityParameters(URL paramURL, URI liveURI, URI storedURI, URI courseDesignUpdateURI, TimePoint startOfTracking, TimePoint endOfTracking, long delayToLiveInMillis, boolean simulateWithStartTimeNow, RaceLogStore raceLogStore, - String tracTracUsername, String tracTracPassword); + String tracTracUsername, String tracTracPassword, String raceStatus); /** * Removes all knowledge about tractracRace which includes removing it from the race cache, from the * {@link com.sap.sailing.domain.base.Regatta} and, if a {@link TrackedRace} for the corresponding diff --git a/java/com.sap.sailing.domain.tractracadapter/src/com/sap/sailing/domain/tractracadapter/TracTracAdapter.java b/java/com.sap.sailing.domain.tractracadapter/src/com/sap/sailing/domain/tractracadapter/TracTracAdapter.java index 0b3f2864b12..ab116e5149e 100755 --- a/java/com.sap.sailing.domain.tractracadapter/src/com/sap/sailing/domain/tractracadapter/TracTracAdapter.java +++ b/java/com.sap.sailing.domain.tractracadapter/src/com/sap/sailing/domain/tractracadapter/TracTracAdapter.java @@ -48,7 +48,7 @@ public interface TracTracAdapter { */ RacesHandle addTracTracRace(TrackerManager trackerManager, URL paramURL, URI liveURI, URI storedURI, URI courseDesignUpdateURI, RaceLogStore raceLogStore, long timeoutInMilliseconds, - String tracTracUsername, String tracTracPassword) throws MalformedURLException, FileNotFoundException, URISyntaxException, Exception; + String tracTracUsername, String tracTracPassword, String raceStatus) throws MalformedURLException, FileNotFoundException, URISyntaxException, Exception; /** * Same as {@link #addTracTracRace(URL, URI, URI, WindStore, long)}, only that start and end of tracking are @@ -63,11 +63,12 @@ public interface TracTracAdapter { * created, with a single default series and a single default fleet. If a valid {@link RegattaIdentifier} * is specified, a regatta lookup is performed with that identifier; if the regatta is found, it is used * to add the races to. Otherwise, a default regatta as described above will be created and used. + * @param raceStatus */ RacesHandle addTracTracRace(TrackerManager trackerManager, RegattaIdentifier regattaToAddTo, URL paramURL, URI liveURI, URI storedURI, URI courseDesignUpdateURI, TimePoint trackingStartTime, TimePoint trackingEndTime, RaceLogStore raceLogStore, - long timeoutForReceivingRaceDefinitionInMilliseconds, boolean simulateWithStartTimeNow, String tracTracUsername, String tracTracPassword) + long timeoutForReceivingRaceDefinitionInMilliseconds, boolean simulateWithStartTimeNow, String tracTracUsername, String tracTracPassword, String raceStatus) throws MalformedURLException, FileNotFoundException, URISyntaxException, Exception; /** diff --git a/java/com.sap.sailing.domain.tractracadapter/src/com/sap/sailing/domain/tractracadapter/TracTracConnectionConstants.java b/java/com.sap.sailing.domain.tractracadapter/src/com/sap/sailing/domain/tractracadapter/TracTracConnectionConstants.java index edfc7f46342..5e94cb6e389 100644 --- a/java/com.sap.sailing.domain.tractracadapter/src/com/sap/sailing/domain/tractracadapter/TracTracConnectionConstants.java +++ b/java/com.sap.sailing.domain.tractracadapter/src/com/sap/sailing/domain/tractracadapter/TracTracConnectionConstants.java @@ -11,6 +11,7 @@ public interface TracTracConnectionConstants { final int PORT_STORED = PORT_LIVE + 1; //For official usage use 4401; final String HIDDEN_STATUS = "HIDDEN"; + final String ONLINE_STATUS = "ONLINE"; final Object REPLAY_STATUS = "REPLAY"; } diff --git a/java/com.sap.sailing.domain.tractracadapter/src/com/sap/sailing/domain/tractracadapter/impl/DomainFactoryImpl.java b/java/com.sap.sailing.domain.tractracadapter/src/com/sap/sailing/domain/tractracadapter/impl/DomainFactoryImpl.java index dd32cd20d08..c355018b3eb 100644 --- a/java/com.sap.sailing.domain.tractracadapter/src/com/sap/sailing/domain/tractracadapter/impl/DomainFactoryImpl.java +++ b/java/com.sap.sailing.domain.tractracadapter/src/com/sap/sailing/domain/tractracadapter/impl/DomainFactoryImpl.java @@ -608,20 +608,20 @@ public class DomainFactoryImpl implements DomainFactory { @Override public TracTracRaceTracker createRaceTracker(URL paramURL, URI liveURI, URI storedURI, URI courseDesignUpdateURI, TimePoint startOfTracking, TimePoint endOfTracking, long delayToLiveInMillis, boolean simulateWithStartTimeNow, - RaceLogStore raceLogStore, WindStore windStore, String tracTracUsername, String tracTracPassword, + RaceLogStore raceLogStore, WindStore windStore, String tracTracUsername, String tracTracPassword, String raceStatus, TrackedRegattaRegistry trackedRegattaRegistry) throws MalformedURLException, FileNotFoundException, URISyntaxException { return new TracTracRaceTrackerImpl(this, paramURL, liveURI, storedURI, courseDesignUpdateURI, startOfTracking, endOfTracking, delayToLiveInMillis, - simulateWithStartTimeNow, raceLogStore, windStore, tracTracUsername, tracTracPassword, trackedRegattaRegistry); + simulateWithStartTimeNow, raceLogStore, windStore, tracTracUsername, tracTracPassword, raceStatus, trackedRegattaRegistry); } @Override public RaceTracker createRaceTracker(Regatta regatta, URL paramURL, URI liveURI, URI storedURI, URI courseDesignUpdateURI, TimePoint startOfTracking, TimePoint endOfTracking, long delayToLiveInMillis, - boolean simulateWithStartTimeNow, RaceLogStore raceLogStore, WindStore windStore, String tracTracUsername, String tracTracPassword, TrackedRegattaRegistry trackedRegattaRegistry) + boolean simulateWithStartTimeNow, RaceLogStore raceLogStore, WindStore windStore, String tracTracUsername, String tracTracPassword, String raceStatus, TrackedRegattaRegistry trackedRegattaRegistry) throws MalformedURLException, FileNotFoundException, URISyntaxException { return new TracTracRaceTrackerImpl(regatta, this, paramURL, liveURI, storedURI, courseDesignUpdateURI, startOfTracking, endOfTracking, delayToLiveInMillis, - simulateWithStartTimeNow, raceLogStore, windStore, tracTracUsername, tracTracPassword, trackedRegattaRegistry); + simulateWithStartTimeNow, raceLogStore, windStore, tracTracUsername, tracTracPassword, raceStatus, trackedRegattaRegistry); } @Override @@ -637,9 +637,9 @@ public class DomainFactoryImpl implements DomainFactory { @Override public RaceTrackingConnectivityParameters createTrackingConnectivityParameters(URL paramURL, URI liveURI, URI storedURI, URI courseDesignUpdateURI, TimePoint startOfTracking, TimePoint endOfTracking, long delayToLiveInMillis, - boolean simulateWithStartTimeNow, RaceLogStore raceLogStore, String tracTracUsername, String tracTracPassword) { + boolean simulateWithStartTimeNow, RaceLogStore raceLogStore, String tracTracUsername, String tracTracPassword, String raceStatus) { return new RaceTrackingConnectivityParametersImpl(paramURL, liveURI, storedURI, courseDesignUpdateURI, startOfTracking, endOfTracking, - delayToLiveInMillis, simulateWithStartTimeNow, raceLogStore, this, tracTracUsername, tracTracPassword); + delayToLiveInMillis, simulateWithStartTimeNow, raceLogStore, this, tracTracUsername, tracTracPassword, raceStatus); } @Override diff --git a/java/com.sap.sailing.domain.tractracadapter/src/com/sap/sailing/domain/tractracadapter/impl/RaceTrackingConnectivityParametersImpl.java b/java/com.sap.sailing.domain.tractracadapter/src/com/sap/sailing/domain/tractracadapter/impl/RaceTrackingConnectivityParametersImpl.java index d5b5118ac0b..5974079a7cd 100755 --- a/java/com.sap.sailing.domain.tractracadapter/src/com/sap/sailing/domain/tractracadapter/impl/RaceTrackingConnectivityParametersImpl.java +++ b/java/com.sap.sailing.domain.tractracadapter/src/com/sap/sailing/domain/tractracadapter/impl/RaceTrackingConnectivityParametersImpl.java @@ -29,10 +29,11 @@ public class RaceTrackingConnectivityParametersImpl implements RaceTrackingConne private final boolean simulateWithStartTimeNow; private final String tracTracUsername; private final String tracTracPassword; + private final String raceStatus; public RaceTrackingConnectivityParametersImpl(URL paramURL, URI liveURI, URI storedURI, URI courseDesignUpdateURI, TimePoint startOfTracking, TimePoint endOfTracking, long delayToLiveInMillis, boolean simulateWithStartTimeNow, - RaceLogStore raceLogStore, DomainFactory domainFactory, String tracTracUsername, String tracTracPassword) { + RaceLogStore raceLogStore, DomainFactory domainFactory, String tracTracUsername, String tracTracPassword, String raceStatus) { super(); this.paramURL = paramURL; this.liveURI = liveURI; @@ -46,13 +47,14 @@ public class RaceTrackingConnectivityParametersImpl implements RaceTrackingConne this.raceLogStore = raceLogStore; this.tracTracUsername = tracTracUsername; this.tracTracPassword = tracTracPassword; + this.raceStatus = raceStatus; } @Override public RaceTracker createRaceTracker(TrackedRegattaRegistry trackedRegattaRegistry, WindStore windStore) throws MalformedURLException, FileNotFoundException, URISyntaxException { RaceTracker tracker = domainFactory.createRaceTracker(paramURL, liveURI, storedURI, courseDesignUpdateURI, startOfTracking, - endOfTracking, delayToLiveInMillis, simulateWithStartTimeNow, raceLogStore, windStore, tracTracUsername, tracTracPassword, trackedRegattaRegistry); + endOfTracking, delayToLiveInMillis, simulateWithStartTimeNow, raceLogStore, windStore, tracTracUsername, tracTracPassword, raceStatus, trackedRegattaRegistry); return tracker; } @@ -60,7 +62,7 @@ public class RaceTrackingConnectivityParametersImpl implements RaceTrackingConne public RaceTracker createRaceTracker(Regatta regatta, TrackedRegattaRegistry trackedRegattaRegistry, WindStore windStore) throws Exception { RaceTracker tracker = domainFactory.createRaceTracker(regatta, paramURL, liveURI, storedURI, courseDesignUpdateURI, startOfTracking, - endOfTracking, delayToLiveInMillis, simulateWithStartTimeNow, raceLogStore, windStore, tracTracUsername, tracTracPassword, trackedRegattaRegistry); + endOfTracking, delayToLiveInMillis, simulateWithStartTimeNow, raceLogStore, windStore, tracTracUsername, tracTracPassword, raceStatus, trackedRegattaRegistry); return tracker; } diff --git a/java/com.sap.sailing.domain.tractracadapter/src/com/sap/sailing/domain/tractracadapter/impl/TracTracAdapterImpl.java b/java/com.sap.sailing.domain.tractracadapter/src/com/sap/sailing/domain/tractracadapter/impl/TracTracAdapterImpl.java index 81b075a0300..9c068699ad2 100755 --- a/java/com.sap.sailing.domain.tractracadapter/src/com/sap/sailing/domain/tractracadapter/impl/TracTracAdapterImpl.java +++ b/java/com.sap.sailing.domain.tractracadapter/src/com/sap/sailing/domain/tractracadapter/impl/TracTracAdapterImpl.java @@ -48,26 +48,27 @@ public class TracTracAdapterImpl implements TracTracAdapter { @Override public RacesHandle addTracTracRace(TrackerManager trackerManager, URL paramURL, URI liveURI, URI storedURI, URI courseDesignUpdateURI, RaceLogStore raceLogStore, long timeoutInMilliseconds, - String tracTracUsername, String tracTracPassword) throws Exception { + String tracTracUsername, String tracTracPassword, String raceStatus) throws Exception { return trackerManager.addRace( /* regattaToAddTo */null, getTracTracDomainFactory().createTrackingConnectivityParameters(paramURL, liveURI, storedURI, courseDesignUpdateURI, /* startOfTracking */null, /* endOfTracking */null, delayToLiveInMillis, /* simulateWithStartTimeNow */false, - raceLogStore, tracTracUsername, tracTracPassword), timeoutInMilliseconds); + raceLogStore, tracTracUsername, tracTracPassword, raceStatus), timeoutInMilliseconds); } @Override public RacesHandle addTracTracRace(TrackerManager trackerManager, RegattaIdentifier regattaToAddTo, URL paramURL, URI liveURI, URI storedURI, URI courseDesignUpdateURI, TimePoint startOfTracking, TimePoint endOfTracking, RaceLogStore raceLogStore, - long timeoutInMilliseconds, boolean simulateWithStartTimeNow, String tracTracUsername, String tracTracPassword) throws Exception { + long timeoutInMilliseconds, boolean simulateWithStartTimeNow, String tracTracUsername, + String tracTracPassword, String raceStatus) throws Exception { return trackerManager.addRace( regattaToAddTo, getTracTracDomainFactory().createTrackingConnectivityParameters(paramURL, liveURI, storedURI, courseDesignUpdateURI, startOfTracking, endOfTracking, delayToLiveInMillis, - simulateWithStartTimeNow, raceLogStore, tracTracUsername, tracTracPassword), + simulateWithStartTimeNow, raceLogStore, tracTracUsername, tracTracPassword, raceStatus), timeoutInMilliseconds); } @@ -88,7 +89,7 @@ public class TracTracAdapterImpl implements TracTracAdapter { for (RaceRecord rr : jsonService.getRaceRecords()) { URL paramURL = rr.getParamURL(); regatta = addTracTracRace(trackerManager, paramURL, liveURI, storedURI, courseDesignUpdateURI, raceLogStore, - timeoutInMilliseconds, tracTracUsername, tracTracPassword).getRegatta(); + timeoutInMilliseconds, tracTracUsername, "", tracTracPassword).getRegatta(); } return regatta; } diff --git a/java/com.sap.sailing.domain.tractracadapter/src/com/sap/sailing/domain/tractracadapter/impl/TracTracRaceTrackerImpl.java b/java/com.sap.sailing.domain.tractracadapter/src/com/sap/sailing/domain/tractracadapter/impl/TracTracRaceTrackerImpl.java index 3b5f28e8a3a..b1c444834bb 100755 --- a/java/com.sap.sailing.domain.tractracadapter/src/com/sap/sailing/domain/tractracadapter/impl/TracTracRaceTrackerImpl.java +++ b/java/com.sap.sailing.domain.tractracadapter/src/com/sap/sailing/domain/tractracadapter/impl/TracTracRaceTrackerImpl.java @@ -63,6 +63,7 @@ import com.sap.sailing.domain.tracking.impl.GPSFixImpl; import com.sap.sailing.domain.tracking.impl.TrackedRaceStatusImpl; import com.sap.sailing.domain.tractracadapter.DomainFactory; import com.sap.sailing.domain.tractracadapter.Receiver; +import com.sap.sailing.domain.tractracadapter.TracTracConnectionConstants; import com.sap.sailing.domain.tractracadapter.TracTracControlPoint; import com.sap.sailing.domain.tractracadapter.TracTracRaceTracker; import com.tractrac.clientmodule.ControlPoint; @@ -98,7 +99,9 @@ public class TracTracRaceTrackerImpl extends AbstractRaceTrackerImpl implements * reported by the threads. The function that calculates the total progress is: * *

-     *   total_progress = sum(progress(thread_i)) / sum(weight(thread_i))
+ * total_progress = sum(progress(thread_i)) / sum(weight(thread_i)) + * + * * The weight is also the maximum individual progress that a thread can send: if a thread has a weight = 10 its * progress only can be between 0 and 10, e.g,: *

@@ -112,35 +115,81 @@ public class TracTracRaceTrackerImpl extends AbstractRaceTrackerImpl implements * The total progress that you receive is: * *

-     *   total_progress = 0 + 0 / 10 + 1 = 0 / 11 = 0
+ * total_progress = 0 + 0 / 10 + 1 = 0 / 11 = 0 + * * * Then, the "Course thread" retrieves the course from the server and it sends a new progress message to the system: * *
-     *   Course thread -> weight = 1, progress = 1  ---> total_progress = 0 + 1 /  10 + 1 = 1 / 11 = 0.090909091
+ * Course thread -> weight = 1, progress = 1 ---> total_progress = 0 + 1 / 10 + 1 = 1 / 11 = 0.090909091 + * * * Then, the "Competitor positions thread" goes to the server and it checks that there is a high number of positions * for the competitors. It decides to change its weight: * *
-     *   Competitor positions thread -> weight = 50, progress = 0 --> total_progress = 0 + 1 / 50 + 1 = 1 / 51 = 0.019607843
+ * Competitor positions thread -> weight = 50, progress = 0 --> total_progress = 0 + 1 / 50 + 1 = 1 / 51 = 0.019607843 + * * * Then, the "Competitor positions thread" starts to retrieve positions and it sends several messages updating the * progress: *
    - *
  • Competitor positions thread -> weight = 50, progress = 1 --> total_progress = 1 + 1 / 50 + 1 = 2 / 51 = 0.039215686
  • - *
  • Competitor positions thread -> weight = 50, progress = 2 --> total_progress = 2 + 1 / 50 + 1 = 3 / 51 = 0.058823529
  • - *
  • Competitor positions thread -> weight = 50, progress = 3 --> total_progress = 3 + 1 / 50 + 1 = 4 / 51 = 0.078431373
  • - *
  • ...
  • - *
  • Competitor positions thread -> weight = 50, progress = 50 --> total_progress = 50 + 1 / 50 + 1 = 51 / 51 = 1.0
  • + *
  • + * + *
    +     * Competitor positions thread -> weight = 50, progress = 1 --> total_progress = 1 + 1 / 50 + 1 = 2 / 51 = 0.039215686
    +     * 
    + * + *
  • + *
  • + * + *
    +     * Competitor positions thread -> weight = 50, progress = 2 --> total_progress = 2 + 1 / 50 + 1 = 3 / 51 = 0.058823529
    +     * 
    + * + *
  • + *
  • + * + *
    +     * Competitor positions thread -> weight = 50, progress = 3 --> total_progress = 3 + 1 / 50 + 1 = 4 / 51 = 0.078431373
    +     * 
    + * + *
  • + *
  • + * + *
    +     * ...
    +     * 
    + * + *
  • + *
  • + * + *
    +     * Competitor positions thread -> weight = 50, progress = 50 --> total_progress = 50 + 1 / 50 + 1 = 51 / 51 = 1.0
    +     * 
    + * + *
  • *
* * This example shows that is possible to receive more that 3 values of the progress lower than one already - * received. It happens because the weight of the threads changes."

+ * received. It happens because the weight of the threads changes." + *

* - * We assume that there won't be more than six threads in TTCM receiving data for the same race. + * We assume that there won't be more than eight threads in TTCM receiving data for the same race, based on Jorge's + * statement from 2014-02-06: "One thread per subscription where the subscriptions are: + *

    + *
  • Competitor positions
  • + *
  • Mark positions
  • + *
  • Mark passings
  • + *
  • Route
  • + *
  • Start/Stop times for race
  • + *
  • Start/Stop times for event
  • + *
  • Messages for race
  • + *
  • Messages for event
  • + *
+ * Potentially, you can create 8 threads per TTCM (connecting only with one single race)." */ - static final Integer MAX_STORED_PACKET_HOP_ALLOWANCE = 6; + static final Integer MAX_STORED_PACKET_HOP_ALLOWANCE = 8; private final Event tractracEvent; private final com.sap.sailing.domain.base.Regatta regatta; @@ -200,19 +249,19 @@ public class TracTracRaceTrackerImpl extends AbstractRaceTrackerImpl implements */ protected TracTracRaceTrackerImpl(DomainFactory domainFactory, URL paramURL, URI liveURI, URI storedURI, URI courseDesignUpdateURI, TimePoint startOfTracking, TimePoint endOfTracking, long delayToLiveInMillis, - boolean simulateWithStartTimeNow, RaceLogStore raceLogStore, WindStore windStore, String tracTracUsername, String tracTracPassword, TrackedRegattaRegistry trackedRegattaRegistry) + boolean simulateWithStartTimeNow, RaceLogStore raceLogStore, WindStore windStore, String tracTracUsername, String tracTracPassword, String raceStatus, TrackedRegattaRegistry trackedRegattaRegistry) throws URISyntaxException, MalformedURLException, FileNotFoundException { this(KeyValue.setup(paramURL), domainFactory, paramURL, liveURI, storedURI, courseDesignUpdateURI, startOfTracking, endOfTracking, - delayToLiveInMillis, simulateWithStartTimeNow, raceLogStore, windStore, tracTracUsername, tracTracPassword, trackedRegattaRegistry); + delayToLiveInMillis, simulateWithStartTimeNow, raceLogStore, windStore, tracTracUsername, tracTracPassword, raceStatus, trackedRegattaRegistry); } private TracTracRaceTrackerImpl(Event tractracEvent, DomainFactory domainFactory, URL paramURL, URI liveURI, URI storedURI, URI courseDesignUpdateURI, TimePoint startOfTracking, TimePoint endOfTracking, long delayToLiveInMillis, boolean simulateWithStartTimeNow, - RaceLogStore raceLogStore, WindStore windStore, String tracTracUsername, String tracTracPassword, TrackedRegattaRegistry trackedRegattaRegistry) + RaceLogStore raceLogStore, WindStore windStore, String tracTracUsername, String tracTracPassword, String raceStatus, TrackedRegattaRegistry trackedRegattaRegistry) throws URISyntaxException, MalformedURLException, FileNotFoundException { this(tractracEvent, null, domainFactory, paramURL, liveURI, storedURI, courseDesignUpdateURI, startOfTracking, endOfTracking, delayToLiveInMillis, simulateWithStartTimeNow, raceLogStore, windStore, - tracTracUsername, tracTracPassword, trackedRegattaRegistry); + tracTracUsername, tracTracPassword, raceStatus, trackedRegattaRegistry); } /** @@ -223,11 +272,11 @@ public class TracTracRaceTrackerImpl extends AbstractRaceTrackerImpl implements */ protected TracTracRaceTrackerImpl(Regatta regatta, DomainFactory domainFactory, URL paramURL, URI liveURI, URI storedURI, URI courseDesignUpdateURI, TimePoint startOfTracking, TimePoint endOfTracking, long delayToLiveInMillis, boolean simulateWithStartTimeNow, - RaceLogStore raceLogStore, WindStore windStore, String tracTracUsername, String tracTracPassword, TrackedRegattaRegistry trackedRegattaRegistry) + RaceLogStore raceLogStore, WindStore windStore, String tracTracUsername, String tracTracPassword, String raceStatus, TrackedRegattaRegistry trackedRegattaRegistry) throws URISyntaxException, MalformedURLException, FileNotFoundException { this(KeyValue.setup(paramURL), regatta, domainFactory, paramURL, liveURI, storedURI, courseDesignUpdateURI, startOfTracking, endOfTracking, delayToLiveInMillis, simulateWithStartTimeNow, raceLogStore, windStore, - tracTracUsername, tracTracPassword, trackedRegattaRegistry); + tracTracUsername, tracTracPassword, raceStatus, trackedRegattaRegistry); } /** @@ -244,7 +293,7 @@ public class TracTracRaceTrackerImpl extends AbstractRaceTrackerImpl implements private TracTracRaceTrackerImpl(Event tractracEvent, final Regatta regatta, DomainFactory domainFactory, URL paramURL, URI liveURI, URI storedURI, URI tracTracUpdateURI, TimePoint startOfTracking, TimePoint endOfTracking, long delayToLiveInMillis, boolean simulateWithStartTimeNow, RaceLogStore raceLogStore, - WindStore windStore, String tracTracUsername, String tracTracPassword, TrackedRegattaRegistry trackedRegattaRegistry) + WindStore windStore, String tracTracUsername, String tracTracPassword, String raceStatus, TrackedRegattaRegistry trackedRegattaRegistry) throws URISyntaxException, MalformedURLException, FileNotFoundException { super(); this.tractracEvent = tractracEvent; @@ -267,7 +316,10 @@ public class TracTracRaceTrackerImpl extends AbstractRaceTrackerImpl implements } // check if there is a directory configured where stored data files can be cached - storedURI = checkForCachedStoredData(storedURI); + // only cache files for races in REPLAY state + if (raceStatus != null && raceStatus.equals(TracTracConnectionConstants.REPLAY_STATUS)) { + storedURI = checkForCachedStoredData(storedURI); + } logger.info("Starting race tracker: " + tractracEvent.getName() + " " + paramURL + " " + liveURI + " " + storedURI + " startOfTracking:" + (startOfTracking != null ? startOfTracking.asMillis() : "n/a") + " endOfTracking:" + (endOfTracking != null ? endOfTracking.asMillis() : "n/a")); @@ -311,18 +363,20 @@ public class TracTracRaceTrackerImpl extends AbstractRaceTrackerImpl implements } private URI checkForCachedStoredData(URI storedURI){ - if (System.getProperty("tractrac.mtb.cache.dir") != null) { - final String directory = System.getProperty("tractrac.mtb.cache.dir"); + final String CACHE_DIR_PROPERTY = "tractrac.mtb.cache.dir"; + if (System.getProperty(CACHE_DIR_PROPERTY) != null) { + final String directory = System.getProperty(CACHE_DIR_PROPERTY); if (new File(directory).exists()) { final String[] pathFragments = storedURI.getPath().split("\\/"); final String mtbFileName = pathFragments[pathFragments.length-1]; final String directoryAndFileName = directory+"/"+mtbFileName; - if (!new File(directoryAndFileName).exists()) { + final File f = new File(directoryAndFileName); + if (!f.exists()) { FileOutputStream mtbOutStream = null; try { logger.info("Starting to download " + storedURI + " to cache dir " + directoryAndFileName); InputStream in = storedURI.toURL().openStream(); - mtbOutStream = new FileOutputStream(new File(directoryAndFileName)); + mtbOutStream = new FileOutputStream(f); byte data[] = new byte[1024]; int count; while ((count = in.read(data, 0, 1024)) != -1) diff --git a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/base/LeaderboardMasterData.java b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/base/LeaderboardMasterData.java deleted file mode 100644 index 28f7d4ee0d0..00000000000 --- a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/base/LeaderboardMasterData.java +++ /dev/null @@ -1,91 +0,0 @@ -package com.sap.sailing.domain.base; - -import java.io.Serializable; -import java.util.List; -import java.util.Map; - -import com.sap.sailing.domain.leaderboard.Leaderboard; -import com.sap.sailing.domain.leaderboard.ThresholdBasedResultDiscardingRule; -import com.sap.sailing.domain.leaderboard.impl.ThresholdBasedResultDiscardingRuleImpl; -import com.sap.sailing.domain.masterdataimport.ScoreCorrectionMasterData; -import com.sap.sailing.domain.racelog.RaceLogEvent; - -public abstract class LeaderboardMasterData { - - private String name; - - private String displayName; - - private int[] resultDiscardingRule; - - private Map competitorsById; - - private ScoreCorrectionMasterData scoreCorrection; - - private Map carriedPoints; - - private List suppressedCompetitors; - - private Map displayNamesByCompetitorId; - - private Map>> raceLogEvents; - - public LeaderboardMasterData(String name, String displayName, int[] resultDiscardingRule, - Map competitorsById, ScoreCorrectionMasterData scoreCorrection, - Map carriedPoints, List suppressedCompetitors, - Map displayNamesByCompetitorId, - Map>> raceLogEvents) { - this.name = name; - this.displayName = displayName; - this.resultDiscardingRule = resultDiscardingRule; - this.competitorsById = competitorsById; - this.scoreCorrection = scoreCorrection; - this.carriedPoints = carriedPoints; - this.suppressedCompetitors = suppressedCompetitors; - this.displayNamesByCompetitorId = displayNamesByCompetitorId; - this.raceLogEvents = raceLogEvents; - } - - public String getName() { - return name; - } - - public String getDisplayName() { - return displayName; - } - - public ThresholdBasedResultDiscardingRule getResultDiscardingRule() { - if (resultDiscardingRule == null) { - return null; - } - ThresholdBasedResultDiscardingRule rule = new ThresholdBasedResultDiscardingRuleImpl(resultDiscardingRule); - return rule; - } - - public Map getCompetitorsById() { - return competitorsById; - } - - public ScoreCorrectionMasterData getScoreCorrection() { - return scoreCorrection; - } - - public Map getCarriedPoints() { - return carriedPoints; - } - - public List getSuppressedCompetitors() { - return suppressedCompetitors; - } - - public Map getDisplayNamesByCompetitorId() { - return displayNamesByCompetitorId; - } - - public Map>> getRaceLogEvents() { - return raceLogEvents; - } - - public abstract Leaderboard getLeaderboard(); - -} diff --git a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/base/RaceColumn.java b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/base/RaceColumn.java index 1b3f741e70a..fd28f8e4e14 100644 --- a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/base/RaceColumn.java +++ b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/base/RaceColumn.java @@ -199,5 +199,32 @@ public interface RaceColumn extends Named { * * @param fleet */ - void removeRaceIdentifier(Fleet fleet); + void removeRaceIdentifier(Fleet fleet); + + /** + * While set to true, any serialization in the current thread will not include the tracked races. Make sure to set + * back to false, after serialization. (in finally block) + * + * @param flagValue + * set to false for default behavior, set to true to exclude tracked races + */ + public void setMasterDataExportOngoingThreadFlag(boolean flagValue); + + /** + * Usually, when a regatta has split fleets that are {@link Fleet#getOrdering() ordered}, a competitor participating in a + * better fleet is always scored better than all competitors participating in worse fleets. However, under some circumstances + * it may be desirable to model a regatta series such that the fleet pertinence does not lead to a persistent scoring ordering + * throughout the regatta. For example, the Extreme Sailing Series Knock-Out Races use ordered fleets, but the fleet that a + * competitor qualified for does not decide about total regatta ranking. It may, however, decide for in-column ranking. See also + * {@link #isSplit}. + */ + boolean isTotalOrderDefinedByFleet(); + + /** + * When a column has more than one fleet, there are two different options for scoring it. Either the scoring scheme is applied + * to the sequence of competitors one gets when first ordering the competitors by fleets and then within each fleet by their + * rank in the fleet's race; or the scoring scheme is applied to each fleet separately, leading to the best score being awarded + * in the column as many times as there are fleets in the column. For the latter case, this method returns true. + */ + boolean hasSplitFleetContiguousScoring(); } diff --git a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/base/RaceColumnListener.java b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/base/RaceColumnListener.java index 6dd812638a8..e25bd4444d2 100755 --- a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/base/RaceColumnListener.java +++ b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/base/RaceColumnListener.java @@ -18,6 +18,8 @@ public interface RaceColumnListener extends Serializable { void isFirstColumnIsNonDiscardableCarryForwardChanged(RaceColumn raceColumn, boolean firstColumnIsNonDiscardableCarryForward); + void hasSplitFleetContiguousScoringChanged(RaceColumn raceColumn, boolean hasSplitFleetContiguousScoring); + boolean canAddRaceColumnToContainer(RaceColumn raceColumn); void raceColumnAddedToContainer(RaceColumn raceColumn); diff --git a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/base/Series.java b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/base/Series.java index 5b60f81b56c..11ff6e0c124 100755 --- a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/base/Series.java +++ b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/base/Series.java @@ -93,4 +93,14 @@ public interface Series extends SeriesBase { boolean isFirstColumnIsNonDiscardableCarryForward(); void setFirstColumnIsNonDiscardableCarryForward(boolean firstColumnIsNonDiscardableCarryForward); + + /** + * When a series has more than one fleet, there are two different options for scoring it. Either the scoring scheme is applied + * to the sequence of competitors one gets when first ordering the competitors by fleets and then within each fleet by their + * rank in the fleet's race; or the scoring scheme is applied to each fleet separately, leading to the best score being awarded + * in the column as many times as there are fleets in the column. For the former case, this method returns true. + */ + boolean hasSplitFleetContiguousScoring(); + + void setSplitFleetContiguousScoring(boolean hasSplitFleetScore); } diff --git a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/base/impl/AbstractRaceColumn.java b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/base/impl/AbstractRaceColumn.java index 58d2e126b70..c5c2a9502a6 100755 --- a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/base/impl/AbstractRaceColumn.java +++ b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/base/impl/AbstractRaceColumn.java @@ -2,6 +2,7 @@ package com.sap.sailing.domain.base.impl; import java.io.IOException; import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; import java.util.HashMap; import java.util.HashSet; import java.util.Map; @@ -24,10 +25,10 @@ import com.sap.sailing.domain.tracking.TrackedRace; public abstract class AbstractRaceColumn extends SimpleAbstractRaceColumn implements RaceColumn { private static final long serialVersionUID = -7801617988982540470L; - private final Map trackedRaces; - private final Map raceIdentifiers; + private Map trackedRaces; + private Map raceIdentifiers; - private final Map raceLogs; + private Map raceLogs; /** * holds the race log identifier template needed to create the appropriate RaceLogIdentifer that is constructed from the @@ -37,6 +38,16 @@ public abstract class AbstractRaceColumn extends SimpleAbstractRaceColumn implem private transient RaceLogInformation raceLogInformation; private RaceLogIdentifierTemplate raceLogIdentifierTemplate; + /** + * we don't want the TrackedRaces to be serialized during a master data export. Thus, we need this thread flag which + * is true only during master data export + */ + private transient ThreadLocal ongoingMasterDataExport = new ThreadLocal() { + protected Boolean initialValue() { + return false; + }; + }; + public AbstractRaceColumn() { this.trackedRaces = new HashMap(); this.raceIdentifiers = new HashMap(); @@ -189,12 +200,40 @@ public abstract class AbstractRaceColumn extends SimpleAbstractRaceColumn implem /** * When deserializing, replication listeners are registered on all race logs. */ + @SuppressWarnings("unchecked") private void readObject(ObjectInputStream ois) throws ClassNotFoundException, IOException { - ois.defaultReadObject(); + + // Check if master data export is ongoing + boolean masterDataImportOngoing = ois.readBoolean(); + if (masterDataImportOngoing) { + this.trackedRaces = new HashMap(); + this.raceIdentifiers = (Map) ois.readObject(); + this.raceLogs = (Map) ois.readObject(); + this.raceLogIdentifierTemplate = (RaceLogIdentifierTemplate) ois.readObject(); + } else { + ois.defaultReadObject(); + } for (Entry entry : raceLogs.entrySet()) { Fleet fleet = entry.getKey(); RaceLog raceLog = entry.getValue(); raceLog.addListener(new RaceColumnRaceLogReplicator(this, raceLogIdentifierTemplate.compileRaceLogIdentifier(fleet))); } } + + @Override + public void setMasterDataExportOngoingThreadFlag(boolean flagValue) { + ongoingMasterDataExport.set(flagValue); + } + + private void writeObject(ObjectOutputStream stream) throws IOException { + if (ongoingMasterDataExport.get()) { + stream.writeBoolean(true); + stream.writeObject(raceIdentifiers); + stream.writeObject(raceLogs); + stream.writeObject(raceLogIdentifierTemplate); + } else { + stream.writeBoolean(false); + stream.defaultWriteObject(); + } + } } diff --git a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/base/impl/RaceColumnInSeriesImpl.java b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/base/impl/RaceColumnInSeriesImpl.java index cb213955f29..e6d97e325ff 100755 --- a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/base/impl/RaceColumnInSeriesImpl.java +++ b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/base/impl/RaceColumnInSeriesImpl.java @@ -111,4 +111,14 @@ public class RaceColumnInSeriesImpl extends AbstractRaceColumn implements RaceCo public boolean isCarryForward() { return isFirstColumnInSeries() && getSeries().isFirstColumnIsNonDiscardableCarryForward(); } + + /** + * Delegates to {@link Series#hasSplitFleetContiguousScoring()}. + */ + @Override + public boolean hasSplitFleetContiguousScoring() { + return getSeries().hasSplitFleetContiguousScoring(); + } + + } diff --git a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/base/impl/RegattaImpl.java b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/base/impl/RegattaImpl.java index c3df16634f1..145fd1b22ba 100755 --- a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/base/impl/RegattaImpl.java +++ b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/base/impl/RegattaImpl.java @@ -287,6 +287,11 @@ public class RegattaImpl extends NamedImpl implements Regatta, RaceColumnListene raceColumnListeners.notifyListenersAboutIsFirstColumnIsNonDiscardableCarryForwardChanged(raceColumn, firstColumnIsNonDiscardableCarryForward); } + @Override + public void hasSplitFleetContiguousScoringChanged(RaceColumn raceColumn, boolean hasSplitFleetContiguousScoring) { + raceColumnListeners.notifyListenersAboutHasSplitFleetContiguousScoringChanged(raceColumn, hasSplitFleetContiguousScoring); + } + @Override public boolean canAddRaceColumnToContainer(RaceColumn raceColumn) { return raceColumnListeners.canAddRaceColumnToContainer(raceColumn); diff --git a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/base/impl/SeriesImpl.java b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/base/impl/SeriesImpl.java index 19a80d0aa1c..aa96989960c 100755 --- a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/base/impl/SeriesImpl.java +++ b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/base/impl/SeriesImpl.java @@ -47,6 +47,15 @@ public class SeriesImpl extends NamedImpl implements Series, RaceColumnListener */ private boolean firstColumnIsNonDiscardableCarryForward; + /** + * When a column has more than one fleet, there are two different options for scoring it. Either the scoring scheme is applied + * to the sequence of competitors one gets when first ordering the competitors by fleets and then within each fleet by their + * rank in the fleet's race; or the scoring scheme is applied to each fleet separately, leading to the best score being awarded + * in the column as many times as there are fleets in the column. For the latter case, this field is false which is + * also the default. + */ + private boolean hasSplitFleetContiguousScoring; + /** * @param fleets * must be non-empty @@ -226,7 +235,13 @@ public class SeriesImpl extends NamedImpl implements Series, RaceColumnListener @Override public void setIsMedal(boolean isMedal) { + boolean oldIsMedal = this.isMedal; this.isMedal = isMedal; + if (oldIsMedal != isMedal) { + for (RaceColumn raceColumn : getRaceColumns()) { + raceColumnListeners.notifyListenersAboutIsMedalRaceChanged(raceColumn, isMedal); + } + } } @Override @@ -249,6 +264,11 @@ public class SeriesImpl extends NamedImpl implements Series, RaceColumnListener raceColumnListeners.notifyListenersAboutIsStartsWithZeroScoreChanged(raceColumn, newIsStartsWithZeroScore); } + @Override + public void hasSplitFleetContiguousScoringChanged(RaceColumn raceColumn, boolean hasSplitFleetContiguousScoring) { + raceColumnListeners.notifyListenersAboutHasSplitFleetContiguousScoringChanged(raceColumn, hasSplitFleetContiguousScoring); + } + @Override public void isFirstColumnIsNonDiscardableCarryForwardChanged(RaceColumn raceColumn, boolean firstColumnIsNonDiscardableCarryForward) { raceColumnListeners.notifyListenersAboutIsFirstColumnIsNonDiscardableCarryForwardChanged(raceColumn, firstColumnIsNonDiscardableCarryForward); @@ -352,6 +372,16 @@ public class SeriesImpl extends NamedImpl implements Series, RaceColumnListener } } + @Override + public void setSplitFleetContiguousScoring(boolean hasSplitFleetContiguousScoring) { + if (hasSplitFleetContiguousScoring != this.hasSplitFleetContiguousScoring) { + this.hasSplitFleetContiguousScoring = hasSplitFleetContiguousScoring; + for (RaceColumn raceColumn : getRaceColumns()) { + raceColumnListeners.notifyListenersAboutHasSplitFleetContiguousScoringChanged(raceColumn, hasSplitFleetContiguousScoring); + } + } + } + @Override public boolean isFirstColumnIsNonDiscardableCarryForward() { return firstColumnIsNonDiscardableCarryForward; @@ -370,5 +400,8 @@ public class SeriesImpl extends NamedImpl implements Series, RaceColumnListener this.firstColumnIsNonDiscardableCarryForward = firstColumnIsNonDiscardableCarryForward; } - + @Override + public boolean hasSplitFleetContiguousScoring() { + return hasSplitFleetContiguousScoring; + } } diff --git a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/base/impl/SimpleAbstractRaceColumn.java b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/base/impl/SimpleAbstractRaceColumn.java index 17df05b55c6..6acd2e73e1b 100755 --- a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/base/impl/SimpleAbstractRaceColumn.java +++ b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/base/impl/SimpleAbstractRaceColumn.java @@ -95,4 +95,19 @@ public abstract class SimpleAbstractRaceColumn implements RaceColumn { return false; } + /** + * Implements this by delegating to and negating the result of {@link #hasSplitFleetContiguousScoring()}. This is a + * reasonable default implementation because if the score is not split up by fleet but scored contiguously + * ascending/descending, this usually means that the fleets re-convene after this series instead of remaining split. + */ + @Override + public boolean isTotalOrderDefinedByFleet() { + return !hasSplitFleetContiguousScoring(); + } + + @Override + public boolean hasSplitFleetContiguousScoring() { + return false; + } + } diff --git a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/leaderboard/Leaderboard.java b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/leaderboard/Leaderboard.java index 8e6f5f0acfd..fa5f8732108 100644 --- a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/leaderboard/Leaderboard.java +++ b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/leaderboard/Leaderboard.java @@ -457,4 +457,6 @@ public interface Leaderboard extends Named { Collection namesOfRaceColumnsForWhichToLoadLegDetails, TrackedRegattaRegistry trackedRegattaRegistry, DomainFactory baseDomainFactory) throws NoWindException, InterruptedException, ExecutionException; + + NumberOfCompetitorsInLeaderboardFetcher getNumberOfCompetitorsInLeaderboardFetcher(); } diff --git a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/leaderboard/LeaderboardCacheManager.java b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/leaderboard/LeaderboardCacheManager.java index c3bbd7075f6..a27b8aa7a91 100755 --- a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/leaderboard/LeaderboardCacheManager.java +++ b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/leaderboard/LeaderboardCacheManager.java @@ -249,6 +249,11 @@ public class LeaderboardCacheManager { removeFromCache(leaderboard); } + @Override + public void hasSplitFleetContiguousScoringChanged(RaceColumn raceColumn, boolean hasSplitFleetContiguousScoring) { + removeFromCache(leaderboard); + } + @Override public void isFirstColumnIsNonDiscardableCarryForwardChanged(RaceColumn raceColumn, boolean firstColumnIsNonDiscardableCarryForward) { diff --git a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/leaderboard/ScoringScheme.java b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/leaderboard/ScoringScheme.java index 7f0d5322efd..36057c3e58a 100755 --- a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/leaderboard/ScoringScheme.java +++ b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/leaderboard/ScoringScheme.java @@ -47,9 +47,11 @@ public interface ScoringScheme extends Serializable { * * If the competitor has no {@link RaceColumn#getTrackedRace(Competitor) tracked race} in the column in which * the competitor participated, null is returned, meaning the competitor has no score assigned for that - * race. + * race. */ - Double getScoreForRank(RaceColumn raceColumn, Competitor competitor, int rank, Callable numberOfCompetitorsInRaceFetcher); + Double getScoreForRank(RaceColumn raceColumn, Competitor competitor, int rank, + Callable numberOfCompetitorsInRaceFetcher, + NumberOfCompetitorsInLeaderboardFetcher numberOfCompetitorsInLeaderboardFetcher); /** * If a competitor is disqualified, a penalty score is attributed by this scoring scheme. Some schemes require to diff --git a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/leaderboard/impl/AbstractScoringSchemeImpl.java b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/leaderboard/impl/AbstractScoringSchemeImpl.java index 1a2fbff83be..9707be938fc 100755 --- a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/leaderboard/impl/AbstractScoringSchemeImpl.java +++ b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/leaderboard/impl/AbstractScoringSchemeImpl.java @@ -170,4 +170,16 @@ public abstract class AbstractScoringSchemeImpl implements ScoringScheme { } return result; } + + protected int getNumberOfCompetitorsInBetterFleets(RaceColumn raceColumn, int competitorFleetOrdering) { + int numberOfCompetitorsInBetterFleets = 0; + for (Fleet fleet : raceColumn.getFleets()) { + TrackedRace trackedRaceOfBetterFleet; + if (fleet.getOrdering() != 0 && fleet.getOrdering() < competitorFleetOrdering && + (trackedRaceOfBetterFleet=raceColumn.getTrackedRace(fleet)) != null) { + numberOfCompetitorsInBetterFleets += Util.size(trackedRaceOfBetterFleet.getRace().getCompetitors()); + } + } + return numberOfCompetitorsInBetterFleets; + } } diff --git a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/leaderboard/impl/AbstractSimpleLeaderboardImpl.java b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/leaderboard/impl/AbstractSimpleLeaderboardImpl.java index 2c09dfda0a7..b606d463017 100755 --- a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/leaderboard/impl/AbstractSimpleLeaderboardImpl.java +++ b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/leaderboard/impl/AbstractSimpleLeaderboardImpl.java @@ -751,6 +751,11 @@ public abstract class AbstractSimpleLeaderboardImpl implements Leaderboard, Race getRaceColumnListeners().notifyListenersAboutIsFirstColumnIsNonDiscardableCarryForwardChanged(raceColumn, firstColumnIsNonDiscardableCarryForward); } + @Override + public void hasSplitFleetContiguousScoringChanged(RaceColumn raceColumn, boolean hasSplitFleetContiguousScoring) { + getRaceColumnListeners().notifyListenersAboutHasSplitFleetContiguousScoringChanged(raceColumn, hasSplitFleetContiguousScoring); + } + @Override public void raceColumnMoved(RaceColumn raceColumn, int newIndex) { getRaceColumnListeners().notifyListenersAboutRaceColumnMoved(raceColumn, newIndex); @@ -1254,9 +1259,10 @@ public abstract class AbstractSimpleLeaderboardImpl implements Leaderboard, Race entryDTO.reasonForMaxPoints = entry.getMaxPointsReason(); entryDTO.discarded = entry.isDiscarded(); if (trackedRace != null) { - entryDTO.timePointOfLastPositionFixAtOrBeforeQueryTimePoint = getTimePointOfLastFixAtOrBefore(competitor, trackedRace, timePoint); - if(entryDTO.timePointOfLastPositionFixAtOrBeforeQueryTimePoint != null) { - long timeDifferenceInMs = timePoint.asMillis() - entryDTO.timePointOfLastPositionFixAtOrBeforeQueryTimePoint.getTime(); + Date timePointOfLastPositionFixAtOrBeforeQueryTimePoint = getTimePointOfLastFixAtOrBefore(competitor, trackedRace, timePoint); + entryDTO.averageSamplingInterval = trackedRace.getTrack(competitor).getAverageIntervalBetweenFixes(); + if (timePointOfLastPositionFixAtOrBeforeQueryTimePoint != null) { + long timeDifferenceInMs = timePoint.asMillis() - timePointOfLastPositionFixAtOrBeforeQueryTimePoint.getTime(); entryDTO.timeSinceLastPositionFixInSeconds = timeDifferenceInMs == 0 ? 0.0 : timeDifferenceInMs / 1000.0; } else { entryDTO.timeSinceLastPositionFixInSeconds = null; @@ -1679,4 +1685,8 @@ public abstract class AbstractSimpleLeaderboardImpl implements Leaderboard, Race return getName() + " " + (getDefaultCourseArea() != null ? getDefaultCourseArea().getName() : "") + " " + (getScoringScheme() != null ? getScoringScheme().getType().name() : ""); } + @Override + public NumberOfCompetitorsInLeaderboardFetcher getNumberOfCompetitorsInLeaderboardFetcher() { + return new NumberOfCompetitorsFetcherImpl(); + } } diff --git a/java/com.sap.sailing.domain.persistence/src/com/sap/sailing/domain/persistence/impl/DelayedLeaderboardCorrectionsImpl.java b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/leaderboard/impl/DelayedLeaderboardCorrectionsImpl.java similarity index 97% rename from java/com.sap.sailing.domain.persistence/src/com/sap/sailing/domain/persistence/impl/DelayedLeaderboardCorrectionsImpl.java rename to java/com.sap.sailing.domain/src/com/sap/sailing/domain/leaderboard/impl/DelayedLeaderboardCorrectionsImpl.java index abd9abb2991..b505bf62b6c 100755 --- a/java/com.sap.sailing.domain.persistence/src/com/sap/sailing/domain/persistence/impl/DelayedLeaderboardCorrectionsImpl.java +++ b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/leaderboard/impl/DelayedLeaderboardCorrectionsImpl.java @@ -1,4 +1,4 @@ -package com.sap.sailing.domain.persistence.impl; +package com.sap.sailing.domain.leaderboard.impl; import java.io.IOException; import java.io.ObjectInputStream; @@ -410,6 +410,10 @@ public class DelayedLeaderboardCorrectionsImpl implements DelayedLeaderboardCorr public void isStartsWithZeroScoreChanged(RaceColumn raceColumn, boolean newIsStartsWithZeroScore) { } + @Override + public void hasSplitFleetContiguousScoringChanged(RaceColumn raceColumn, boolean hasSplitFleetContiguousScoring) { + } + @Override public void isFirstColumnIsNonDiscardableCarryForwardChanged(RaceColumn raceColumn, boolean firstColumnIsNonDiscardableCarryForward) { } diff --git a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/leaderboard/impl/HighPoint.java b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/leaderboard/impl/HighPoint.java index 7ccc793da02..9da8d934900 100755 --- a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/leaderboard/impl/HighPoint.java +++ b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/leaderboard/impl/HighPoint.java @@ -13,7 +13,8 @@ import com.sap.sailing.domain.leaderboard.NumberOfCompetitorsInLeaderboardFetche /** * The scoring system as used by the Extreme Sailing Series. Disqualified competitors get 0 points; the winner gets as - * many points as there are competitors in the race. Higher scores are better. + * many points as there are competitors in the race. Higher scores are better. No negative scores are returned. Worst + * score a competitor can get is 1.0. * * @author Axel Uhl (D043530) * @@ -26,7 +27,9 @@ public class HighPoint extends AbstractScoringSchemeImpl { } @Override - public Double getScoreForRank(RaceColumn raceColumn, Competitor competitor, int rank, Callable numberOfCompetitorsInRaceFetcher) { + public Double getScoreForRank(RaceColumn raceColumn, Competitor competitor, int rank, + Callable numberOfCompetitorsInRaceFetcher, + NumberOfCompetitorsInLeaderboardFetcher numberOfCompetitorsInLeaderboardFetcher) { Double result; if (rank == 0) { result = null; @@ -34,10 +37,23 @@ public class HighPoint extends AbstractScoringSchemeImpl { Integer numberOfCompetitorsInRace; try { numberOfCompetitorsInRace = numberOfCompetitorsInRaceFetcher.call(); + int competitorFleetOrdering; if (numberOfCompetitorsInRace == null) { result = null; } else { - result = (double) (numberOfCompetitorsInRace - rank + 1); + final int effectiveRank; + final int numberOfCompetitorsDeterminingMaxPoints; + if (raceColumn.hasSplitFleetContiguousScoring() + && (competitorFleetOrdering = raceColumn.getFleetOfCompetitor(competitor).getOrdering()) != 0) { + int numberOfCompetitorsInBetterFleets = getNumberOfCompetitorsInBetterFleets(raceColumn, + competitorFleetOrdering); + effectiveRank = rank + numberOfCompetitorsInBetterFleets; + numberOfCompetitorsDeterminingMaxPoints = numberOfCompetitorsInLeaderboardFetcher.getNumberOfCompetitorsInLeaderboard(); + } else { + effectiveRank = rank; + numberOfCompetitorsDeterminingMaxPoints = numberOfCompetitorsInRace; + } + result = (double) (numberOfCompetitorsDeterminingMaxPoints - effectiveRank + 1); } } catch (Exception e) { throw new RuntimeException(e); diff --git a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/leaderboard/impl/HighPointExtremeSailingSeriesOverall.java b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/leaderboard/impl/HighPointExtremeSailingSeriesOverall.java index 68f0a7e78a2..7b223d106df 100755 --- a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/leaderboard/impl/HighPointExtremeSailingSeriesOverall.java +++ b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/leaderboard/impl/HighPointExtremeSailingSeriesOverall.java @@ -7,6 +7,7 @@ import com.sap.sailing.domain.base.Competitor; import com.sap.sailing.domain.base.RaceColumn; import com.sap.sailing.domain.common.ScoringSchemeType; import com.sap.sailing.domain.common.impl.Util.Pair; +import com.sap.sailing.domain.leaderboard.NumberOfCompetitorsInLeaderboardFetcher; /** * A variant of the {@link HighPoint} scoring scheme which breaks ties differently and which assigns a score of 10 to @@ -30,12 +31,12 @@ public class HighPointExtremeSailingSeriesOverall extends HighPoint { @Override public Double getScoreForRank(RaceColumn raceColumn, Competitor competitor, int rank, - Callable numberOfCompetitorsInRaceFetcher) { + Callable numberOfCompetitorsInRaceFetcher, NumberOfCompetitorsInLeaderboardFetcher numberOfCompetitorsInLeaderboardFetcher) { Double result; if (rank == 0) { result = null; } else { - result = Math.max(0.0, (double) (MAX_POINTS - rank + 1)); + result = Math.max(1.0, (double) (MAX_POINTS - rank + 1)); } return result; } diff --git a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/leaderboard/impl/HighPointFirstGetsFixedScore.java b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/leaderboard/impl/HighPointFirstGetsFixedScore.java index 433809235ee..b3a60a85a37 100755 --- a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/leaderboard/impl/HighPointFirstGetsFixedScore.java +++ b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/leaderboard/impl/HighPointFirstGetsFixedScore.java @@ -4,11 +4,12 @@ import java.util.concurrent.Callable; import com.sap.sailing.domain.base.Competitor; import com.sap.sailing.domain.base.RaceColumn; +import com.sap.sailing.domain.leaderboard.NumberOfCompetitorsInLeaderboardFetcher; /** * A variant of the {@link HighPoint} scoring system where the winner gets a fixed number of points, and - * all subsequent ranks get one point less. No negative scores are returned. 0.0 is the worst score a + * all subsequent ranks get one point less. No negative scores are returned. 1.0 is the worst score a * competitor can score. * * @author Axel Uhl (D043530) @@ -24,12 +25,22 @@ public abstract class HighPointFirstGetsFixedScore extends HighPoint { } @Override - public Double getScoreForRank(RaceColumn raceColumn, Competitor competitor, int rank, Callable numberOfCompetitorsInRaceFetcher) { - Double result; + public Double getScoreForRank(RaceColumn raceColumn, Competitor competitor, int rank, Callable numberOfCompetitorsInRaceFetcher, NumberOfCompetitorsInLeaderboardFetcher numberOfCompetitorsInLeaderboardFetcher) { + final int effectiveRank; + final Double result; + int competitorFleetOrdering; if (rank == 0) { + effectiveRank = 0; + } else if (raceColumn.hasSplitFleetContiguousScoring() && (competitorFleetOrdering=raceColumn.getFleetOfCompetitor(competitor).getOrdering()) != 0) { + int numberOfCompetitorsInBetterFleets = getNumberOfCompetitorsInBetterFleets(raceColumn, competitorFleetOrdering); + effectiveRank = rank + numberOfCompetitorsInBetterFleets; + } else { + effectiveRank = rank; + } + if (effectiveRank == 0) { result = null; } else { - result = Math.max(0.0, (double) (scoreForRaceWinner - rank + 1)); + result = Math.max(1.0, (double) (scoreForRaceWinner - effectiveRank + 1)); } return result; } diff --git a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/leaderboard/impl/LeaderboardTotalRankComparator.java b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/leaderboard/impl/LeaderboardTotalRankComparator.java index 1392a1ed4c7..a4018c19eaf 100755 --- a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/leaderboard/impl/LeaderboardTotalRankComparator.java +++ b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/leaderboard/impl/LeaderboardTotalRankComparator.java @@ -140,7 +140,7 @@ public class LeaderboardTotalRankComparator implements Comparator { // (tracked or manual) is sufficient preemptiveColumnResult = compareByMedalRaceParticipation(o1Score, o2Score); } - if (preemptiveColumnResult == 0) { + if (preemptiveColumnResult == 0 && raceColumn.isTotalOrderDefinedByFleet()) { preemptiveColumnResult = compareByFleet(raceColumn, o1, o2); } if (preemptiveColumnResult != 0) { diff --git a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/leaderboard/impl/LowPoint.java b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/leaderboard/impl/LowPoint.java index 50bd8660b8c..0a8ee7899c2 100755 --- a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/leaderboard/impl/LowPoint.java +++ b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/leaderboard/impl/LowPoint.java @@ -27,15 +27,27 @@ public class LowPoint extends AbstractScoringSchemeImpl { } @Override - public Double getScoreForRank(RaceColumn raceColumn, Competitor competitor, int rank, Callable numberOfCompetitorsInRaceFetcher) { - return rank == 0 ? null : (double) rank; + public Double getScoreForRank(RaceColumn raceColumn, Competitor competitor, int rank, Callable numberOfCompetitorsInRaceFetcher, NumberOfCompetitorsInLeaderboardFetcher numberOfCompetitorsInLeaderboardFetcher) { + final int effectiveRank; + final Double result; + int competitorFleetOrdering; + if (rank == 0) { + effectiveRank = 0; + } else if (raceColumn.hasSplitFleetContiguousScoring() && (competitorFleetOrdering=raceColumn.getFleetOfCompetitor(competitor).getOrdering()) != 0) { + int numberOfCompetitorsInBetterFleets = getNumberOfCompetitorsInBetterFleets(raceColumn, competitorFleetOrdering); + effectiveRank = rank + numberOfCompetitorsInBetterFleets; + } else { + effectiveRank = rank; + } + result = effectiveRank == 0 ? null : (double) effectiveRank; + return result; } @Override public Double getPenaltyScore(RaceColumn raceColumn, Competitor competitor, MaxPointsReason maxPointsReason, Integer numberOfCompetitorsInRace, NumberOfCompetitorsInLeaderboardFetcher numberOfCompetitorsInLeaderboardFetcher) { Double result; - if (numberOfCompetitorsInRace == null) { + if (numberOfCompetitorsInRace == null || raceColumn.hasSplitFleetContiguousScoring()) { result = (double) (numberOfCompetitorsInLeaderboardFetcher.getNumberOfCompetitorsInLeaderboard()+1); } else { result = (double) (numberOfCompetitorsInRace+1); diff --git a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/leaderboard/impl/LowPointWinnerGetsZero.java b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/leaderboard/impl/LowPointWinnerGetsZero.java index 7dd0a3f2289..e042eed5c84 100755 --- a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/leaderboard/impl/LowPointWinnerGetsZero.java +++ b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/leaderboard/impl/LowPointWinnerGetsZero.java @@ -5,6 +5,7 @@ import java.util.concurrent.Callable; import com.sap.sailing.domain.base.Competitor; import com.sap.sailing.domain.base.RaceColumn; import com.sap.sailing.domain.common.ScoringSchemeType; +import com.sap.sailing.domain.leaderboard.NumberOfCompetitorsInLeaderboardFetcher; /** * As compared to the regular low-point scheme, the 2013 ISAF World Cup will score the winner of a race with @@ -30,7 +31,7 @@ public class LowPointWinnerGetsZero extends LowPoint { private static final long serialVersionUID = 3405249102284162690L; @Override - public Double getScoreForRank(RaceColumn raceColumn, Competitor competitor, int rank, Callable numberOfCompetitorsInRacefetcher) { + public Double getScoreForRank(RaceColumn raceColumn, Competitor competitor, int rank, Callable numberOfCompetitorsInRacefetcher, NumberOfCompetitorsInLeaderboardFetcher numberOfCompetitorsInLeaderboardFetcher) { return rank == 0 ? null : rank == 1 ? 0.0 : (double) rank; } diff --git a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/leaderboard/impl/ScoreCorrectionImpl.java b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/leaderboard/impl/ScoreCorrectionImpl.java index 70da2000ee1..3b8fce93ac2 100755 --- a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/leaderboard/impl/ScoreCorrectionImpl.java +++ b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/leaderboard/impl/ScoreCorrectionImpl.java @@ -365,7 +365,7 @@ public class ScoreCorrectionImpl implements SettableScoreCorrection { public Integer call() { return getNumberOfCompetitorsInRace(raceColumn, competitor, numberOfCompetitorsInLeaderboardFetcher); } - }); + }, numberOfCompetitorsInLeaderboardFetcher); } catch (Exception e) { throw new RuntimeException(e); } @@ -437,7 +437,7 @@ public class ScoreCorrectionImpl implements SettableScoreCorrection { public Integer call() { return getNumberOfCompetitorsInRace(raceColumn, competitor, numberOfCompetitorsInLeaderboardFetcher); } - }); + }, numberOfCompetitorsInLeaderboardFetcher); } catch (Exception e) { throw new RuntimeException(e); } diff --git a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/leaderboard/meta/MetaLeaderboardColumn.java b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/leaderboard/meta/MetaLeaderboardColumn.java index 58ea343050e..71d5f4de383 100755 --- a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/leaderboard/meta/MetaLeaderboardColumn.java +++ b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/leaderboard/meta/MetaLeaderboardColumn.java @@ -131,6 +131,11 @@ public class MetaLeaderboardColumn extends SimpleAbstractRaceColumn implements R getRaceColumnListeners().notifyListenersAboutIsFirstColumnIsNonDiscardableCarryForwardChanged(raceColumn, firstColumnIsNonDiscardableCarryForward); } + @Override + public void hasSplitFleetContiguousScoringChanged(RaceColumn raceColumn, boolean hasSplitFleetContiguousScoring) { + getRaceColumnListeners().notifyListenersAboutHasSplitFleetContiguousScoringChanged(raceColumn, hasSplitFleetContiguousScoring); + } + @Override public boolean canAddRaceColumnToContainer(RaceColumn raceColumn) { return getRaceColumnListeners().canAddRaceColumnToContainer(raceColumn); @@ -193,4 +198,8 @@ public class MetaLeaderboardColumn extends SimpleAbstractRaceColumn implements R @Override public void removeRaceIdentifier(Fleet fleet) { } + + @Override + public void setMasterDataExportOngoingThreadFlag(boolean flagValue) { + } } diff --git a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/masterdataimport/EventMasterData.java b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/masterdataimport/EventMasterData.java deleted file mode 100644 index c7bff6e406d..00000000000 --- a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/masterdataimport/EventMasterData.java +++ /dev/null @@ -1,49 +0,0 @@ -package com.sap.sailing.domain.masterdataimport; - -import com.sap.sailing.domain.common.impl.Util.Pair; - -public class EventMasterData { - - private String id; - private String name; - private String venueName; - private String pubUrl; - private Iterable> courseAreas; - private boolean isPublic; - - public EventMasterData(String id, String name, String venueName, String pubUrl, Iterable> courseAreas, boolean isPublic) { - this.id = id; - this.name = name; - this.venueName = venueName; - this.pubUrl = pubUrl; - this.courseAreas = courseAreas; - this.isPublic = isPublic; - } - - public String getId() { - return id; - } - - public String getName() { - return name; - } - - public String getVenueName() { - return venueName; - } - - public String getPubUrl() { - return pubUrl; - } - - public Iterable> getCourseAreas() { - return courseAreas; - } - - public boolean isPublic() { - return isPublic; - } - - - -} diff --git a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/masterdataimport/FlexibleLeaderboardMasterData.java b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/masterdataimport/FlexibleLeaderboardMasterData.java deleted file mode 100644 index 63274a80f71..00000000000 --- a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/masterdataimport/FlexibleLeaderboardMasterData.java +++ /dev/null @@ -1,60 +0,0 @@ -package com.sap.sailing.domain.masterdataimport; - -import java.io.Serializable; -import java.util.List; -import java.util.Map; - -import com.sap.sailing.domain.base.Competitor; -import com.sap.sailing.domain.base.CourseArea; -import com.sap.sailing.domain.base.LeaderboardMasterData; -import com.sap.sailing.domain.leaderboard.Leaderboard; -import com.sap.sailing.domain.leaderboard.ScoringScheme; -import com.sap.sailing.domain.leaderboard.impl.FlexibleLeaderboardImpl; -import com.sap.sailing.domain.racelog.RaceLogEvent; - -public class FlexibleLeaderboardMasterData extends LeaderboardMasterData { - - private ScoringScheme scoringScheme; - - private String courseAreaId; - - private CourseArea courseArea; - - private List raceColumns; - - public FlexibleLeaderboardMasterData(String name, String displayName, int[] resultDiscardingRule, - Map competitorsById, ScoreCorrectionMasterData scoreCorrection, - ScoringScheme scoringScheme, String courseAreaId, List raceColumns, - Map carriedPoints, List suppressedCompetitors, - Map displayNamesByCompetitorId, - Map>> raceLogEvents) { - super(name, displayName, resultDiscardingRule, competitorsById, scoreCorrection, carriedPoints, - suppressedCompetitors, displayNamesByCompetitorId, raceLogEvents); - this.scoringScheme = scoringScheme; - this.courseAreaId = courseAreaId; - this.raceColumns = raceColumns; - } - - public ScoringScheme getScoringScheme() { - return scoringScheme; - } - - public String getCourseAreaId() { - return courseAreaId; - } - - public void setCourseArea(CourseArea courseArea) { - this.courseArea = courseArea; - } - - @Override - public Leaderboard getLeaderboard() { - return new FlexibleLeaderboardImpl(getName(), getResultDiscardingRule(), scoringScheme, - courseArea); - } - - public List getRaceColumns() { - return raceColumns; - } - -} diff --git a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/masterdataimport/LeaderboardGroupMasterData.java b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/masterdataimport/LeaderboardGroupMasterData.java deleted file mode 100644 index 69415391588..00000000000 --- a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/masterdataimport/LeaderboardGroupMasterData.java +++ /dev/null @@ -1,108 +0,0 @@ -package com.sap.sailing.domain.masterdataimport; - -import java.io.Serializable; -import java.util.List; -import java.util.Map; -import java.util.Set; - -import com.sap.sailing.domain.base.Competitor; -import com.sap.sailing.domain.base.LeaderboardMasterData; -import com.sap.sailing.domain.leaderboard.ScoringScheme; -import com.sap.sailing.domain.leaderboard.ThresholdBasedResultDiscardingRule; -import com.sap.sailing.domain.leaderboard.impl.ThresholdBasedResultDiscardingRuleImpl; - -/** - * Holds leaderboard group object AND its leaderboards, etc - * - * @author d054528 Frederik Petersen - * - */ -public class LeaderboardGroupMasterData { - - private final String name; - private final String description; - private final boolean hasOverallLeaderboard; - private final ScoringScheme overallLeaderboardScoringScheme; - private final int[] overallLeaderboardDiscardingRule; - private final Iterable leaderboards; - private final boolean displayGroupsRevese; - private final Set events; - private final Set regattas; - private final Map metaColumnsWithFactors; - private final List overallLeaderboardSuppressedCompetitorIds; - - public LeaderboardGroupMasterData(String name, String description, boolean displayGroupsRevese, - boolean hasOverallLeaderboard, ScoringScheme overallLeaderboardScoringScheme, - int[] overallLeaderboardDiscardingRule, List overallLeaderboardAuppressedCompetitorIds, - Map metaColumnsWithFactors, Iterable leaderboards, Set events, Set regattas) { - super(); - this.name = name; - this.description = description; - this.hasOverallLeaderboard = hasOverallLeaderboard; - this.overallLeaderboardScoringScheme = overallLeaderboardScoringScheme; - this.overallLeaderboardSuppressedCompetitorIds = overallLeaderboardAuppressedCompetitorIds; - this.overallLeaderboardDiscardingRule = overallLeaderboardDiscardingRule; - this.metaColumnsWithFactors = metaColumnsWithFactors; - this.leaderboards = leaderboards; - this.displayGroupsRevese = displayGroupsRevese; - this.events = events; - this.regattas = regattas; - } - - public Competitor getCompetitorById(Serializable id) { - for (LeaderboardMasterData leaderboard : leaderboards) { - Competitor c = leaderboard.getCompetitorsById().get(id); - if (c != null) { - return c; - } - } - return null; - } - - public String getName() { - return name; - } - - public String getDescription() { - return description; - } - - public boolean hasOverallLeaderboard() { - return hasOverallLeaderboard; - } - - public ScoringScheme getOverallLeaderboardScoringScheme() { - return overallLeaderboardScoringScheme; - } - - public List getOverallLeaderboardSuppressedCompetitorIds() { - return overallLeaderboardSuppressedCompetitorIds; - } - - public ThresholdBasedResultDiscardingRule getOverallLeaderboardDiscardingRule() { - return overallLeaderboardDiscardingRule == null ? new ThresholdBasedResultDiscardingRuleImpl(new int[0]) : - new ThresholdBasedResultDiscardingRuleImpl(overallLeaderboardDiscardingRule); - } - - public Iterable getLeaderboards() { - return leaderboards; - } - - public boolean isDisplayGroupsRevese() { - return displayGroupsRevese; - } - - public Set getEvents() { - return events; - } - - public Set getRegattas() { - return regattas; - } - - public Map getMetaColumnsWithFactors() { - return metaColumnsWithFactors; - } - - -} diff --git a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/masterdataimport/RaceColumnMasterData.java b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/masterdataimport/RaceColumnMasterData.java deleted file mode 100644 index d021f9841ed..00000000000 --- a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/masterdataimport/RaceColumnMasterData.java +++ /dev/null @@ -1,45 +0,0 @@ -package com.sap.sailing.domain.masterdataimport; - -import java.util.Map; -import java.util.Set; - -import com.sap.sailing.domain.common.RaceIdentifier; - -public class RaceColumnMasterData { - private final String name; - private final boolean medal; - private final Map raceIdentifiersByFleetName; - private Double factor; - private Set windTracks; - - public RaceColumnMasterData(String name, boolean medal, Map raceIdentifiersByFleetName, - Double factor, Set windTracks) { - super(); - this.name = name; - this.medal = medal; - this.raceIdentifiersByFleetName = raceIdentifiersByFleetName; - this.factor = factor; - this.windTracks = windTracks; - } - - public String getName() { - return name; - } - - public boolean isMedal() { - return medal; - } - - public Map getRaceIdentifiersByFleetName() { - return raceIdentifiersByFleetName; - } - - public Double getFactor() { - return factor; - } - - public Set getWindTrackMasterData() { - return windTracks; - } - -} diff --git a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/masterdataimport/RegattaLeaderboardMasterData.java b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/masterdataimport/RegattaLeaderboardMasterData.java deleted file mode 100644 index bfaaf3c680e..00000000000 --- a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/masterdataimport/RegattaLeaderboardMasterData.java +++ /dev/null @@ -1,47 +0,0 @@ -package com.sap.sailing.domain.masterdataimport; - -import java.io.Serializable; -import java.util.List; -import java.util.Map; - -import com.sap.sailing.domain.base.Competitor; -import com.sap.sailing.domain.base.LeaderboardMasterData; -import com.sap.sailing.domain.base.Regatta; -import com.sap.sailing.domain.common.RegattaIdentifier; -import com.sap.sailing.domain.common.RegattaName; -import com.sap.sailing.domain.leaderboard.Leaderboard; -import com.sap.sailing.domain.leaderboard.impl.RegattaLeaderboardImpl; -import com.sap.sailing.domain.racelog.RaceLogEvent; - -public class RegattaLeaderboardMasterData extends LeaderboardMasterData { - - private String regattaName; - private Regatta regatta; - - public RegattaLeaderboardMasterData(String name, String displayName, int[] resultDiscardingRule, - Map competitorsById, ScoreCorrectionMasterData scoreCorrection, - String regattaName, Map carriedPoints, List suppressedCompetitors, - Map displayNamesByCompetitorId, - Map>> raceLogEvents) { - super(name, displayName, resultDiscardingRule, competitorsById, scoreCorrection, carriedPoints, - suppressedCompetitors, displayNamesByCompetitorId, raceLogEvents); - this.regattaName = regattaName; - } - - public RegattaIdentifier getRegattaName() { - return new RegattaName(regattaName); - } - - public void setRegatta(Regatta regatta) { - this.regatta = regatta; - } - - @Override - public Leaderboard getLeaderboard() { - if (regatta == null) { - return null; - } - return new RegattaLeaderboardImpl(regatta, getResultDiscardingRule()); - } - -} diff --git a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/masterdataimport/RegattaMasterData.java b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/masterdataimport/RegattaMasterData.java deleted file mode 100644 index 50887bc34e7..00000000000 --- a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/masterdataimport/RegattaMasterData.java +++ /dev/null @@ -1,74 +0,0 @@ -package com.sap.sailing.domain.masterdataimport; - -import java.io.Serializable; - -import com.sap.sailing.domain.base.configuration.RegattaConfiguration; -public class RegattaMasterData { - - private Serializable id; - private String baseName; - private String defaultCourseAreaId; - private String boatClassName; - private String scoringSchemeType; - private Iterable series; - private final RegattaConfiguration configuration; - private boolean isPersistent; - private String regattaName; - private Iterable raceIdsAsStrings; - public RegattaMasterData(Serializable id, String baseName, String defaultCourseAreaId, String boatClassName, - String scoringSchemeType, Iterable series, boolean isPersistent, String regattaName, - Iterable raceIdsAsStrings, - RegattaConfiguration configuration) { - this.id = id; - this.baseName = baseName; - this.defaultCourseAreaId = defaultCourseAreaId; - this.boatClassName = boatClassName; - this.scoringSchemeType = scoringSchemeType; - this.series = series; - this.isPersistent = isPersistent; - this.regattaName = regattaName; - this.raceIdsAsStrings = raceIdsAsStrings; - this.configuration = configuration; - } - - public Iterable getRaceIdsAsStrings() { - return raceIdsAsStrings; - } - - public Serializable getId() { - return id; - } - - public String getBaseName() { - return baseName; - } - - public String getDefaultCourseAreaId() { - return defaultCourseAreaId; - } - - public RegattaConfiguration getRegattaConfiguration() { - return configuration; - } - - public String getBoatClassName() { - return boatClassName; - } - - public String getScoringSchemeType() { - return scoringSchemeType; - } - - public Iterable getSeries() { - return series; - } - - public boolean isPersistent() { - return isPersistent; - } - - public String getRegattaName() { - return regattaName; - } - -} diff --git a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/masterdataimport/ScoreCorrectionMasterData.java b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/masterdataimport/ScoreCorrectionMasterData.java deleted file mode 100644 index 9a3ad10770b..00000000000 --- a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/masterdataimport/ScoreCorrectionMasterData.java +++ /dev/null @@ -1,29 +0,0 @@ -package com.sap.sailing.domain.masterdataimport; - -import java.util.Map; - -public class ScoreCorrectionMasterData { - - private String comment; - private Long timepointMillis; - private Map> correctionForRaceColumns; - - public ScoreCorrectionMasterData(String comment, Long timepointMillis, - Map> correctionForRaceColumns) { - this.comment = comment; - this.timepointMillis = timepointMillis; - this.correctionForRaceColumns = correctionForRaceColumns; - } - - public String getComment() { - return comment; - } - - public Long getTimepointMillis() { - return timepointMillis; - } - - public Map> getCorrectionForRaceColumns() { - return correctionForRaceColumns; - } -} diff --git a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/masterdataimport/SeriesMasterData.java b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/masterdataimport/SeriesMasterData.java deleted file mode 100644 index 13b180f7adc..00000000000 --- a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/masterdataimport/SeriesMasterData.java +++ /dev/null @@ -1,42 +0,0 @@ -package com.sap.sailing.domain.masterdataimport; - -import com.sap.sailing.domain.base.Fleet; - -public class SeriesMasterData { - - private String name; - private boolean isMedal; - private Iterable fleets; - private Iterable raceColumns; - private int[] discardingRule; - - public SeriesMasterData(String name, boolean isMedal, Iterable fleets, Iterable raceColumns, int[] discardingRule) { - this.name = name; - this.isMedal = isMedal; - this.fleets = fleets; - this.raceColumns = raceColumns; - this.discardingRule = discardingRule; - } - - public String getName() { - return name; - } - - public boolean isMedal() { - return isMedal; - } - - public Iterable getFleets() { - return fleets; - } - - public Iterable getRaceColumnNames() { - return raceColumns; - } - - public int[] getDiscardingRule() { - return discardingRule; - } - - -} diff --git a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/masterdataimport/SingleScoreCorrectionMasterData.java b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/masterdataimport/SingleScoreCorrectionMasterData.java deleted file mode 100644 index 456eba3f6ad..00000000000 --- a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/masterdataimport/SingleScoreCorrectionMasterData.java +++ /dev/null @@ -1,30 +0,0 @@ -package com.sap.sailing.domain.masterdataimport; - -import java.io.Serializable; - -public class SingleScoreCorrectionMasterData { - - private Serializable competitorId; - private Double explicitScoreCorrection; - private String maxPointsReason; - - public SingleScoreCorrectionMasterData(Serializable competitorId, Double explicitScoreCorrection, - String maxPointsReason) { - this.competitorId = competitorId; - this.explicitScoreCorrection = explicitScoreCorrection; - this.maxPointsReason = maxPointsReason; - } - - public Serializable getCompetitorId() { - return competitorId; - } - - public Double getExplicitScoreCorrection() { - return explicitScoreCorrection; - } - - public String getMaxPointsReason() { - return maxPointsReason; - } - -} diff --git a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/masterdataimport/TopLevelMasterData.java b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/masterdataimport/TopLevelMasterData.java new file mode 100644 index 00000000000..3b4d1c4b0be --- /dev/null +++ b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/masterdataimport/TopLevelMasterData.java @@ -0,0 +1,169 @@ +package com.sap.sailing.domain.masterdataimport; + +import java.io.Serializable; +import java.util.Collection; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Set; + +import com.sap.sailing.domain.base.CourseArea; +import com.sap.sailing.domain.base.Event; +import com.sap.sailing.domain.base.Fleet; +import com.sap.sailing.domain.base.RaceColumn; +import com.sap.sailing.domain.base.Regatta; +import com.sap.sailing.domain.common.WindSource; +import com.sap.sailing.domain.common.media.MediaTrack; +import com.sap.sailing.domain.leaderboard.Leaderboard; +import com.sap.sailing.domain.leaderboard.LeaderboardGroup; +import com.sap.sailing.domain.leaderboard.RegattaLeaderboard; +import com.sap.sailing.domain.tracking.TrackedRace; +import com.sap.sailing.domain.tracking.WindTrack; + +/** + * Holds all information needed for a master data import. + * + * @author Frederik Petersen (D054528) + * + */ +public class TopLevelMasterData implements Serializable { + + private static final long serialVersionUID = 4820893865792553281L; + private final Map> raceIdStringsForRegatta; + private final Set allMediaTracks; + private final Set leaderboardGroups; + private final Set windTrackMasterData; + private final Map> eventForLeaderboardGroup; + + public TopLevelMasterData(final Set groupsToExport, final Iterable allEvents, + final Map regattaForRaceIdString, final Collection allMediaTracks) { + this.raceIdStringsForRegatta = convertToRaceIdStringsForRegattaMap(regattaForRaceIdString); + this.allMediaTracks = new HashSet(); + this.allMediaTracks.addAll(allMediaTracks); + this.leaderboardGroups = groupsToExport; + this.windTrackMasterData = fillWindMap(groupsToExport); + this.eventForLeaderboardGroup = createEventMap(groupsToExport, allEvents); + } + + /** + * Workaround to look for the events connected to RegattaLeadeboards. There should be a proper connection between + * regatta and event soon. TODO + * + * @param groupsToExport + * @param allEvents + * @return + */ + private Map> createEventMap(Set groupsToExport, + Iterable allEvents) { + Map> eventsForLeaderboardGroup = new HashMap>(); + Map eventForCourseArea = new HashMap(); + for (Event event : allEvents) { + for (CourseArea courseArea : event.getVenue().getCourseAreas()) { + eventForCourseArea.put(courseArea, event); + } + } + for (LeaderboardGroup leaderboardGroup : groupsToExport) { + HashSet eventSet = new HashSet(); + eventsForLeaderboardGroup.put(leaderboardGroup, eventSet); + for (Leaderboard leaderboard : leaderboardGroup.getLeaderboards()) { + if (leaderboard instanceof RegattaLeaderboard) { + RegattaLeaderboard regattaLeaderboard = (RegattaLeaderboard) leaderboard; + CourseArea courseArea = regattaLeaderboard.getRegatta().getDefaultCourseArea(); + if (courseArea != null) { + Event event = eventForCourseArea.get(courseArea); + if (event != null) { + eventSet.add(event); + } + } + } + } + + } + return eventsForLeaderboardGroup; + } + + private Map> convertToRaceIdStringsForRegattaMap(Map regattaForRaceIdString) { + Map> raceIdStringsForRegatta = new HashMap>(); + for (Entry entry : regattaForRaceIdString.entrySet()) { + Regatta regatta = entry.getValue(); + Set raceIds = raceIdStringsForRegatta.get(regatta); + if (raceIds == null) { + raceIds = new HashSet(); + raceIdStringsForRegatta.put(regatta, raceIds); + } + raceIds.add(entry.getKey()); + } + return raceIdStringsForRegatta; + } + + private Set fillWindMap(Set groupsToExport) { + Set windTrackMasterDataSet = new HashSet(); + for (LeaderboardGroup group : groupsToExport) { + for (Leaderboard leaderboard : group.getLeaderboards()) { + for (RaceColumn raceColumn : leaderboard.getRaceColumns()) { + for (Fleet fleet : raceColumn.getFleets()) { + addWindTracksToSetIfExistantAndSourceCanBeStored(windTrackMasterDataSet, raceColumn, fleet); + } + } + } + } + return windTrackMasterDataSet; + } + + private void addWindTracksToSetIfExistantAndSourceCanBeStored(Set windTrackMasterDataSet, + RaceColumn raceColumn, Fleet fleet) { + TrackedRace trackedRace = raceColumn.getTrackedRace(fleet); + if (trackedRace != null) { + Iterable windSources = trackedRace.getWindSources(); + String raceName = trackedRace.getRace().getName(); + Serializable raceId = trackedRace.getRace().getId(); + String regattaName = trackedRace.getTrackedRegatta().getRegatta().getName(); + if (windSources != null) { + for (WindSource source : windSources) { + if (source.canBeStored()) { + WindTrack track = trackedRace.getOrCreateWindTrack(source); + track.lockForRead(); + try { + windTrackMasterDataSet.add(new WindTrackMasterData(source.getType(), source.getId(), track + .getFixes(), regattaName, raceName, raceId)); + } finally { + track.unlockAfterRead(); + } + } + } + } + } + } + + public Collection getAllMediaTracks() { + return allMediaTracks; + } + + public Collection getLeaderboardGroups() { + return leaderboardGroups; + } + + public Set getWindTrackMasterData() { + return windTrackMasterData; + } + + public void setMasterDataExportFlagOnRaceColumns(boolean flagValue) { + for (LeaderboardGroup group : leaderboardGroups) { + for (Leaderboard leaderboard : group.getLeaderboards()) { + for (RaceColumn raceColumn : leaderboard.getRaceColumns()) { + raceColumn.setMasterDataExportOngoingThreadFlag(true); + } + } + } + } + + public Map> getRaceIdStringsForRegatta() { + return raceIdStringsForRegatta; + } + + public Map> getEventForLeaderboardGroup() { + return eventForLeaderboardGroup; + } + +} diff --git a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/masterdataimport/WindTrackMasterData.java b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/masterdataimport/WindTrackMasterData.java index c9dfce4b859..8493667ea5a 100644 --- a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/masterdataimport/WindTrackMasterData.java +++ b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/masterdataimport/WindTrackMasterData.java @@ -1,7 +1,6 @@ package com.sap.sailing.domain.masterdataimport; import java.io.Serializable; -import java.util.Set; import com.sap.sailing.domain.common.WindSource; import com.sap.sailing.domain.common.WindSourceType; @@ -9,34 +8,36 @@ import com.sap.sailing.domain.common.impl.WindSourceImpl; import com.sap.sailing.domain.common.impl.WindSourceWithAdditionalID; import com.sap.sailing.domain.tracking.Wind; -public class WindTrackMasterData { +public class WindTrackMasterData implements Serializable { + + private static final long serialVersionUID = -2047209715118386803L; private final WindSourceType windSourceType; - private final Serializable windSourceId; - private final Set fixes; + private final Object windSourceId; + private final Iterable fixes; private final String regattaName; private final String raceName; private final Serializable raceId; - public WindTrackMasterData(String windSourceTypeName, Serializable windSourceId, Set fixes, + public WindTrackMasterData(WindSourceType windSourceType, Object windSourceId, Iterable fixes, String regattaName, String raceName, Serializable raceId) { this.windSourceId = windSourceId; this.fixes = fixes; this.regattaName = regattaName; this.raceName = raceName; this.raceId = raceId; - this.windSourceType = WindSourceType.valueOf(windSourceTypeName); + this.windSourceType = windSourceType; } public WindSourceType getWindSourceType() { return windSourceType; } - public Serializable getWindSourceId() { + public Object getWindSourceId() { return windSourceId; } - public Set getFixes() { + public Iterable getFixes() { return fixes; } @@ -52,7 +53,6 @@ public class WindTrackMasterData { return raceId; } - public WindSource getWindSource() { WindSource source; if (windSourceId != null) { diff --git a/java/com.sap.sailing.domain/src/com/sap/sailing/util/impl/RaceColumnListeners.java b/java/com.sap.sailing.domain/src/com/sap/sailing/util/impl/RaceColumnListeners.java index 11e4b69eca0..3fd17e9b759 100755 --- a/java/com.sap.sailing.domain/src/com/sap/sailing/util/impl/RaceColumnListeners.java +++ b/java/com.sap.sailing.domain/src/com/sap/sailing/util/impl/RaceColumnListeners.java @@ -91,6 +91,12 @@ public class RaceColumnListeners implements Serializable { } } + public void notifyListenersAboutHasSplitFleetContiguousScoringChanged(RaceColumn raceColumn, boolean hasSplitFleetContiguousScoring) { + for (RaceColumnListener listener : getRaceColumnListeners()) { + listener.hasSplitFleetContiguousScoringChanged(raceColumn, hasSplitFleetContiguousScoring); + } + } + public void notifyListenersAboutIsFirstColumnIsNonDiscardableCarryForwardChanged(RaceColumn raceColumn, boolean firstColumnIsNonDiscardableCarryForward) { for (RaceColumnListener listener : getRaceColumnListeners()) { listener.isFirstColumnIsNonDiscardableCarryForwardChanged(raceColumn, firstColumnIsNonDiscardableCarryForward); @@ -151,4 +157,5 @@ public class RaceColumnListeners implements Serializable { listener.raceLogEventAdded(raceColumn, raceLogIdentifier, event); } } + } diff --git a/java/com.sap.sailing.gwt.ui/META-INF/MANIFEST.MF b/java/com.sap.sailing.gwt.ui/META-INF/MANIFEST.MF index 3041f3ab0fc..522143acdf8 100755 --- a/java/com.sap.sailing.gwt.ui/META-INF/MANIFEST.MF +++ b/java/com.sap.sailing.gwt.ui/META-INF/MANIFEST.MF @@ -34,8 +34,8 @@ Bundle-Activator: com.sap.sailing.gwt.ui.server.Activator Bundle-ActivationPolicy: lazy Import-Package: javax.jms;version="1.1.0", javax.servlet;version="2.6.0", - javax.servlet.http;version="2.6.0", javax.servlet.descriptor;version="2.6.0", + javax.servlet.http;version="2.6.0", org.json.simple, org.json.simple.parser, org.osgi.framework, diff --git a/java/com.sap.sailing.gwt.ui/RaceBoard.css b/java/com.sap.sailing.gwt.ui/RaceBoard.css index 077019b1f6c..24b3072fcee 100644 --- a/java/com.sap.sailing.gwt.ui/RaceBoard.css +++ b/java/com.sap.sailing.gwt.ui/RaceBoard.css @@ -153,6 +153,10 @@ img.openColumn { text-decoration: none; } +.competitorInfo-Canvas { + pointer-events: none; +} + .gwt-DialogBox { z-index: 20; } diff --git a/java/com.sap.sailing.gwt.ui/SailingGWT Remote Profiling.launch b/java/com.sap.sailing.gwt.ui/SailingGWT Remote Profiling.launch index 0c012601c94..3b48a46e865 100755 --- a/java/com.sap.sailing.gwt.ui/SailingGWT Remote Profiling.launch +++ b/java/com.sap.sailing.gwt.ui/SailingGWT Remote Profiling.launch @@ -27,7 +27,6 @@ - diff --git a/java/com.sap.sailing.gwt.ui/SailingGWT.launch b/java/com.sap.sailing.gwt.ui/SailingGWT.launch index 2a3d82ae5a5..a737234f455 100755 --- a/java/com.sap.sailing.gwt.ui/SailingGWT.launch +++ b/java/com.sap.sailing.gwt.ui/SailingGWT.launch @@ -27,7 +27,6 @@ - diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/DeviceConfigurationDetailComposite.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/DeviceConfigurationDetailComposite.java index 3c70ad1a011..c4d1ec76f18 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/DeviceConfigurationDetailComposite.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/DeviceConfigurationDetailComposite.java @@ -26,11 +26,11 @@ import com.google.gwt.user.client.ui.VerticalPanel; import com.sap.sailing.gwt.ui.client.ErrorReporter; import com.sap.sailing.gwt.ui.client.SailingServiceAsync; import com.sap.sailing.gwt.ui.client.StringMessages; +import com.sap.sailing.gwt.ui.client.shared.controls.listedit.ListEditorComposite; +import com.sap.sailing.gwt.ui.client.shared.controls.listedit.StringListEditorComposite; import com.sap.sailing.gwt.ui.shared.DeviceConfigurationDTO; import com.sap.sailing.gwt.ui.shared.DeviceConfigurationDTO.RegattaConfigurationDTO; import com.sap.sailing.gwt.ui.shared.DeviceConfigurationMatcherDTO; -import com.sap.sailing.gwt.ui.shared.ListEditorComposite; -import com.sap.sailing.gwt.ui.shared.StringListEditorComposite; import com.sap.sse.gwt.ui.DataEntryDialog.DialogCallback; public class DeviceConfigurationDetailComposite extends Composite { @@ -208,7 +208,7 @@ public class DeviceConfigurationDetailComposite extends Composite { List initialValues = originalConfiguration.allowedCourseAreaNames == null ? Collections . emptyList() : originalConfiguration.allowedCourseAreaNames; - allowedCourseAreasList = StringListEditorComposite.createCollapsed(initialValues, stringMessages, stringMessages.courseAreas(), resources.removeIcon(), suggestedCourseAreaNames); + allowedCourseAreasList = new StringListEditorComposite(initialValues, stringMessages, stringMessages.courseAreas(), resources.removeIcon(), suggestedCourseAreaNames); allowedCourseAreasList.setWidth("80%"); allowedCourseAreasList.addValueChangeHandler(dirtyValueMarker); @@ -220,7 +220,7 @@ public class DeviceConfigurationDetailComposite extends Composite { List initialValues = originalConfiguration.byNameDesignerCourseNames == null ? Collections . emptyList() : originalConfiguration.byNameDesignerCourseNames; - courseNamesList = StringListEditorComposite.createCollapsed(initialValues, stringMessages, stringMessages.courseNames(), resources.removeIcon(), suggestedCourseNames); + courseNamesList = new StringListEditorComposite(initialValues, stringMessages, stringMessages.courseNames(), resources.removeIcon(), suggestedCourseNames); courseNamesList.setWidth("80%"); courseNamesList.addValueChangeHandler(dirtyValueMarker); grid.setWidget(gridRow, 0, new Label(stringMessages.courseNames())); diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/FleetListEditorComposite.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/FleetListEditorComposite.java index 61b3e36aecd..55103bfa42b 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/FleetListEditorComposite.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/FleetListEditorComposite.java @@ -2,34 +2,29 @@ package com.sap.sailing.gwt.ui.adminconsole; import java.util.List; +import com.google.gwt.dom.client.Style.FontWeight; import com.google.gwt.event.dom.client.ChangeEvent; import com.google.gwt.event.dom.client.ChangeHandler; import com.google.gwt.event.dom.client.ClickEvent; import com.google.gwt.event.dom.client.ClickHandler; import com.google.gwt.resources.client.ImageResource; import com.google.gwt.user.client.ui.Button; -import com.google.gwt.user.client.ui.CaptionPanel; -import com.google.gwt.user.client.ui.Grid; import com.google.gwt.user.client.ui.HasVerticalAlignment; import com.google.gwt.user.client.ui.HorizontalPanel; import com.google.gwt.user.client.ui.IntegerBox; +import com.google.gwt.user.client.ui.Label; import com.google.gwt.user.client.ui.ListBox; import com.google.gwt.user.client.ui.TextBox; import com.google.gwt.user.client.ui.Widget; import com.sap.sailing.domain.common.Color; import com.sap.sailing.domain.common.dto.FleetDTO; import com.sap.sailing.gwt.ui.client.StringMessages; -import com.sap.sailing.gwt.ui.shared.ListEditorComposite; +import com.sap.sailing.gwt.ui.client.shared.controls.listedit.ExpandedListEditorUi; +import com.sap.sailing.gwt.ui.client.shared.controls.listedit.ListEditorComposite; public class FleetListEditorComposite extends ListEditorComposite { - - public static ListEditorComposite createExpanded(List initialValues, - StringMessages stringMessages, ImageResource removeImage) { - return new FleetListEditorComposite(initialValues, new ExpandedUi(stringMessages, removeImage)); - } - - public FleetListEditorComposite(List initialValues, ListEditorUiStrategy activeUi) { - super(initialValues, activeUi); + public FleetListEditorComposite(List initialValues, StringMessages stringMessages, ImageResource removeImage) { + super(initialValues, new ExpandedUi(stringMessages, removeImage)); } private static class ExpandedUi extends ExpandedListEditorUi { @@ -40,10 +35,9 @@ public class FleetListEditorComposite extends ListEditorComposite { @Override protected Widget createAddWidget() { - CaptionPanel captionPanel = new CaptionPanel(stringMessages.addFleet()); - - HorizontalPanel panel = new HorizontalPanel(); - panel.setVerticalAlignment(HasVerticalAlignment.ALIGN_MIDDLE); + HorizontalPanel hPanel = new HorizontalPanel(); + hPanel.setSpacing(4); + hPanel.setVerticalAlignment(HasVerticalAlignment.ALIGN_MIDDLE); final TextBox nameBox = createNameBox(); final IntegerBox orderNoBox = createOrderNoBox(); @@ -56,54 +50,35 @@ public class FleetListEditorComposite extends ListEditorComposite { } }); - Grid fleetsGrid = new Grid(2, 3); - fleetsGrid.setCellSpacing(4); - fleetsGrid.setHTML(0, 0, stringMessages.color()); - fleetsGrid.setHTML(0, 1, stringMessages.name()); - fleetsGrid.setHTML(0, 2, stringMessages.rank()); - fleetsGrid.setWidget(1, 0, colorListBox); - fleetsGrid.setWidget(1, 1, nameBox); - fleetsGrid.setWidget(1, 2, orderNoBox); - - panel.add(fleetsGrid); - panel.add(addButton); - captionPanel.add(panel); - return captionPanel; + hPanel.add(new Label(stringMessages.color() + ":")); + hPanel.add(colorListBox); + hPanel.add(new Label(stringMessages.name() + ":")); + hPanel.add(nameBox); + hPanel.add(new Label(stringMessages.rank() + ":")); + hPanel.add(orderNoBox); + hPanel.add(addButton); + return hPanel; } @Override - protected Widget createValueWidget(FleetDTO value) { - HorizontalPanel panel = new HorizontalPanel(); - - final TextBox nameBox = createNameBox(); - nameBox.setValue(value.getName()); - nameBox.setEnabled(false); - nameBox.setReadOnly(true); - - final IntegerBox orderNoBox = createOrderNoBox(); - orderNoBox.setValue(value.getOrderNo()); - orderNoBox.setEnabled(false); - orderNoBox.setReadOnly(true); - - final ListBox colorListBox = createColorListBox(nameBox, orderNoBox); - colorListBox.setEnabled(false); - if (value.getColor() == null) { - colorListBox.setSelectedIndex(0); + protected Widget createValueWidget(int rowIndex, FleetDTO fleet) { + HorizontalPanel hPanel = new HorizontalPanel(); + hPanel.setSpacing(4); + Label fleetLabel = new Label(stringMessages.fleet() + " '" + fleet.getName() + "' :"); + fleetLabel.getElement().getStyle().setFontWeight(FontWeight.BOLD); + hPanel.add(fleetLabel); + + String valueText = ""; + if(fleet.getColor() != null) { + valueText += stringMessages.color() + " '" + fleet.getColor().toString() + "'"; } else { - for (int i = 1; i < colorListBox.getItemCount(); i++) { - String fleetsColorValue = colorListBox.getValue(i); - FleetColors fleetsColor = FleetColors.valueOf(fleetsColorValue); - if (fleetsColor.getColor().equals(value.getColor())) { - colorListBox.setSelectedIndex(i); - break; - } - } + valueText += stringMessages.noColor(); } - - panel.add(colorListBox); - panel.add(nameBox); - panel.add(orderNoBox); - return panel; + valueText += ", " + stringMessages.rank() + " " + fleet.getOrderNo(); + + hPanel.add(new Label(valueText)); + + return hPanel; } private IntegerBox createOrderNoBox() { @@ -115,7 +90,6 @@ public class FleetListEditorComposite extends ListEditorComposite { private TextBox createNameBox() { final TextBox nameBox = new TextBox(); - nameBox.setValue("Default"); nameBox.setVisibleLength(40); nameBox.setWidth("175px"); return nameBox; diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/RegattaDetailsComposite.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/RegattaDetailsComposite.java index 67710bea756..ffd62bd4268 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/RegattaDetailsComposite.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/RegattaDetailsComposite.java @@ -123,6 +123,13 @@ public class RegattaDetailsComposite extends Composite { } }; + TextColumn hasSplitFleetContiguousScoringColumn = new TextColumn() { + @Override + public String getValue(SeriesDTO series) { + return series.hasSplitFleetContiguousScoring() ? stringMessages.yes() : stringMessages.no(); + } + }; + TextColumn isFirstColumnIsNonDiscardableCarryForwardColumn = new TextColumn() { @Override public String getValue(SeriesDTO series) { @@ -213,6 +220,7 @@ public class RegattaDetailsComposite extends Composite { table.addColumn(discardsColumn, stringMessages.discarding()); table.addColumn(isFirstColumnIsNonDiscardableCarryForwardColumn, stringMessages.firstRaceIsNonDiscardableCarryForward()); table.addColumn(startsWithZeroScoreColumn, stringMessages.startsWithZeroScore()); + table.addColumn(hasSplitFleetContiguousScoringColumn, stringMessages.hasSplitFleetContiguousScoring()); table.addColumn(seriesActionColumn, stringMessages.actions()); return table; @@ -248,6 +256,7 @@ public class RegattaDetailsComposite extends Composite { final boolean isMedalChanged = series.isMedal() != seriesDescriptor.isMedal(); final boolean isStartsWithZeroScoreChanged = series.isStartsWithZeroScore() != seriesDescriptor.isStartsWithZeroScore(); final boolean isFirstColumnIsNonDiscardableCarryForwardChanged = series.isFirstColumnIsNonDiscardableCarryForward() != seriesDescriptor.isFirstColumnIsNonDiscardableCarryForward(); + final boolean hasSplitFleetContiguousScoringChanged = series.hasSplitFleetContiguousScoring() != seriesDescriptor.hasSplitFleetContiguousScoring(); final boolean seriesResultDiscardingThresholdsChanged = !Arrays.equals(series.getDiscardThresholds(), seriesDescriptor.getResultDiscardingThresholds()); final RegattaIdentifier regattaIdentifier = new RegattaName(regatta.getName()); @@ -294,10 +303,11 @@ public class RegattaDetailsComposite extends Composite { regattaRefresher.fillRegattas(); } }); - if (isMedalChanged || seriesResultDiscardingThresholdsChanged || isStartsWithZeroScoreChanged || isFirstColumnIsNonDiscardableCarryForwardChanged) { + if (isMedalChanged || seriesResultDiscardingThresholdsChanged || isStartsWithZeroScoreChanged || isFirstColumnIsNonDiscardableCarryForwardChanged + || hasSplitFleetContiguousScoringChanged) { sailingService.updateSeries(regattaIdentifier, series.getName(), seriesDescriptor.isMedal(), seriesDescriptor.getResultDiscardingThresholds(), seriesDescriptor.isStartsWithZeroScore(), - seriesDescriptor.isFirstColumnIsNonDiscardableCarryForward(), + seriesDescriptor.isFirstColumnIsNonDiscardableCarryForward(), seriesDescriptor.hasSplitFleetContiguousScoring(), new AsyncCallback() { @Override public void onFailure(Throwable caught) { diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/RegattaStructureManagementPanel.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/RegattaStructureManagementPanel.java index f884564dbf8..a0d3a6b4b9f 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/RegattaStructureManagementPanel.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/RegattaStructureManagementPanel.java @@ -160,7 +160,8 @@ public class RegattaStructureManagementPanel extends SimplePanel implements Rega for (SeriesDTO seriesDTO : newRegatta.series) { SeriesCreationParametersDTO seriesPair = new SeriesCreationParametersDTO(seriesDTO.getFleets(), seriesDTO.isMedal(), seriesDTO.isStartsWithZeroScore(), - seriesDTO.isFirstColumnIsNonDiscardableCarryForward(), seriesDTO.getDiscardThresholds()); + seriesDTO.isFirstColumnIsNonDiscardableCarryForward(), seriesDTO.getDiscardThresholds(), + seriesDTO.hasSplitFleetContiguousScoring()); seriesStructure.put(seriesDTO.getName(), seriesPair); } sailingService.createRegatta(newRegatta.getName(), newRegatta.boatClass==null?null:newRegatta.boatClass.getName(), diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/RegattaWithSeriesAndFleetsCreateDialog.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/RegattaWithSeriesAndFleetsCreateDialog.java index fa06e1f8164..3bb12fd277f 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/RegattaWithSeriesAndFleetsCreateDialog.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/RegattaWithSeriesAndFleetsCreateDialog.java @@ -7,10 +7,11 @@ import java.util.HashSet; import java.util.List; import com.google.gwt.core.shared.GWT; +import com.google.gwt.user.client.ui.TabPanel; import com.google.gwt.user.client.ui.VerticalPanel; import com.sap.sailing.gwt.ui.client.StringMessages; +import com.sap.sailing.gwt.ui.client.shared.controls.listedit.ListEditorComposite; import com.sap.sailing.gwt.ui.shared.EventDTO; -import com.sap.sailing.gwt.ui.shared.ListEditorComposite; import com.sap.sailing.gwt.ui.shared.RegattaDTO; import com.sap.sailing.gwt.ui.shared.SeriesDTO; @@ -48,7 +49,7 @@ public class RegattaWithSeriesAndFleetsCreateDialog extends RegattaWithSeriesAnd if (!nameNotEmpty) { errorMessage = stringMessages.pleaseEnterAName(); } else if (!boatClassNotEmpty) { - errorMessage = stringMessages.pleaseEnterAName(); + errorMessage = stringMessages.pleaseEnterABoatClass(); } else if (!unique) { errorMessage = stringMessages.regattaWithThisNameAlreadyExists(); } @@ -98,13 +99,16 @@ public class RegattaWithSeriesAndFleetsCreateDialog extends RegattaWithSeriesAnd super(new RegattaDTO(), existingEvents, stringConstants.addRegatta(), stringConstants.ok(), stringConstants, new RegattaParameterValidator(stringConstants, existingRegattas), callback); - this.seriesEditor = SeriesWithFleetsListEditor.createExpanded(Collections.emptyList(), stringMessages, resources.removeIcon()); + this.seriesEditor = new SeriesWithFleetsListEditor(Collections.emptyList(), stringMessages, resources.removeIcon()); } @Override protected void setupAdditionalWidgetsOnPanel(final VerticalPanel panel) { - panel.add(createHeadlineLabel(stringMessages.series())); - panel.add(seriesEditor); + TabPanel tabPanel = new TabPanel(); + tabPanel.setWidth("100%"); + tabPanel.add(seriesEditor, stringMessages.series()); + tabPanel.selectTab(0); + panel.add(tabPanel); } @Override diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/SeriesDescriptor.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/SeriesDescriptor.java index 918c5b1fb53..a466f32f271 100755 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/SeriesDescriptor.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/SeriesDescriptor.java @@ -17,14 +17,18 @@ public class SeriesDescriptor { private final List races; private final boolean isMedal; private final boolean startsWithZeroScore; + private final boolean hasSplitFleetContiguousScoring; private final boolean firstColumnIsNonDiscardableCarryForward; private final int[] resultDiscardingThresholds; - public SeriesDescriptor(SeriesDTO series, List races, boolean isMedal, int[] resultDiscardingThresholds, boolean startsWithZeroScore, boolean firstColumnIsNonDiscardableCarryForward) { + public SeriesDescriptor(SeriesDTO series, List races, boolean isMedal, + int[] resultDiscardingThresholds, boolean startsWithZeroScore, + boolean firstColumnIsNonDiscardableCarryForward, boolean hasSplitFleetContiguousScoring) { this.series = series; this.races = races; this.isMedal = isMedal; this.startsWithZeroScore = startsWithZeroScore; + this.hasSplitFleetContiguousScoring = hasSplitFleetContiguousScoring; this.resultDiscardingThresholds = resultDiscardingThresholds; this.firstColumnIsNonDiscardableCarryForward = firstColumnIsNonDiscardableCarryForward; } @@ -48,6 +52,10 @@ public class SeriesDescriptor { public boolean isStartsWithZeroScore() { return startsWithZeroScore; } + + public boolean hasSplitFleetContiguousScoring() { + return hasSplitFleetContiguousScoring; + } public boolean isFirstColumnIsNonDiscardableCarryForward() { return firstColumnIsNonDiscardableCarryForward; diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/SeriesEditDialog.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/SeriesEditDialog.java index e1b7df38864..365a60be501 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/SeriesEditDialog.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/SeriesEditDialog.java @@ -7,6 +7,8 @@ import java.util.List; import java.util.Set; import com.google.gwt.core.shared.GWT; +import com.google.gwt.event.dom.client.ChangeEvent; +import com.google.gwt.event.dom.client.ChangeHandler; import com.google.gwt.event.dom.client.ClickEvent; import com.google.gwt.event.dom.client.ClickHandler; import com.google.gwt.event.logical.shared.ValueChangeEvent; @@ -15,17 +17,20 @@ import com.google.gwt.resources.client.ImageResource; import com.google.gwt.user.client.Window; import com.google.gwt.user.client.ui.Button; import com.google.gwt.user.client.ui.CheckBox; +import com.google.gwt.user.client.ui.HasVerticalAlignment; import com.google.gwt.user.client.ui.HorizontalPanel; import com.google.gwt.user.client.ui.Label; import com.google.gwt.user.client.ui.ListBox; +import com.google.gwt.user.client.ui.TabPanel; import com.google.gwt.user.client.ui.TextBox; import com.google.gwt.user.client.ui.VerticalPanel; import com.google.gwt.user.client.ui.Widget; import com.sap.sailing.domain.common.dto.RaceColumnDTO; import com.sap.sailing.gwt.ui.client.StringMessages; +import com.sap.sailing.gwt.ui.client.shared.controls.listedit.StringListEditorComposite; +import com.sap.sailing.gwt.ui.client.shared.controls.listedit.StringListInlineEditorComposite; import com.sap.sailing.gwt.ui.shared.RegattaDTO; import com.sap.sailing.gwt.ui.shared.SeriesDTO; -import com.sap.sailing.gwt.ui.shared.StringListEditorComposite; import com.sap.sse.gwt.ui.DataEntryDialog; public class SeriesEditDialog extends DataEntryDialog { @@ -34,12 +39,15 @@ public class SeriesEditDialog extends DataEntryDialog { private CheckBox isMedalCheckbox; private CheckBox startWithZeroScoreCheckbox; + private CheckBox hasSplitFleetContiguousScoringCheckbox; private CheckBox firstColumnIsNonDiscardableCarryForwardCheckbox; private CheckBox useSeriesResultDiscardingThresholdsCheckbox; private final StringMessages stringMessages; private VerticalPanel additionalWidgetPanel; private final SeriesDTO selectedSeries; + private final RegattaDTO regatta; private final DiscardThresholdBoxes discardThresholdBoxes; + private StringListEditorComposite raceNamesEditor; private static class RaceDialogValidator implements Validator { private StringMessages stringMessages; @@ -105,6 +113,7 @@ public class SeriesEditDialog extends DataEntryDialog { public SeriesEditDialog(RegattaDTO regatta, SeriesDTO selectedSeries, StringMessages stringMessages,DialogCallback callback) { super(stringMessages.actionEditSeries(), null, stringMessages.ok(), stringMessages.cancel(), new RaceDialogValidator(regatta, stringMessages), callback); + this.regatta = regatta; this.selectedSeries = selectedSeries; this.stringMessages = stringMessages; discardThresholdBoxes = new DiscardThresholdBoxes(this, selectedSeries.getDiscardThresholds(), stringMessages); @@ -125,7 +134,7 @@ public class SeriesEditDialog extends DataEntryDialog { return new SeriesDescriptor(selectedSeries, races, isMedalCheckbox.getValue(), useSeriesResultDiscardingThresholdsCheckbox.getValue() ? discardThresholdBoxes.getDiscardThresholds() : null, startWithZeroScoreCheckbox.getValue(), - firstColumnIsNonDiscardableCarryForwardCheckbox.getValue()); + firstColumnIsNonDiscardableCarryForwardCheckbox.getValue(), hasSplitFleetContiguousScoringCheckbox.getValue()); } private RaceColumnDTO findRaceColumnInSeriesByName(SeriesDTO series, String raceColumnName) { @@ -159,6 +168,9 @@ public class SeriesEditDialog extends DataEntryDialog { startWithZeroScoreCheckbox = createCheckbox(stringMessages.startsWithZeroScore()); startWithZeroScoreCheckbox.setValue(selectedSeries.isStartsWithZeroScore()); additionalWidgetPanel.add(startWithZeroScoreCheckbox); + hasSplitFleetContiguousScoringCheckbox = createCheckbox(stringMessages.hasSplitFleetContiguousScoring()); + hasSplitFleetContiguousScoringCheckbox.setValue(selectedSeries.hasSplitFleetContiguousScoring()); + additionalWidgetPanel.add(hasSplitFleetContiguousScoringCheckbox); firstColumnIsNonDiscardableCarryForwardCheckbox = createCheckbox(stringMessages.firstRaceIsNonDiscardableCarryForward()); firstColumnIsNonDiscardableCarryForwardCheckbox.setValue(selectedSeries.isFirstColumnIsNonDiscardableCarryForward()); additionalWidgetPanel.add(firstColumnIsNonDiscardableCarryForwardCheckbox); @@ -173,13 +185,24 @@ public class SeriesEditDialog extends DataEntryDialog { additionalWidgetPanel.add(useSeriesResultDiscardingThresholdsCheckbox); additionalWidgetPanel.add(discardThresholdBoxes.getWidget()); discardThresholdBoxes.getWidget().setVisible(useSeriesResultDiscardingThresholdsCheckbox.getValue()); - raceNamesEditor = new StringListEditorComposite(getExistingRacesOfSeries(), new RaceNamesEditorUi(stringMessages, resources.removeIcon(), seriesName)); - additionalWidgetPanel.add(raceNamesEditor); + + raceNamesEditor = new StringListInlineEditorComposite(getExistingRacesOfSeries(), new RaceNamesEditorUi(regatta, stringMessages, resources.removeIcon(), seriesName)); + raceNamesEditor.addValueChangeHandler(new ValueChangeHandler>() { + @Override + public void onValueChange(ValueChangeEvent> event) { + validate(); + } + }); + + TabPanel tabPanel = new TabPanel(); + tabPanel.setWidth("100%"); + tabPanel.add(raceNamesEditor, stringMessages.races()); + tabPanel.selectTab(0); + additionalWidgetPanel.add(tabPanel); + return additionalWidgetPanel; } - private StringListEditorComposite raceNamesEditor; - private List getExistingRacesOfSeries() { List names = new ArrayList(); SeriesDTO selectedSeries = getSelectedSeries(); @@ -195,63 +218,187 @@ public class SeriesEditDialog extends DataEntryDialog { return selectedSeries; } - private class RaceNamesEditorUi extends StringListEditorComposite.ExpandedUi { + private class RaceNamesEditorUi extends StringListInlineEditorComposite.ExpandedUi { + private final RegattaDTO regatta; - private final ListBox addRacesListBox; + private final ListBox addRacesFromListBox; + private final ListBox addRacesToListBox; private final TextBox raceNamePrefixTextBox; private final Button addRacesBtn; private final String seriesName; + private final Label addRacesHintLabel; - public RaceNamesEditorUi(StringMessages stringMessages, ImageResource removeImage, String seriesName) { + public RaceNamesEditorUi(RegattaDTO regatta, StringMessages stringMessages, ImageResource removeImage, String seriesName) { super(stringMessages, removeImage, Collections.emptyList()); - this.addRacesListBox = createListBox(false); + this.regatta = regatta; + this.addRacesFromListBox = createListBox(false); + this.addRacesToListBox = createListBox(false); this.raceNamePrefixTextBox = createTextBox(null); this.addRacesBtn = new Button(stringMessages.add()); + this.addRacesHintLabel = new Label(""); this.seriesName = seriesName; } + private List resolveRaceNamesToAdd() { + List result = new ArrayList(); + String racePrefix = raceNamePrefixTextBox.getText(); + int to = addRacesToListBox.getSelectedIndex() + 1; + int from = addRacesFromListBox.getSelectedIndex() + 1; + int racesToCreate = to - from + 1; + if(racesToCreate > 0) { + for(int i = from; i <= to; i++) { + String raceName = racePrefix + i; + result.add(raceName); + } + } + + return result; + } + + public void updateHintLabel() { + List resolveRaceNamesToAdd = resolveRaceNamesToAdd(); + String hintText = "Hint: 'Add' will create the races: "; + for(String raceName: resolveRaceNamesToAdd) { + hintText += raceName + " "; + } + addRacesHintLabel.setText(hintText); + } + + public void updateFromToListboxesSelection() { + int nextNumber = calculateNextValidRaceNumber(raceNamePrefixTextBox.getValue()); + addRacesFromListBox.setSelectedIndex(nextNumber-1); + addRacesToListBox.setSelectedIndex(nextNumber-1); + } + + private int calculateNextValidRaceNumber(String prefix) { + int maxNumber = 0; + List allRaces = new ArrayList(); + for (SeriesDTO seriesDTO: regatta.series) { + if(seriesName.equals(seriesDTO.getName())) { + allRaces.addAll(context.getValue()); + } else { + for (RaceColumnDTO raceColumn : seriesDTO.getRaceColumns()) { + allRaces.add(raceColumn.getName()); + } + } + } + for(String name: allRaces) { + if(prefix != null && !prefix.isEmpty()) { + if(name.startsWith(prefix)) { + String withoutPrefix = name.substring(prefix.length(), name.length()); + try { + int number = Integer.parseInt(withoutPrefix); + if(number > maxNumber) { + maxNumber = number; + } + } catch ( NumberFormatException nbe) { + // do nothing + } + } + } else { + try { + int number = Integer.parseInt(name); + if(number > maxNumber) { + maxNumber = number; + } + } catch ( NumberFormatException nbe) { + // do nothing + } + } + } + return maxNumber+1; + } + @Override protected Widget createAddWidget() { + VerticalPanel vPanel = new VerticalPanel(); + HorizontalPanel addRacesPanel = new HorizontalPanel(); - addRacesPanel.setSpacing(3); - addRacesPanel.add(new Label(stringMessages.add())); - addRacesPanel.add(addRacesListBox); + addRacesPanel.setVerticalAlignment(HasVerticalAlignment.ALIGN_MIDDLE); + addRacesPanel.setSpacing(5); + addRacesPanel.add(new Label("Add races")); + for(int i = 1; i <= 50; i++) { - addRacesListBox.addItem("" + i); + addRacesFromListBox.addItem("" + i); + addRacesToListBox.addItem("" + i); } - addRacesListBox.setSelectedIndex(0); + updateFromToListboxesSelection(); + + addRacesFromListBox.addChangeHandler(new ChangeHandler() { + @Override + public void onChange(ChangeEvent event) { + updateHintLabel(); + } + }); + addRacesToListBox.addChangeHandler(new ChangeHandler() { + @Override + public void onChange(ChangeEvent event) { + updateHintLabel(); + } + }); + + addRacesPanel.add(addRacesFromListBox); + addRacesPanel.add(new Label("to")); + addRacesPanel.add(addRacesToListBox); + addRacesPanel.add(new Label("with name prefix")); + + raceNamePrefixTextBox.setWidth("20px"); if ("Default".equals(seriesName)) { raceNamePrefixTextBox.setText("R"); } else { raceNamePrefixTextBox.setText(seriesName.substring(0, 1).toUpperCase()); } - raceNamePrefixTextBox.setWidth("20px"); + + raceNamePrefixTextBox.addValueChangeHandler(new ValueChangeHandler() { + @Override + public void onValueChange(ValueChangeEvent event) { + updateHintLabel(); + } + }); + addRacesPanel.add(raceNamePrefixTextBox); addRacesBtn.addStyleName("inlineButton"); + addRacesBtn.addClickHandler(new ClickHandler() { @Override public void onClick(ClickEvent event) { SeriesDTO selectedSeries = getSelectedSeries(); if(selectedSeries != null) { - String racePrefix = raceNamePrefixTextBox.getText(); - int racesCountToCreate = addRacesListBox.getSelectedIndex()+1; - int currentSize = context.getValue().size(); - for(int i = 1; i <= racesCountToCreate; i++) { - String raceName = racePrefix; - if(racesCountToCreate != 1 || selectedSeries.getRaceColumns().size() > 0) { - raceName += (currentSize + i); - } - addValue(raceName); + List raceNamesToAdd = resolveRaceNamesToAdd(); + for(String raceToAdd: raceNamesToAdd) { + addValue(raceToAdd); } validate(); +// updateFromToListboxesSelection(); +// updateHintLabel(); } else { Window.alert("Please select a series first."); } } }); addRacesPanel.add(addRacesBtn); - return addRacesPanel; + + vPanel.add(addRacesPanel); + + addRacesHintLabel.getElement().getStyle().setColor("gray"); + vPanel.add(addRacesHintLabel); + updateFromToListboxesSelection(); + updateHintLabel(); + + return vPanel; + } + + @Override + public void onRowAdded() { + updateFromToListboxesSelection(); + updateHintLabel(); + } + + @Override + public void onRowRemoved() { + updateFromToListboxesSelection(); + updateHintLabel(); } } } diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/SeriesWithFleetsCreateDialog.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/SeriesWithFleetsCreateDialog.java index d2a8c66d25d..8d32448630b 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/SeriesWithFleetsCreateDialog.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/SeriesWithFleetsCreateDialog.java @@ -12,12 +12,13 @@ import com.google.gwt.event.logical.shared.ValueChangeHandler; import com.google.gwt.user.client.ui.CheckBox; import com.google.gwt.user.client.ui.Grid; import com.google.gwt.user.client.ui.Label; +import com.google.gwt.user.client.ui.TabPanel; import com.google.gwt.user.client.ui.TextBox; import com.google.gwt.user.client.ui.VerticalPanel; import com.google.gwt.user.client.ui.Widget; import com.sap.sailing.domain.common.dto.FleetDTO; import com.sap.sailing.gwt.ui.client.StringMessages; -import com.sap.sailing.gwt.ui.shared.ListEditorComposite; +import com.sap.sailing.gwt.ui.client.shared.controls.listedit.ListEditorComposite; import com.sap.sailing.gwt.ui.shared.SeriesDTO; import com.sap.sse.gwt.ui.DataEntryDialog; @@ -31,6 +32,7 @@ public class SeriesWithFleetsCreateDialog extends DataEntryDialog { private TextBox nameEntryField; private CheckBox isMedalSeriesCheckbox; private CheckBox startsWithZeroScoreCheckbox; + private CheckBox hasSplitFleetContiguousScoringCheckbox; private CheckBox firstColumnIsNonDiscardableCarryForwardCheckbox; private CheckBox useSeriesResultDiscardingThresholdsCheckbox; private DiscardThresholdBoxes discardThresholdBoxes; @@ -104,6 +106,7 @@ public class SeriesWithFleetsCreateDialog extends DataEntryDialog { nameEntryField.setVisibleLength(40); isMedalSeriesCheckbox = createCheckbox(stringMessages.medalSeries()); startsWithZeroScoreCheckbox = createCheckbox(stringMessages.startsWithZeroScore()); + hasSplitFleetContiguousScoringCheckbox = createCheckbox(stringMessages.hasSplitFleetContiguousScoring()); firstColumnIsNonDiscardableCarryForwardCheckbox = createCheckbox(stringMessages.firstRaceIsNonDiscardableCarryForward()); useSeriesResultDiscardingThresholdsCheckbox = createCheckbox(stringMessages.seriesDefinesResultDiscardingRule()); useSeriesResultDiscardingThresholdsCheckbox.addValueChangeHandler(new ValueChangeHandler() { @@ -114,9 +117,8 @@ public class SeriesWithFleetsCreateDialog extends DataEntryDialog { }); discardThresholdBoxes = new DiscardThresholdBoxes(this, stringMessages); discardThresholdBoxes.getWidget().setVisible(false); - fleetListComposite = FleetListEditorComposite.createExpanded(Arrays.asList(new FleetDTO("Default", 0, null)), stringMessages, resources.removeIcon()); + fleetListComposite = new FleetListEditorComposite(Arrays.asList(new FleetDTO("Default", 0, null)), stringMessages, resources.removeIcon()); fleetListComposite.addValueChangeHandler(new ValueChangeHandler>() { - @Override public void onValueChange(ValueChangeEvent> event) { validate(); @@ -129,6 +131,7 @@ public class SeriesWithFleetsCreateDialog extends DataEntryDialog { series.setName(nameEntryField.getText()); series.setMedal(isMedalSeriesCheckbox.getValue()); series.setStartsWithZeroScore(startsWithZeroScoreCheckbox.getValue()); + series.setSplitFleetContiguousScoring(hasSplitFleetContiguousScoringCheckbox.getValue()); series.setFirstColumnIsNonDiscardableCarryForward(firstColumnIsNonDiscardableCarryForwardCheckbox.getValue()); series.setFleets(fleetListComposite.getValue()); series.setDiscardThresholds(useSeriesResultDiscardingThresholdsCheckbox.getValue() ? discardThresholdBoxes.getDiscardThresholds() : null); @@ -142,17 +145,22 @@ public class SeriesWithFleetsCreateDialog extends DataEntryDialog { if (additionalWidget != null) { panel.add(additionalWidget); } - Grid formGrid = new Grid(6, 2); + Grid formGrid = new Grid(7, 2); panel.add(formGrid); formGrid.setWidget(0, 0, new Label(stringMessages.name() + ":")); formGrid.setWidget(0, 1, nameEntryField); formGrid.setWidget(1, 1, isMedalSeriesCheckbox); formGrid.setWidget(2, 1, startsWithZeroScoreCheckbox); - formGrid.setWidget(3, 1, firstColumnIsNonDiscardableCarryForwardCheckbox); - formGrid.setWidget(4, 1, useSeriesResultDiscardingThresholdsCheckbox); - formGrid.setWidget(5, 1, discardThresholdBoxes.getWidget()); - panel.add(createHeadlineLabel(stringMessages.fleets())); - panel.add(fleetListComposite); + formGrid.setWidget(3, 1, hasSplitFleetContiguousScoringCheckbox); + formGrid.setWidget(4, 1, firstColumnIsNonDiscardableCarryForwardCheckbox); + formGrid.setWidget(5, 1, useSeriesResultDiscardingThresholdsCheckbox); + formGrid.setWidget(6, 1, discardThresholdBoxes.getWidget()); + + TabPanel tabPanel = new TabPanel(); + tabPanel.setWidth("100%"); + tabPanel.add(fleetListComposite, stringMessages.fleets()); + tabPanel.selectTab(0); + panel.add(tabPanel); return panel; } diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/SeriesWithFleetsListEditor.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/SeriesWithFleetsListEditor.java index 0dd791bbc80..ad25e181061 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/SeriesWithFleetsListEditor.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/SeriesWithFleetsListEditor.java @@ -8,26 +8,22 @@ import com.google.gwt.event.dom.client.ClickEvent; import com.google.gwt.event.dom.client.ClickHandler; import com.google.gwt.resources.client.ImageResource; import com.google.gwt.user.client.ui.Button; -import com.google.gwt.user.client.ui.Grid; +import com.google.gwt.user.client.ui.HorizontalPanel; import com.google.gwt.user.client.ui.Label; import com.google.gwt.user.client.ui.Widget; import com.sap.sailing.gwt.ui.client.StringMessages; -import com.sap.sailing.gwt.ui.shared.ListEditorComposite; +import com.sap.sailing.gwt.ui.client.shared.controls.listedit.ExpandedListEditorUi; +import com.sap.sailing.gwt.ui.client.shared.controls.listedit.ListEditorComposite; import com.sap.sailing.gwt.ui.shared.SeriesDTO; import com.sap.sse.gwt.ui.DataEntryDialog.DialogCallback; public class SeriesWithFleetsListEditor extends ListEditorComposite { - public static ListEditorComposite createExpanded(List initialValues, StringMessages stringMessages, ImageResource removeImage) { - return new SeriesWithFleetsListEditor(initialValues, new ExpandedUi(stringMessages, removeImage)); - } - - protected SeriesWithFleetsListEditor(List initialValues, ListEditorUiStrategy activeUi) { - super(initialValues, activeUi); + public SeriesWithFleetsListEditor(List initialValues, StringMessages stringMessages, ImageResource removeImage) { + super(initialValues, new ExpandedUi(stringMessages, removeImage)); } private static class ExpandedUi extends ExpandedListEditorUi { - public ExpandedUi(StringMessages stringMessages, ImageResource removeImage) { super(stringMessages, removeImage); } @@ -56,24 +52,29 @@ public class SeriesWithFleetsListEditor extends ListEditorComposite { } @Override - protected Widget createValueWidget(SeriesDTO seriesDTO) { - Grid seriesGrid = new Grid(2, 3); - seriesGrid.setCellSpacing(3); - Label seriesLabel = new Label(stringMessages.series() + ":"); + protected Widget createValueWidget(int rowIndex, SeriesDTO seriesDTO) { + HorizontalPanel hPanel = new HorizontalPanel(); + hPanel.setSpacing(5); + Label seriesLabel = new Label(stringMessages.series() + " '" + seriesDTO.getName() + "' :"); seriesLabel.setWordWrap(false); seriesLabel.getElement().getStyle().setFontWeight(FontWeight.BOLD); - seriesGrid.setWidget(0, 0, seriesLabel); - seriesGrid.setHTML(0, 1, seriesDTO.getName()); + hPanel.add(seriesLabel); + + String fleetText = seriesDTO.getFleets().size() + " "; + if (seriesDTO.getFleets() != null && seriesDTO.getFleets().size() > 0) { - seriesGrid.setHTML(1, 1, seriesDTO.getFleets().size() + " fleets: " - + seriesDTO.getFleets().toString()); + if(seriesDTO.getFleets().size() == 1) { + fleetText = "1 " + stringMessages.fleet(); + } else { + fleetText = seriesDTO.getFleets().size() + " " + stringMessages.fleets(); + } + fleetText += ": " + seriesDTO.getFleets().toString(); } else { - seriesGrid.setHTML(1, 1, seriesDTO.getFleets().size() + " No fleets defined."); + fleetText = "No fleets defined."; } - return seriesGrid; - + hPanel.add(new Label(fleetText)); + + return hPanel; } - } - } diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/SailingService.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/SailingService.java index 3a5db9509de..42fed6647b3 100755 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/SailingService.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/SailingService.java @@ -169,7 +169,8 @@ public interface SailingService extends RemoteService { List addRaceColumnsToSeries(RegattaIdentifier regattaIdentifier, String seriesName, List columnNames); void updateSeries(RegattaIdentifier regattaIdentifier, String seriesName, boolean isMedal, - int[] resultDiscardingThresholds, boolean startsWithZeroScore, boolean firstRaceIsNonDiscardableCarryForward); + int[] resultDiscardingThresholds, boolean startsWithZeroScore, + boolean firstRaceIsNonDiscardableCarryForward, boolean hasSplitFleetScore); RaceColumnInSeriesDTO addRaceColumnToSeries(RegattaIdentifier regattaIdentifier, String seriesName, String columnName); @@ -343,7 +344,7 @@ public interface SailingService extends RemoteService { QueryResult runQuery(QueryDefinition queryDefinition) throws Exception; Iterable getCompetitors(); - + DataMiningSerializationDummy pseudoMethodSoThatSomeDataMiningClassesAreAddedToTheGWTSerializationPolicy(); Iterable getCompetitorsOfLeaderboard(String leaderboardName); diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/SailingServiceAsync.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/SailingServiceAsync.java index f2ae2d7096e..6d13e49f096 100755 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/SailingServiceAsync.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/SailingServiceAsync.java @@ -368,8 +368,9 @@ public interface SailingServiceAsync { void addRaceColumnsToSeries(RegattaIdentifier regattaIdentifier, String seriesName, List columnNames, AsyncCallback> callback); - void updateSeries(RegattaIdentifier regattaIdentifier, String seriesName, boolean isMedal, int[] resultDiscardingThresholds, - boolean startsWithZeroScore, boolean firstColumnIsNonDiscardableCarryForward, AsyncCallback callback); + void updateSeries(RegattaIdentifier regattaIdentifier, String seriesName, boolean isMedal, + int[] resultDiscardingThresholds, boolean startsWithZeroScore, + boolean firstRaceIsNonDiscardableCarryForward, boolean hasSplitFleetScore, AsyncCallback callback); void removeRaceColumnsFromSeries(RegattaIdentifier regattaIdentifier, String seriesName, List columnNames, AsyncCallback callback); diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages.java index 2f7b325ae9d..9c4358c625a 100755 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages.java @@ -48,6 +48,7 @@ public interface StringMessages extends Messages { String leaderboardName(); String cancel(); String pleaseEnterAName(); + String pleaseEnterABoatClass(); String discardRacesFromHowManyStartedRacesOn(); String leaderboardWithThisNameAlreadyExists(); String discardThresholdsMustBeNumeric(); @@ -956,4 +957,5 @@ public interface StringMessages extends Messages { String groupingProvider(); String use(); String releaseNotes(); + String hasSplitFleetContiguousScoring(); } diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages.properties b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages.properties index 933bc1f0daf..129c9ef91f0 100755 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages.properties +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages.properties @@ -44,6 +44,7 @@ unlink=Unlink leaderboardName=Leaderboard Name cancel=Cancel pleaseEnterAName=Please enter a name +pleaseEnterABoatClass=Please enter a boat class discardRacesFromHowManyStartedRacesOn=Discard one more race starting with how many started races leaderboardWithThisNameAlreadyExists=Leaderboard with this name already exists discardThresholdsMustBeNumeric=Discard thresholds must be numeric @@ -944,4 +945,5 @@ statisticProvider=Statistic Provider toCalculateThe=to calculate the use=Use groupingProvider=Grouping Provider -releaseNotes=News and Release History \ No newline at end of file +releaseNotes=News and Release History +hasSplitFleetContiguousScoring=Split fleets scored contiguously \ No newline at end of file diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages_de.properties b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages_de.properties index da8ab28359f..c0956c2d475 100755 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages_de.properties +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages_de.properties @@ -44,6 +44,7 @@ unlink=Unlink leaderboardName=Name Rangliste cancel=Abbrechen pleaseEnterAName=Bitte geben Sie einen Namen ein. +pleaseEnterABoatClass=Bitte geben Sie eine Bootsklasse ein. discardRacesFromHowManyStartedRacesOn=Discard one more race starting with how many started races leaderboardWithThisNameAlreadyExists=Eine Rangliste mit diesem Namen existiert bereits. discardThresholdsMustBeNumeric=Discard thresholds must be numeric @@ -940,4 +941,5 @@ statisticProvider=Statistik-Versorger toCalculateThe=zur Berechnung von use=Verwende groupingProvider=Gruppierungs-Versorger -releaseNotes=Neuigkeiten und Änderungshistorie \ No newline at end of file +releaseNotes=Neuigkeiten und Änderungshistorie +hasSplitFleetContiguousScoring=Gruppen durchgängig bepunkten \ No newline at end of file diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/shared/controls/listedit/CollapsedListEditorUi.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/shared/controls/listedit/CollapsedListEditorUi.java new file mode 100644 index 00000000000..1308576c2af --- /dev/null +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/shared/controls/listedit/CollapsedListEditorUi.java @@ -0,0 +1,115 @@ +package com.sap.sailing.gwt.ui.client.shared.controls.listedit; + +import java.util.List; + +import com.google.gwt.event.dom.client.ClickEvent; +import com.google.gwt.event.dom.client.ClickHandler; +import com.google.gwt.user.client.ui.Button; +import com.google.gwt.user.client.ui.HorizontalPanel; +import com.google.gwt.user.client.ui.TextBox; +import com.google.gwt.user.client.ui.Widget; +import com.sap.sailing.gwt.ui.client.StringMessages; +import com.sap.sse.gwt.ui.DataEntryDialog; +import com.sap.sse.gwt.ui.DataEntryDialog.DialogCallback; + +public abstract class CollapsedListEditorUi extends ListEditorUi { + private static final int collapsedTitleMaxLength = 20; + + private final String popupDialogTitle; + private final ExpandedListEditorUi expandedUi; + private TextBox collapsedValuesBox; + private Button collapsedEditButton; + + public CollapsedListEditorUi(StringMessages stringMessages, String popupDialogTitle, + ExpandedListEditorUi expandedUi) { + super(stringMessages); + this.popupDialogTitle = popupDialogTitle; + this.expandedUi = expandedUi; + } + + protected abstract String getCollapsedValueText(List value); + + protected abstract ListEditorComposite createExpandedUi(List initialValues, + ExpandedListEditorUi ui); + + @Override + public void setContext(ListEditorComposite context) { + super.setContext(context); + } + + @Override + public Widget initWidget() { + HorizontalPanel panel = new HorizontalPanel(); + collapsedValuesBox = new TextBox(); + collapsedValuesBox.setReadOnly(true); + + collapsedEditButton = new Button(stringMessages.edit()); + collapsedEditButton.addClickHandler(new ClickHandler() { + @Override + public void onClick(ClickEvent event) { + new PopupEditDialog(context.getValue(), expandedUi, popupDialogTitle, + new DialogCallback>() { + + @Override + public void ok(List editedObject) { + context.setValue(editedObject); + } + + @Override + public void cancel() { + + } + }).show(); + } + }); + panel.add(collapsedValuesBox); + panel.add(collapsedEditButton); + return panel; + } + + @Override + public void refresh() { + String text = getCollapsedValueText(context.getValue()); + String shortText = text; + if (shortText.length() > collapsedTitleMaxLength) { + shortText = shortText.substring(0, collapsedTitleMaxLength) + "..."; + } + collapsedValuesBox.setText(shortText); + collapsedValuesBox.setTitle(text); + } + + @Override + public boolean isCollapsed() { + return true; + } + + private class PopupEditDialog extends DataEntryDialog> { + + private ListEditorComposite expandedComposite; + + public PopupEditDialog(List initialValues, ExpandedListEditorUi ui, String dialogTitle, + DataEntryDialog.DialogCallback> callback) { + super(dialogTitle, "", stringMessages.save(), stringMessages.cancel(), null, callback); + expandedComposite = createExpandedUi(initialValues, ui); + } + + @Override + protected Widget getAdditionalWidget() { + return expandedComposite; + } + + @Override + protected List getResult() { + return expandedComposite.getValue(); + } + } + + @Override + public void onRowAdded() { + } + + @Override + public void onRowRemoved() { + } +} + diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/shared/controls/listedit/ExpandedListEditorUi.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/shared/controls/listedit/ExpandedListEditorUi.java new file mode 100644 index 00000000000..f84d396b723 --- /dev/null +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/shared/controls/listedit/ExpandedListEditorUi.java @@ -0,0 +1,105 @@ +package com.sap.sailing.gwt.ui.client.shared.controls.listedit; + +import com.google.gwt.event.dom.client.ClickEvent; +import com.google.gwt.event.dom.client.ClickHandler; +import com.google.gwt.resources.client.ImageResource; +import com.google.gwt.user.client.ui.Grid; +import com.google.gwt.user.client.ui.Image; +import com.google.gwt.user.client.ui.PushButton; +import com.google.gwt.user.client.ui.ValueBoxBase; +import com.google.gwt.user.client.ui.VerticalPanel; +import com.google.gwt.user.client.ui.Widget; +import com.sap.sailing.gwt.ui.client.StringMessages; + +public abstract class ExpandedListEditorUi extends ListEditorUi { + private final ImageResource removeImage; + + private Grid expandedValuesGrid; + + public ExpandedListEditorUi(StringMessages stringMessages, ImageResource removeImage) { + super(stringMessages); + this.removeImage = removeImage; + } + + protected abstract Widget createAddWidget(); + + protected abstract Widget createValueWidget(int rowIndex, ValueType newValue); + + @Override + public Widget initWidget() { + expandedValuesGrid = new Grid(0, 2); + + VerticalPanel panel = new VerticalPanel(); + panel.add(createAddWidget()); + panel.add(expandedValuesGrid); + return panel; + } + + @Override + public void refresh() { + expandedValuesGrid.clear(); + for (ValueType value : context.getValue()) { + addRow(value); + } + } + + @Override + public boolean isCollapsed() { + return false; + } + + private void addRow(ValueType newValue) { + int rowIndex = expandedValuesGrid.insertRow(expandedValuesGrid.getRowCount()); + + PushButton removeButton = new PushButton(new Image(removeImage)); + removeButton.setTitle(stringMessages.remove()); + removeButton.addClickHandler(new ClickHandler() { + + @Override + public void onClick(ClickEvent event) { + int rowToRemove = expandedValuesGrid.getCellForEvent(event).getRowIndex(); + removeRow(rowToRemove); + } + }); + + expandedValuesGrid.setWidget(rowIndex, 0, createValueWidget(rowIndex, newValue)); + expandedValuesGrid.setWidget(rowIndex, 1, removeButton); + } + + private void removeRow(int rowIndexToRemove) { + expandedValuesGrid.removeRow(rowIndexToRemove); + context.getValue().remove(rowIndexToRemove); + context.onChange(); + + onRowRemoved(); + } + + protected void setValueFromValueWidget(ValueBoxBase valueWidget, ValueType newValue, boolean fireEvents) { + for(int i = 0; i < expandedValuesGrid.getRowCount(); i++) { + Widget gridWidget = expandedValuesGrid.getWidget(i, 0); + if(gridWidget.getElement() == valueWidget.getElement()) { + context.getValue().set(i, newValue); + if (fireEvents) { + context.onChange(); + } + break; + } + } + } + + protected void addValue(ValueType newValue) { + context.getValue().add(newValue); + addRow(newValue); + context.onChange(); + + onRowAdded(); + } + + @Override + public void onRowAdded() { + } + + @Override + public void onRowRemoved() { + } +} diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/shared/controls/listedit/ListEditorComposite.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/shared/controls/listedit/ListEditorComposite.java new file mode 100644 index 00000000000..541b83d151f --- /dev/null +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/shared/controls/listedit/ListEditorComposite.java @@ -0,0 +1,61 @@ +package com.sap.sailing.gwt.ui.client.shared.controls.listedit; + +import java.util.ArrayList; +import java.util.List; + +import com.google.gwt.event.logical.shared.HasValueChangeHandlers; +import com.google.gwt.event.logical.shared.ValueChangeEvent; +import com.google.gwt.event.logical.shared.ValueChangeHandler; +import com.google.gwt.event.shared.HandlerRegistration; +import com.google.gwt.user.client.ui.Composite; +import com.google.gwt.user.client.ui.HasValue; + +public class ListEditorComposite extends Composite implements HasValue>, + HasValueChangeHandlers> { + + private final ListEditorUiStrategy activeUi; + + private List values; + + protected ListEditorComposite(List initialValues, ListEditorUiStrategy activeUi) { + this.values = new ArrayList(initialValues); + this.activeUi = activeUi; + this.activeUi.setContext(this); + + initWidget(activeUi.initWidget()); + activeUi.refresh(); + } + + @Override + public List getValue() { + return values; + } + + @Override + public void setValue(List newValues) { + setValue(newValues, true); + } + + @Override + public void setValue(List newValues, boolean fireEvents) { + this.values = newValues; + activeUi.refresh(); + if (fireEvents) { + onChange(); + } + } + + @Override + public HandlerRegistration addValueChangeHandler(ValueChangeHandler> handler) { + return addHandler(handler, ValueChangeEvent.getType()); + } + + public void onChange() { + ValueChangeEvent.fire(this, getValue()); + } + + public boolean isCollapsed() { + return activeUi.isCollapsed(); + } + +} diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/shared/controls/listedit/ListEditorUi.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/shared/controls/listedit/ListEditorUi.java new file mode 100644 index 00000000000..f8caab779de --- /dev/null +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/shared/controls/listedit/ListEditorUi.java @@ -0,0 +1,17 @@ +package com.sap.sailing.gwt.ui.client.shared.controls.listedit; + +import com.sap.sailing.gwt.ui.client.StringMessages; + +public abstract class ListEditorUi implements ListEditorUiStrategy { + protected final StringMessages stringMessages; + protected ListEditorComposite context; + + public ListEditorUi(StringMessages stringMessages) { + this.stringMessages = stringMessages; + } + + @Override + public void setContext(ListEditorComposite context) { + this.context = context; + } +} diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/shared/controls/listedit/ListEditorUiStrategy.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/shared/controls/listedit/ListEditorUiStrategy.java new file mode 100644 index 00000000000..c16ccf902bb --- /dev/null +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/shared/controls/listedit/ListEditorUiStrategy.java @@ -0,0 +1,16 @@ +package com.sap.sailing.gwt.ui.client.shared.controls.listedit; + +import com.google.gwt.user.client.ui.Widget; + +public interface ListEditorUiStrategy { + Widget initWidget(); + + void refresh(); + + void setContext(ListEditorComposite context); + + boolean isCollapsed(); + + void onRowAdded(); + void onRowRemoved(); +} \ No newline at end of file diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/StringListEditorComposite.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/shared/controls/listedit/StringListEditorComposite.java similarity index 86% rename from java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/StringListEditorComposite.java rename to java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/shared/controls/listedit/StringListEditorComposite.java index fe408cb4cb2..815794caa68 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/StringListEditorComposite.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/shared/controls/listedit/StringListEditorComposite.java @@ -1,4 +1,4 @@ -package com.sap.sailing.gwt.ui.shared; +package com.sap.sailing.gwt.ui.client.shared.controls.listedit; import java.util.List; @@ -16,16 +16,19 @@ import com.google.gwt.user.client.ui.Widget; import com.sap.sailing.gwt.ui.client.StringMessages; public class StringListEditorComposite extends ListEditorComposite { - - public static ListEditorComposite createCollapsed(List initialValues, StringMessages stringMessages, + public StringListEditorComposite(List initialValues, StringMessages stringMessages, String popupDialogTitle, ImageResource removeImage, List suggestValues) { - return new StringListEditorComposite(initialValues, new CollapsedUi(stringMessages, popupDialogTitle, + super(initialValues, new CollapsedUi(stringMessages, popupDialogTitle, new ExpandedUi(stringMessages, removeImage, suggestValues))); } - public static ListEditorComposite createExpanded(List initialValues, StringMessages stringMessages, + public StringListEditorComposite(List initialValues, StringMessages stringMessages, ImageResource removeImage, List suggestValues) { - return new StringListEditorComposite(initialValues, new ExpandedUi(stringMessages, removeImage, suggestValues)); + super(initialValues, new ExpandedUi(stringMessages, removeImage, suggestValues)); + } + + public StringListEditorComposite(List initialValues, ListEditorUiStrategy activeUi) { + super(initialValues, activeUi); } public static class CollapsedUi extends CollapsedListEditorUi { @@ -51,7 +54,6 @@ public class StringListEditorComposite extends ListEditorComposite { protected ListEditorComposite createExpandedUi(List initialValues, ExpandedListEditorUi ui) { return new StringListEditorComposite(initialValues, ui); } - } public static class ExpandedUi extends ExpandedListEditorUi { @@ -99,14 +101,8 @@ public class StringListEditorComposite extends ListEditorComposite { } @Override - protected Widget createValueWidget(String newValue) { + protected Widget createValueWidget(int rowIndex, String newValue) { return new Label(newValue); } - } - - public StringListEditorComposite(List initialValues, ListEditorUiStrategy activeUi) { - super(initialValues, activeUi); - } - } diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/shared/controls/listedit/StringListInlineEditorComposite.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/shared/controls/listedit/StringListInlineEditorComposite.java new file mode 100644 index 00000000000..662ad8f324e --- /dev/null +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/shared/controls/listedit/StringListInlineEditorComposite.java @@ -0,0 +1,129 @@ +package com.sap.sailing.gwt.ui.client.shared.controls.listedit; + +import java.util.List; + +import com.google.gwt.event.dom.client.ClickEvent; +import com.google.gwt.event.dom.client.ClickHandler; +import com.google.gwt.event.dom.client.KeyUpEvent; +import com.google.gwt.event.dom.client.KeyUpHandler; +import com.google.gwt.event.logical.shared.ValueChangeEvent; +import com.google.gwt.event.logical.shared.ValueChangeHandler; +import com.google.gwt.resources.client.ImageResource; +import com.google.gwt.user.client.ui.Button; +import com.google.gwt.user.client.ui.HorizontalPanel; +import com.google.gwt.user.client.ui.MultiWordSuggestOracle; +import com.google.gwt.user.client.ui.SuggestBox; +import com.google.gwt.user.client.ui.TextBox; +import com.google.gwt.user.client.ui.Widget; +import com.sap.sailing.gwt.ui.client.StringMessages; + +public class StringListInlineEditorComposite extends StringListEditorComposite { + public StringListInlineEditorComposite(List initialValues, StringMessages stringMessages, + String popupDialogTitle, ImageResource removeImage, List suggestValues) { + super(initialValues, new CollapsedUi(stringMessages, popupDialogTitle, + new ExpandedUi(stringMessages, removeImage, suggestValues))); + } + + public StringListInlineEditorComposite(List initialValues, StringMessages stringMessages, + ImageResource removeImage, List suggestValues) { + super(initialValues, new ExpandedUi(stringMessages, removeImage, suggestValues)); + } + + public StringListInlineEditorComposite(List initialValues, ListEditorUiStrategy activeUi) { + super(initialValues, activeUi); + } + + public static class CollapsedUi extends CollapsedListEditorUi { + + public CollapsedUi(StringMessages stringMessages, String dialogTitle, ExpandedListEditorUi expandedUi) { + super(stringMessages, dialogTitle, expandedUi); + } + + @Override + protected String getCollapsedValueText(List value) { + StringBuilder valuesText = new StringBuilder(); + for (int i = 0; i < value.size(); i++) { + if (i > 0) { + valuesText.append(','); + } + valuesText.append(value.get(i)); + } + String condensedValue = valuesText.toString(); + return condensedValue; + } + + @Override + protected ListEditorComposite createExpandedUi(List initialValues, ExpandedListEditorUi ui) { + return new StringListInlineEditorComposite(initialValues, ui); + } + } + + public static class ExpandedUi extends ExpandedListEditorUi { + + protected final MultiWordSuggestOracle inputOracle; + + public ExpandedUi(StringMessages stringMessages, ImageResource removeImage, List suggestValues) { + super(stringMessages, removeImage); + this.inputOracle = new MultiWordSuggestOracle(); + + inputOracle.addAll(suggestValues); + } + + @Override + public void setContext(ListEditorComposite context) { + super.setContext(context); + inputOracle.addAll(context.getValue()); + } + + @Override + protected Widget createAddWidget() { + final SuggestBox inputBox = new SuggestBox(inputOracle); + final Button addButton = new Button(stringMessages.add()); + addButton.setEnabled(false); + addButton.addClickHandler(new ClickHandler() { + + @Override + public void onClick(ClickEvent event) { + addValue(inputBox.getValue()); + inputBox.setText(""); + } + }); + inputBox.addKeyUpHandler(new KeyUpHandler() { + + @Override + public void onKeyUp(KeyUpEvent event) { + addButton.setEnabled(!inputBox.getValue().isEmpty()); + } + }); + + HorizontalPanel panel = new HorizontalPanel(); + panel.add(inputBox); + panel.add(addButton); + return panel; + } + + @Override + protected Widget createValueWidget(final int rowIndex, String newValue) { + final TextBox textBox = new TextBox(); + textBox.setValue(newValue); + + textBox.addKeyUpHandler(new KeyUpHandler() { + @Override + public void onKeyUp(KeyUpEvent event) { + textBox.setFocus(false); + // this ensures that the value is copied into the TextBox.getValue() result and a ChangeEvent is fired + textBox.setFocus(true); + } + }); + + textBox.addValueChangeHandler(new ValueChangeHandler() { + @Override + public void onValueChange(ValueChangeEvent event) { + String newValue = event.getValue(); + setValueFromValueWidget(textBox, newValue, true); + } + }); + return textBox; + } + } +} diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/shared/racemap/BoatClassImageDataResolver.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/shared/racemap/BoatClassImageDataResolver.java deleted file mode 100644 index 60ff9715357..00000000000 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/shared/racemap/BoatClassImageDataResolver.java +++ /dev/null @@ -1,71 +0,0 @@ -package com.sap.sailing.gwt.ui.client.shared.racemap; - -import java.util.HashMap; -import java.util.Map; - -import com.google.gwt.core.client.GWT; - -/** - * A resolver utility for finding a boat image for a given boat class - * @author C5163874 - */ -public class BoatClassImageDataResolver { - private static Map boatImagesMap; - private static Map compatibleBoatImagesMap; - private static BoatClassImageData defaultBoatImages; - - private static BoatImageResources boatImageResources = GWT.create(BoatImageResources.class); - - static { - boatImagesMap = new HashMap(); - compatibleBoatImagesMap = new HashMap(); - - BoatClassImageData _470er = new BoatClassImageData("470er", 4.70, 44, 72, 42, "470"); - _470er.setDownWindPortIcons(boatImageResources.class470er_DownWindPortIcon(), boatImageResources.class470er_DownWindPortIconSelected()); - _470er.setDownWindStarboardIcons(boatImageResources.class470er_DownWindStarboardIcon(), boatImageResources.class470er_DownWindStarboardIconSelected()); - _470er.setUpWindPortIcons(boatImageResources.class470er_UpWindPortIcon(), boatImageResources.class470er_UpWindPortIconSelected()); - _470er.setUpWindStarboardIcons(boatImageResources.class470er_UpWindStarboardIcon(), boatImageResources.class470er_UpWindStarboardIconSelected()); - _470er.setReachingPortIcons(boatImageResources.class470er_ReachingPortIcon(), boatImageResources.class470er_ReachingPortIconSelected()); - _470er.setReachingStarboardIcons(boatImageResources.class470er_ReachingStarboardIcon(), boatImageResources.class470er_ReachingStarboardIconSelected()); - - BoatClassImageData _49er = new BoatClassImageData("49er", 4.90, 42, 67, 31, "49erFX", "49FX"); - _49er.setDownWindPortIcons(boatImageResources.class49er_DownWindPortIcon(), boatImageResources.class49er_DownWindPortIconSelected()); - _49er.setDownWindStarboardIcons(boatImageResources.class49er_DownWindStarboardIcon(), boatImageResources.class49er_DownWindStarboardIconSelected()); - _49er.setUpWindPortIcons(boatImageResources.class49er_UpWindPortIcon(), boatImageResources.class49er_UpWindPortIconSelected()); - _49er.setUpWindStarboardIcons(boatImageResources.class49er_UpWindStarboardIcon(), boatImageResources.class49er_UpWindStarboardIconSelected()); - _49er.setReachingPortIcons(boatImageResources.class49er_ReachingPortIcon(), boatImageResources.class49er_ReachingPortIconSelected()); - _49er.setReachingStarboardIcons(boatImageResources.class49er_ReachingStarboardIcon(), boatImageResources.class49er_ReachingStarboardIconSelected()); - - BoatClassImageData extreme40 = new BoatClassImageData("Extreme40", 12.2, 120, 153, 97); - extreme40.setDownWindPortIcons(boatImageResources.Extreme40_DownWindPortIcon(), boatImageResources.Extreme40_DownWindPortIconSelected()); - extreme40.setDownWindStarboardIcons(boatImageResources.Extreme40_DownWindStarboardIcon(), boatImageResources.Extreme40_DownWindStarboardIconSelected()); - extreme40.setUpWindPortIcons(boatImageResources.Extreme40_UpWindPortIcon(), boatImageResources.Extreme40_UpWindPortIconSelected()); - extreme40.setUpWindStarboardIcons(boatImageResources.Extreme40_UpWindStarboardIcon(), boatImageResources.Extreme40_UpWindStarboardIconSelected()); - extreme40.setReachingPortIcons(boatImageResources.Extreme40_ReachingPortIcon(), boatImageResources.Extreme40_ReachingPortIconSelected()); - extreme40.setReachingStarboardIcons(boatImageResources.Extreme40_ReachingStarboardIcon(), boatImageResources.Extreme40_ReachingStarboardIconSelected()); - - defaultBoatImages = _470er; - boatImagesMap.put(_470er.getMainBoatClassName(), _470er); - boatImagesMap.put(_49er.getMainBoatClassName(), _49er); - boatImagesMap.put(extreme40.getMainBoatClassName(), extreme40); - } - - public static BoatClassImageData resolveBoatClassImages(String boatClassName) { - BoatClassImageData result = defaultBoatImages; - if(boatImagesMap.containsKey(boatClassName)) { - result = boatImagesMap.get(boatClassName); - } else if (compatibleBoatImagesMap.containsKey(boatClassName)) { - result = compatibleBoatImagesMap.get(boatClassName); - } else { - // now try to find compatible boat class images - for(BoatClassImageData boatClassImageData: boatImagesMap.values()) { - if(boatClassImageData.isBoatClassNameCompatible(boatClassName)) { - result = boatClassImageData; - compatibleBoatImagesMap.put(boatClassName, boatClassImageData); - break; - } - } - } - return result; - } -} diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/shared/racemap/BoatImageResources.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/shared/racemap/BoatImageResources.java deleted file mode 100644 index 411b39ac029..00000000000 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/shared/racemap/BoatImageResources.java +++ /dev/null @@ -1,120 +0,0 @@ -package com.sap.sailing.gwt.ui.client.shared.racemap; - -import com.google.gwt.resources.client.ClientBundle; -import com.google.gwt.resources.client.ImageResource; - -public interface BoatImageResources extends ClientBundle { - // 49er boats - @Source("com/sap/sailing/gwt/ui/client/images/boats/class_49er/49er_DW_Port.png") - ImageResource class49er_DownWindPortIcon(); - - @Source("com/sap/sailing/gwt/ui/client/images/boats/class_49er/49er_DW_Port_Selected.png") - ImageResource class49er_DownWindPortIconSelected(); - - @Source("com/sap/sailing/gwt/ui/client/images/boats/class_49er/49er_UW_Port.png") - ImageResource class49er_UpWindPortIcon(); - - @Source("com/sap/sailing/gwt/ui/client/images/boats/class_49er/49er_UW_Port_Selected.png") - ImageResource class49er_UpWindPortIconSelected(); - - @Source("com/sap/sailing/gwt/ui/client/images/boats/class_49er/49er_DW_Starboard.png") - ImageResource class49er_DownWindStarboardIcon(); - - @Source("com/sap/sailing/gwt/ui/client/images/boats/class_49er/49er_DW_Starboard_Selected.png") - ImageResource class49er_DownWindStarboardIconSelected(); - - @Source("com/sap/sailing/gwt/ui/client/images/boats/class_49er/49er_UW_Starboard.png") - ImageResource class49er_UpWindStarboardIcon(); - - @Source("com/sap/sailing/gwt/ui/client/images/boats/class_49er/49er_UW_Starboard_Selected.png") - ImageResource class49er_UpWindStarboardIconSelected(); - - @Source("com/sap/sailing/gwt/ui/client/images/boats/class_49er/49er_Reach_Port.png") - ImageResource class49er_ReachingPortIcon(); - - @Source("com/sap/sailing/gwt/ui/client/images/boats/class_49er/49er_Reach_Port_Selected.png") - ImageResource class49er_ReachingPortIconSelected(); - - @Source("com/sap/sailing/gwt/ui/client/images/boats/class_49er/49er_Reach_Starboard.png") - ImageResource class49er_ReachingStarboardIcon(); - - @Source("com/sap/sailing/gwt/ui/client/images/boats/class_49er/49er_Reach_Starboard_Selected.png") - ImageResource class49er_ReachingStarboardIconSelected(); - - - // 470er boats - @Source("com/sap/sailing/gwt/ui/client/images/boats/class_470er/470er_DW_Port.png") - ImageResource class470er_DownWindPortIcon(); - - @Source("com/sap/sailing/gwt/ui/client/images/boats/class_470er/470er_DW_Port_Selected.png") - ImageResource class470er_DownWindPortIconSelected(); - - @Source("com/sap/sailing/gwt/ui/client/images/boats/class_470er/470er_UW_Port.png") - ImageResource class470er_UpWindPortIcon(); - - @Source("com/sap/sailing/gwt/ui/client/images/boats/class_470er/470er_UW_Port_Selected.png") - ImageResource class470er_UpWindPortIconSelected(); - - @Source("com/sap/sailing/gwt/ui/client/images/boats/class_470er/470er_DW_Starboard.png") - ImageResource class470er_DownWindStarboardIcon(); - - @Source("com/sap/sailing/gwt/ui/client/images/boats/class_470er/470er_DW_Starboard_Selected.png") - ImageResource class470er_DownWindStarboardIconSelected(); - - @Source("com/sap/sailing/gwt/ui/client/images/boats/class_470er/470er_UW_Starboard.png") - ImageResource class470er_UpWindStarboardIcon(); - - @Source("com/sap/sailing/gwt/ui/client/images/boats/class_470er/470er_UW_Starboard_Selected.png") - ImageResource class470er_UpWindStarboardIconSelected(); - - @Source("com/sap/sailing/gwt/ui/client/images/boats/class_470er/470er_Reach_Port.png") - ImageResource class470er_ReachingPortIcon(); - - @Source("com/sap/sailing/gwt/ui/client/images/boats/class_470er/470er_Reach_Port_Selected.png") - ImageResource class470er_ReachingPortIconSelected(); - - @Source("com/sap/sailing/gwt/ui/client/images/boats/class_470er/470er_Reach_Starboard.png") - ImageResource class470er_ReachingStarboardIcon(); - - @Source("com/sap/sailing/gwt/ui/client/images/boats/class_470er/470er_Reach_Starboard_Selected.png") - ImageResource class470er_ReachingStarboardIconSelected(); - - - // Extreme 40 boats - @Source("com/sap/sailing/gwt/ui/client/images/boats/class_extreme40/Extreme40_DW_Port.png") - ImageResource Extreme40_DownWindPortIcon(); - - @Source("com/sap/sailing/gwt/ui/client/images/boats/class_extreme40/Extreme40_DW_Port_Selected.png") - ImageResource Extreme40_DownWindPortIconSelected(); - - @Source("com/sap/sailing/gwt/ui/client/images/boats/class_extreme40/Extreme40_UW_Port.png") - ImageResource Extreme40_UpWindPortIcon(); - - @Source("com/sap/sailing/gwt/ui/client/images/boats/class_extreme40/Extreme40_UW_Port_Selected.png") - ImageResource Extreme40_UpWindPortIconSelected(); - - @Source("com/sap/sailing/gwt/ui/client/images/boats/class_extreme40/Extreme40_DW_Starboard.png") - ImageResource Extreme40_DownWindStarboardIcon(); - - @Source("com/sap/sailing/gwt/ui/client/images/boats/class_extreme40/Extreme40_DW_Starboard_Selected.png") - ImageResource Extreme40_DownWindStarboardIconSelected(); - - @Source("com/sap/sailing/gwt/ui/client/images/boats/class_extreme40/Extreme40_UW_Starboard.png") - ImageResource Extreme40_UpWindStarboardIcon(); - - @Source("com/sap/sailing/gwt/ui/client/images/boats/class_extreme40/Extreme40_UW_Starboard_Selected.png") - ImageResource Extreme40_UpWindStarboardIconSelected(); - - @Source("com/sap/sailing/gwt/ui/client/images/boats/class_extreme40/Extreme40_Reach_Port.png") - ImageResource Extreme40_ReachingPortIcon(); - - @Source("com/sap/sailing/gwt/ui/client/images/boats/class_extreme40/Extreme40_Reach_Port_Selected.png") - ImageResource Extreme40_ReachingPortIconSelected(); - - @Source("com/sap/sailing/gwt/ui/client/images/boats/class_extreme40/Extreme40_Reach_Starboard.png") - ImageResource Extreme40_ReachingStarboardIcon(); - - @Source("com/sap/sailing/gwt/ui/client/images/boats/class_extreme40/Extreme40_Reach_Starboard_Selected.png") - ImageResource Extreme40_ReachingStarboardIconSelected(); - -} diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/shared/racemap/BoatOverlay.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/shared/racemap/BoatOverlay.java index 9141335f381..27a711c0aa6 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/shared/racemap/BoatOverlay.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/shared/racemap/BoatOverlay.java @@ -96,20 +96,25 @@ public class BoatOverlay extends CanvasOverlayV3 { } public Pair getBoatScaleAndSize(BoatClassDTO boatClass) { - double minBoatLength = 25; + // the minimum boat length is related to the hull of the boat, not the overall length + double minBoatHullLengthInPx = 25; - Size boatSizeInPixel = calculateBoundingBox(mapProjection, + Size boatSizeHullInPixel = calculateBoundingBox(mapProjection, LatLng.newInstance(boatFix.position.latDeg, boatFix.position.lngDeg), - boatVectorGraphics.getBoatLengthInMeters(), boatVectorGraphics.getBoatBeamInMeters()); + boatVectorGraphics.getBoatHullLengthInMeters(), boatVectorGraphics.getBoatBeamInMeters()); - double boatLengthInPixel = boatSizeInPixel.getWidth(); - if(boatLengthInPixel < minBoatLength) - boatLengthInPixel = minBoatLength; + double boatHullLengthInPixel = boatSizeHullInPixel.getWidth(); + if(boatHullLengthInPixel < minBoatHullLengthInPx) { + boatHullLengthInPixel = minBoatHullLengthInPx; + } // The coordinates of the canvas drawing methods are based on the 'centimeter' unit (1px = 1cm). // To calculate the display real boat size the scale factor from canvas units to the real - double boatSizeScaleFactor = boatLengthInPixel / (boatVectorGraphics.getBoatLengthInMeters() * 100); + double boatSizeScaleFactor = boatHullLengthInPixel / (boatVectorGraphics.getBoatHullLengthInMeters() * 100); - return new Pair(boatSizeScaleFactor, Size.newInstance(boatLengthInPixel + boatLengthInPixel / 2.0, boatLengthInPixel + boatLengthInPixel / 2.0)); + // as the canvas contains the whole boat the canvas size relates to the overall length, not the hull length + double scaledCanvasSize = (boatVectorGraphics.getBoatOverallLengthInMeters() * 100) * boatSizeScaleFactor; + + return new Pair(boatSizeScaleFactor, Size.newInstance(scaledCanvasSize + scaledCanvasSize / 2.0, scaledCanvasSize + scaledCanvasSize / 2.0)); } } diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/shared/racemap/CompetitorInfoOverlay.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/shared/racemap/CompetitorInfoOverlay.java index c0234dca5b7..8a9cb8a73fa 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/shared/racemap/CompetitorInfoOverlay.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/shared/racemap/CompetitorInfoOverlay.java @@ -41,6 +41,7 @@ public class CompetitorInfoOverlay extends CanvasOverlayV3 { canvasHeight = 100; setCanvasSize(canvasWidth, canvasHeight); + canvas.addStyleName("competitorInfo-Canvas"); } @Override diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/shared/racemap/CourseMarkOverlay.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/shared/racemap/CourseMarkOverlay.java index 4f46cdefc9c..b45db1899a1 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/shared/racemap/CourseMarkOverlay.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/shared/racemap/CourseMarkOverlay.java @@ -108,11 +108,15 @@ public class CourseMarkOverlay extends CanvasOverlayV3 { } public Pair getMarkScaleAndSize(PositionDTO markPosition) { - double minMarkHeight = 25; + double minMarkHeight = 20; + + // the original buoy vector graphics is too small (2.1m x 1.5m) for higher zoom levels + // therefore we scale the buoys with factor 2 by default + double buoyScaleFactor = 2.0; Size markSizeInPixel = calculateBoundingBox(mapProjection, LatLng.newInstance(markPosition.latDeg, markPosition.lngDeg), - markVectorGraphics.getMarkWidthInMeters(), markVectorGraphics.getMarkHeightInMeters()); + markVectorGraphics.getMarkWidthInMeters() * buoyScaleFactor, markVectorGraphics.getMarkHeightInMeters() * buoyScaleFactor); double markHeightInPixel = markSizeInPixel.getHeight(); if(markHeightInPixel < minMarkHeight) diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/shared/racemap/FixesAndTails.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/shared/racemap/FixesAndTails.java index 09187c1990e..e9b74b5f531 100755 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/shared/racemap/FixesAndTails.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/shared/racemap/FixesAndTails.java @@ -220,6 +220,11 @@ public class FixesAndTails { * competitor's tail, the tail is adjusted by inserting the corresponding fix. *

* + * If the last fix so far was an {@link GPSFixDTO#extrapolated extrapolated} fix, and the merge leads to a different + * fix being the last one shown, the previously last fix that was extrapolated will be removed. This way, at most + * one extrapolated fix is shown, avoiding jitter on the map as actual fixes are received that obsolete the + * extrapolated ones.

+ * * Precondition: {@link #hasFixesFor(CompetitorDTO) hasFixesFor(competitorDTO)}==true * * @param mergeThis diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/shared/racemap/RaceMap.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/shared/racemap/RaceMap.java index 329acd1ff66..d3ec01bb064 100755 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/shared/racemap/RaceMap.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/shared/racemap/RaceMap.java @@ -425,7 +425,7 @@ public class RaceMap extends AbsolutePanel implements TimeListener, CompetitorSe final int requestID = ++boatPositionRequestIDCounter; GetRaceMapDataAction getRaceMapDataAction = new GetRaceMapDataAction(sailingService, competitorSelection.getAllCompetitors(), race, - date, fromAndToAndOverlap.getA(), fromAndToAndOverlap.getB(), true, new AsyncCallback() { + date, fromAndToAndOverlap.getA(), fromAndToAndOverlap.getB(), /* extrapolate */ true, new AsyncCallback() { @Override public void onFailure(Throwable caught) { errorReporter.reportError("Error obtaining racemap data: " + caught.getMessage(), true /*silentMode */); diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/shared/racemap/RaceMapImageManager.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/shared/racemap/RaceMapImageManager.java index 61a9bbf358c..f089f106132 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/shared/racemap/RaceMapImageManager.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/shared/racemap/RaceMapImageManager.java @@ -1,8 +1,6 @@ package com.sap.sailing.gwt.ui.client.shared.racemap; -import java.util.ArrayList; import java.util.HashMap; -import java.util.List; import java.util.Map; import com.google.gwt.core.client.GWT; @@ -11,9 +9,7 @@ import com.google.gwt.maps.client.base.Point; import com.google.gwt.maps.client.overlays.Marker; import com.google.gwt.maps.client.overlays.MarkerImage; import com.google.gwt.maps.client.overlays.MarkerOptions; -import com.google.gwt.resources.client.ImageResource; import com.sap.sailing.domain.common.ManeuverType; -import com.sap.sailing.domain.common.MarkType; import com.sap.sailing.domain.common.Tack; import com.sap.sailing.domain.common.impl.Util.Pair; @@ -29,69 +25,23 @@ public class RaceMapImageManager { */ protected ImageTransformer windSensorIconTransformer; - /** - * The default image for a course mark - */ - private MarkImageDescriptor defaultCourseMarkDescriptor; - - private final List markImageDescriptors; - protected Map, Marker> maneuverIconsForTypeAndTargetTack; private static RaceMapResources resources = GWT.create(RaceMapResources.class); public RaceMapImageManager() { - markImageDescriptors = new ArrayList(); - maneuverIconsForTypeAndTargetTack = new HashMap, Marker>(); combinedWindIconTransformer = new ImageTransformer(resources.combinedWindIcon()); windSensorIconTransformer = new ImageTransformer(resources.expeditionWindIcon()); } - public MarkImageDescriptor resolveMarkImage(MarkType type, String color, String shape, String pattern) { - MarkImageDescriptor result = defaultCourseMarkDescriptor; - int highestCompatibilityLevel = -1; - - for (MarkImageDescriptor imageDescriptor: markImageDescriptors) { - int compatibilityLevel = imageDescriptor.getCompatibilityLevel(type, color, shape, pattern); - if(compatibilityLevel > highestCompatibilityLevel) { - result = imageDescriptor; - highestCompatibilityLevel = compatibilityLevel; - if(highestCompatibilityLevel == 3) { - break; - } - } - } - - return result; - } - /** * Loads the map overlay icons * The method can only be called after the map is loaded */ public void loadMapIcons(MapWidget map) { if(map != null) { - defaultCourseMarkDescriptor = createMarkImageDescriptor(resources.buoyIcon(), MarkType.BUOY, "undefined", null, null, 6, 20); - - createMarkImageDescriptor(resources.buoyRedIcon(), MarkType.BUOY, "red", null, null, 6, 20); - createMarkImageDescriptor(resources.buoyGreenIcon(), MarkType.BUOY, "green", null, null, 6, 20); - createMarkImageDescriptor(resources.buoyYellowIcon(), MarkType.BUOY, "yellow", null, null, 6, 20); - createMarkImageDescriptor(resources.buoyGreyIcon(), MarkType.BUOY, "grey", null, null, 6, 20); - createMarkImageDescriptor(resources.buoyWhiteIcon(), MarkType.BUOY, "white", null, null, 6, 20); - createMarkImageDescriptor(resources.buoyWhiteConeIcon(), MarkType.BUOY, "white", "conical", null, 6, 20); - createMarkImageDescriptor(resources.buoyBlackIcon(), MarkType.BUOY, "black", null, null, 6, 20); - createMarkImageDescriptor(resources.buoyBlackConeIcon(), MarkType.BUOY, "black", "conical", null, 6, 20); - createMarkImageDescriptor(resources.buoyDarkOrangeIcon(), MarkType.BUOY, "orange", null, null, 6, 20); - createMarkImageDescriptor(resources.buoyBlackFinishIcon(), MarkType.BUOY, "black", "cylinder", "checkered", 6, 20); - - createMarkImageDescriptor(resources.cameraBoatIcon(), MarkType.CAMERABOAT, null, null, null, 35, 20); - createMarkImageDescriptor(resources.umpireBoatIcon(), MarkType.UMPIREBOAT, null, null, null, 35, 20); - createMarkImageDescriptor(resources.startBoatIcon(), MarkType.STARTBOAT, null, null, null, 35, 20); - - createMarkImageDescriptor(resources.landmarkIcon(), MarkType.LANDMARK, null, null, null, 6, 15); - Marker tackToStarboardIcon = createMarker("http://chart.apis.google.com/chart?chst=d_map_pin_letter&chld=T|00FF00|000000", 10, 33); maneuverIconsForTypeAndTargetTack.put(new Pair(ManeuverType.TACK, Tack.STARBOARD), tackToStarboardIcon); @@ -143,15 +93,6 @@ public class RaceMapImageManager { return marker; } - private MarkImageDescriptor createMarkImageDescriptor(ImageResource imgResource, MarkType type, String color, String shape, String pattern, - int anchorPointX, int anchorPointY) { - MarkImageDescriptor markIconDescriptor = new MarkImageDescriptor(imgResource, Point.newInstance(anchorPointX, anchorPointY), - type, color, shape, pattern); - markImageDescriptors.add(markIconDescriptor); - - return markIconDescriptor; - } - public ImageTransformer getCombinedWindIconTransformer() { return combinedWindIconTransformer; } diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/shared/racemap/RaceMapResources.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/shared/racemap/RaceMapResources.java index 7f27bb1f2d2..4044c5ad0cf 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/shared/racemap/RaceMapResources.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/shared/racemap/RaceMapResources.java @@ -4,43 +4,6 @@ import com.google.gwt.resources.client.ClientBundle; import com.google.gwt.resources.client.ImageResource; interface RaceMapResources extends ClientBundle { - - @Source("com/sap/sailing/gwt/ui/client/images/buoys/buoy.png") - ImageResource buoyIcon(); - - @Source("com/sap/sailing/gwt/ui/client/images/buoys/buoy_black_cone.png") - ImageResource buoyBlackConeIcon(); - - @Source("com/sap/sailing/gwt/ui/client/images/buoys/buoy_black_finish.png") - ImageResource buoyBlackFinishIcon(); - - @Source("com/sap/sailing/gwt/ui/client/images/buoys/buoy_black.png") - ImageResource buoyBlackIcon(); - - @Source("com/sap/sailing/gwt/ui/client/images/buoys/buoy_dark_orange.png") - ImageResource buoyDarkOrangeIcon(); - - @Source("com/sap/sailing/gwt/ui/client/images/buoys/buoy_grey.png") - ImageResource buoyGreyIcon(); - - @Source("com/sap/sailing/gwt/ui/client/images/buoys/buoy_white_grey.png") - ImageResource buoyWhiteIcon(); - - @Source("com/sap/sailing/gwt/ui/client/images/buoys/buoy_white_grey_cone.png") - ImageResource buoyWhiteConeIcon(); - - @Source("com/sap/sailing/gwt/ui/client/images/buoys/buoy_red.png") - ImageResource buoyRedIcon(); - - @Source("com/sap/sailing/gwt/ui/client/images/buoys/buoy_yellow.png") - ImageResource buoyYellowIcon(); - - @Source("com/sap/sailing/gwt/ui/client/images/buoys/buoy_green.png") - ImageResource buoyGreenIcon(); - - @Source("com/sap/sailing/gwt/ui/client/images/buoys/landmark.png") - ImageResource landmarkIcon(); - @Source("com/sap/sailing/gwt/ui/client/images/cameraBoat.png") ImageResource cameraBoatIcon(); diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/leaderboard/LeaderboardPanel.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/leaderboard/LeaderboardPanel.java index 04a856f011b..801b7c13c26 100755 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/leaderboard/LeaderboardPanel.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/leaderboard/LeaderboardPanel.java @@ -880,13 +880,21 @@ public class LeaderboardPanel extends SimplePanel implements TimeListener, PlayS return result; } + /** + * Reports the ratio of the time that passed since the last position fix and the average sampling interval of the + * competitor's track. On a perfect track, this value will never exceed 1.0. Immediately when a fix is received, this + * value goes to 0.0. For a competitor whose tracker is lagging, this value can grow considerably greater than 1. + * + * @author Axel Uhl (D043530) + * + */ private class RaceTrackingQuality implements LegDetailField { @Override public Double get(LeaderboardRowDTO row) { Double result = null; LeaderboardEntryDTO fieldsForRace = row.fieldsByRaceColumnName.get(getRaceColumnName()); - if (fieldsForRace != null) { - result = fieldsForRace.timeSinceLastPositionFixInSeconds; + if (fieldsForRace != null && fieldsForRace.timeSinceLastPositionFixInSeconds != null && fieldsForRace.averageSamplingInterval != null) { + result = fieldsForRace.timeSinceLastPositionFixInSeconds / fieldsForRace.averageSamplingInterval.asSeconds(); } return result; } diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/leaderboard/TrackingQualityColumn.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/leaderboard/TrackingQualityColumn.java index 5a8fbfd05e9..e78421c094d 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/leaderboard/TrackingQualityColumn.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/leaderboard/TrackingQualityColumn.java @@ -34,20 +34,16 @@ public class TrackingQualityColumn extends DetailTypeColumn { } @Override - public void render(Double timeSinceLastPositionFixInSeconds, SafeHtmlBuilder builder) { - if (timeSinceLastPositionFixInSeconds != null) { + public void render(Double ratioOfLagAndAverageSamplingInterval, SafeHtmlBuilder builder) { + if (ratioOfLagAndAverageSamplingInterval != null) { builder.append(SafeHtmlUtils.fromTrustedString("

")); } else { builder.append(SafeHtmlUtils.fromTrustedString(STYLE_TRACKING_QUALITY_CIRCLE_GREEN)); diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/server/SailingServiceImpl.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/server/SailingServiceImpl.java index 500086595ef..3faa6522ee7 100755 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/server/SailingServiceImpl.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/server/SailingServiceImpl.java @@ -1,10 +1,9 @@ package com.sap.sailing.gwt.ui.server; -import java.io.BufferedReader; import java.io.FilterInputStream; import java.io.IOException; import java.io.InputStream; -import java.io.InputStreamReader; +import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.io.Serializable; import java.io.UnsupportedEncodingException; @@ -15,7 +14,6 @@ import java.net.URISyntaxException; import java.net.URL; import java.net.URLEncoder; import java.net.UnknownHostException; -import java.nio.charset.Charset; import java.text.ParseException; import java.util.ArrayList; import java.util.Calendar; @@ -164,6 +162,7 @@ import com.sap.sailing.domain.leaderboard.MetaLeaderboard; import com.sap.sailing.domain.leaderboard.RegattaLeaderboard; import com.sap.sailing.domain.leaderboard.ThresholdBasedResultDiscardingRule; import com.sap.sailing.domain.leaderboard.caching.LiveLeaderboardUpdater; +import com.sap.sailing.domain.masterdataimport.TopLevelMasterData; import com.sap.sailing.domain.persistence.DomainObjectFactory; import com.sap.sailing.domain.persistence.MongoObjectFactory; import com.sap.sailing.domain.persistence.MongoRaceLogStoreFactory; @@ -240,6 +239,7 @@ import com.sap.sailing.gwt.ui.shared.RaceInfoDTO.GateStartInfoDTO; import com.sap.sailing.gwt.ui.shared.RaceInfoDTO.RRS26InfoDTO; import com.sap.sailing.gwt.ui.shared.RaceInfoDTO.RaceInfoExtensionDTO; import com.sap.sailing.gwt.ui.shared.RaceLogDTO; +import com.sap.sailing.gwt.ui.shared.RaceLogEventDTO; import com.sap.sailing.gwt.ui.shared.RaceLogSetStartTimeDTO; import com.sap.sailing.gwt.ui.shared.RaceTimesInfoDTO; import com.sap.sailing.gwt.ui.shared.RaceWithCompetitorsDTO; @@ -247,7 +247,6 @@ import com.sap.sailing.gwt.ui.shared.RegattaDTO; import com.sap.sailing.gwt.ui.shared.RegattaOverviewEntryDTO; import com.sap.sailing.gwt.ui.shared.RegattaScoreCorrectionDTO; import com.sap.sailing.gwt.ui.shared.RegattaScoreCorrectionDTO.ScoreCorrectionEntryDTO; -import com.sap.sailing.gwt.ui.shared.RaceLogEventDTO; import com.sap.sailing.gwt.ui.shared.ReplicaDTO; import com.sap.sailing.gwt.ui.shared.ReplicationMasterDTO; import com.sap.sailing.gwt.ui.shared.ReplicationStateDTO; @@ -704,7 +703,7 @@ public class SailingServiceImpl extends ProxiedRemoteServiceServlet implements S } SeriesDTO result = new SeriesDTO(series.getName(), fleets, raceColumns, series.isMedal(), series.getResultDiscardingRule() == null ? null : series.getResultDiscardingRule().getDiscardIndexResultsStartingWithHowManyRaces(), - series.isStartsWithZeroScore(), series.isFirstColumnIsNonDiscardableCarryForward()); + series.isStartsWithZeroScore(), series.isFirstColumnIsNonDiscardableCarryForward(), series.hasSplitFleetContiguousScoring()); return result; } @@ -905,7 +904,9 @@ public class SailingServiceImpl extends ProxiedRemoteServiceServlet implements S new MillisecondsTimePoint(record.getTrackingStartTime().asMillis()), new MillisecondsTimePoint(record.getTrackingEndTime().asMillis()), MongoRaceLogStoreFactory.INSTANCE.getMongoRaceLogStore(mongoObjectFactory, domainObjectFactory), - RaceTracker.TIMEOUT_FOR_RECEIVING_RACE_DEFINITION_IN_MILLISECONDS, simulateWithStartTimeNow, tracTracUsername, tracTracPassword); + RaceTracker.TIMEOUT_FOR_RECEIVING_RACE_DEFINITION_IN_MILLISECONDS, simulateWithStartTimeNow, + tracTracUsername, tracTracPassword, + record.getRaceStatus()); if (trackWind) { new Thread("Wind tracking starter for race " + record.getEventName() + "/" + record.getName()) { public void run() { @@ -2941,8 +2942,11 @@ public class SailingServiceImpl extends ProxiedRemoteServiceServlet implements S @Override public void updateSeries(RegattaIdentifier regattaIdentifier, String seriesName, boolean isMedal, - int[] resultDiscardingThresholds, boolean startsWithZeroScore, boolean firstColumnIsNonDiscardableCarryForward) { - getService().apply(new UpdateSeries(regattaIdentifier, seriesName, isMedal, resultDiscardingThresholds, startsWithZeroScore, firstColumnIsNonDiscardableCarryForward)); + int[] resultDiscardingThresholds, boolean startsWithZeroScore, + boolean firstColumnIsNonDiscardableCarryForward, boolean hasSplitFleetContiguousScoring) { + getService().apply( + new UpdateSeries(regattaIdentifier, seriesName, isMedal, resultDiscardingThresholds, + startsWithZeroScore, firstColumnIsNonDiscardableCarryForward, hasSplitFleetContiguousScoring)); } @Override @@ -3363,7 +3367,7 @@ public class SailingServiceImpl extends ProxiedRemoteServiceServlet implements S URL serverAddress = null; InputStream inputStream = null; - BufferedReader rd = null; + ObjectInputStream objectInputStream = null; try { serverAddress = createUrl(hostname, port, query); //set up out communications stuff @@ -3385,13 +3389,10 @@ public class SailingServiceImpl extends ProxiedRemoteServiceServlet implements S inputStream = new TimeoutExtendingInputStream(connection.getInputStream(), connection); } - rd = new BufferedReader(new InputStreamReader(inputStream, Charset.forName("UTF-8"))); - StringBuilder sb = new StringBuilder(); - String line; - while ((line = rd.readLine()) != null) { - sb.append(line); - } - return importFromHttpResponse(sb.toString(), override); + objectInputStream = getService().getBaseDomainFactory().createObjectInputStreamResolvingAgainstThisFactory( + inputStream); + TopLevelMasterData topLevelMasterData = (TopLevelMasterData) objectInputStream.readObject(); + return importFromHttpResponse(topLevelMasterData, override); } catch (Exception e) { throw new RuntimeException(e); } finally { @@ -3404,8 +3405,8 @@ public class SailingServiceImpl extends ProxiedRemoteServiceServlet implements S if (inputStream != null) { inputStream.close(); } - if (rd != null) { - rd.close(); + if (objectInputStream != null) { + objectInputStream.close(); } } catch (IOException e) { } @@ -3413,12 +3414,13 @@ public class SailingServiceImpl extends ProxiedRemoteServiceServlet implements S } private URL createUrl(String host, Integer port, String query) throws Exception { - return new URL("http://" + host + ":" + port + "/sailingserver/api/v1/masterdata/leaderboardgroups?" + query); + return new URL("http://" + host + ":" + port + "/sailingserver/spi/v1/masterdata/leaderboardgroups?" + query); } - protected MasterDataImportObjectCreationCount importFromHttpResponse(String string, boolean override) { + protected MasterDataImportObjectCreationCount importFromHttpResponse(TopLevelMasterData topLevelMasterData, + boolean override) { MasterDataImporter importer = new MasterDataImporter(baseDomainFactory, getService()); - return importer.importMasterData(string, override); + return importer.importMasterData(topLevelMasterData, override); } private String createLeaderboardQuery(String[] groupNames, boolean compress) throws UnsupportedEncodingException { diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/ListEditorComposite.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/ListEditorComposite.java deleted file mode 100644 index 0472d9dc782..00000000000 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/ListEditorComposite.java +++ /dev/null @@ -1,258 +0,0 @@ -package com.sap.sailing.gwt.ui.shared; - -import java.util.ArrayList; -import java.util.List; - -import com.google.gwt.event.dom.client.ClickEvent; -import com.google.gwt.event.dom.client.ClickHandler; -import com.google.gwt.event.logical.shared.HasValueChangeHandlers; -import com.google.gwt.event.logical.shared.ValueChangeEvent; -import com.google.gwt.event.logical.shared.ValueChangeHandler; -import com.google.gwt.event.shared.HandlerRegistration; -import com.google.gwt.resources.client.ImageResource; -import com.google.gwt.user.client.ui.Button; -import com.google.gwt.user.client.ui.Composite; -import com.google.gwt.user.client.ui.Grid; -import com.google.gwt.user.client.ui.HasValue; -import com.google.gwt.user.client.ui.HorizontalPanel; -import com.google.gwt.user.client.ui.Image; -import com.google.gwt.user.client.ui.PushButton; -import com.google.gwt.user.client.ui.TextBox; -import com.google.gwt.user.client.ui.VerticalPanel; -import com.google.gwt.user.client.ui.Widget; -import com.sap.sailing.gwt.ui.client.StringMessages; -import com.sap.sse.gwt.ui.DataEntryDialog; -import com.sap.sse.gwt.ui.DataEntryDialog.DialogCallback; - -public class ListEditorComposite extends Composite implements HasValue>, - HasValueChangeHandlers> { - - public interface ListEditorUiStrategy { - Widget initWidget(); - - void refresh(); - - void setContext(ListEditorComposite context); - - boolean isCollapsed(); - } - - public abstract static class ListEditorUi implements ListEditorUiStrategy { - protected final StringMessages stringMessages; - protected ListEditorComposite context; - - public ListEditorUi(StringMessages stringMessages) { - this.stringMessages = stringMessages; - } - - @Override - public void setContext(ListEditorComposite context) { - this.context = context; - } - } - - public abstract static class CollapsedListEditorUi extends ListEditorUi { - private static final int collapsedTitleMaxLength = 20; - - private final String popupDialogTitle; - private final ExpandedListEditorUi expandedUi; - - public CollapsedListEditorUi(StringMessages stringMessages, String popupDialogTitle, - ExpandedListEditorUi expandedUi) { - super(stringMessages); - this.popupDialogTitle = popupDialogTitle; - this.expandedUi = expandedUi; - } - - private TextBox collapsedValuesBox; - private Button collapsedEditButton; - - @Override - public void setContext(ListEditorComposite context) { - super.setContext(context); - } - - @Override - public Widget initWidget() { - HorizontalPanel panel = new HorizontalPanel(); - collapsedValuesBox = new TextBox(); - collapsedValuesBox.setReadOnly(true); - - collapsedEditButton = new Button(stringMessages.edit()); - collapsedEditButton.addClickHandler(new ClickHandler() { - @Override - public void onClick(ClickEvent event) { - new PopupEditDialog(context.getValue(), expandedUi, popupDialogTitle, - new DialogCallback>() { - - @Override - public void ok(List editedObject) { - context.setValue(editedObject); - } - - @Override - public void cancel() { - - } - }).show(); - } - }); - panel.add(collapsedValuesBox); - panel.add(collapsedEditButton); - return panel; - } - - @Override - public void refresh() { - String text = getCollapsedValueText(context.getValue()); - String shortText = text; - if (shortText.length() > collapsedTitleMaxLength) { - shortText = shortText.substring(0, collapsedTitleMaxLength) + "..."; - } - collapsedValuesBox.setText(shortText); - collapsedValuesBox.setTitle(text); - } - - @Override - public boolean isCollapsed() { - return true; - } - - protected abstract String getCollapsedValueText(List value); - - protected abstract ListEditorComposite createExpandedUi(List initialValues, - ExpandedListEditorUi ui); - - private class PopupEditDialog extends DataEntryDialog> { - - private ListEditorComposite expandedComposite; - - public PopupEditDialog(List initialValues, ExpandedListEditorUi ui, String dialogTitle, - DataEntryDialog.DialogCallback> callback) { - super(dialogTitle, "", stringMessages.save(), stringMessages.cancel(), null, callback); - expandedComposite = createExpandedUi(initialValues, ui); - } - - @Override - protected Widget getAdditionalWidget() { - return expandedComposite; - } - - @Override - protected List getResult() { - return expandedComposite.getValue(); - } - } - } - - public abstract static class ExpandedListEditorUi extends ListEditorUi { - - private final ImageResource removeImage; - - private Grid expandedValuesGrid; - - public ExpandedListEditorUi(StringMessages stringMessages, ImageResource removeImage) { - super(stringMessages); - this.removeImage = removeImage; - } - - @Override - public Widget initWidget() { - expandedValuesGrid = new Grid(0, 2); - - VerticalPanel panel = new VerticalPanel(); - panel.add(createAddWidget()); - panel.add(expandedValuesGrid); - return panel; - } - - @Override - public void refresh() { - expandedValuesGrid.clear(); - for (ValueType value : context.getValue()) { - addRow(value); - } - } - - @Override - public boolean isCollapsed() { - return false; - } - - private void addRow(ValueType newValue) { - int rowIndex = expandedValuesGrid.insertRow(expandedValuesGrid.getRowCount()); - - PushButton removeButton = new PushButton(new Image(removeImage)); - removeButton.setTitle(stringMessages.remove()); - removeButton.addClickHandler(new ClickHandler() { - - @Override - public void onClick(ClickEvent event) { - int rowToRemove = expandedValuesGrid.getCellForEvent(event).getRowIndex(); - expandedValuesGrid.removeRow(rowToRemove); - context.getValue().remove(rowToRemove); - context.onChange(); - } - }); - - expandedValuesGrid.setWidget(rowIndex, 0, createValueWidget(newValue)); - expandedValuesGrid.setWidget(rowIndex, 1, removeButton); - } - - protected void addValue(ValueType newValue) { - context.getValue().add(newValue); - addRow(newValue); - context.onChange(); - } - - protected abstract Widget createAddWidget(); - - protected abstract Widget createValueWidget(ValueType newValue); - } - - private final ListEditorUiStrategy activeUi; - - private List values; - - protected ListEditorComposite(List initialValues, ListEditorUiStrategy activeUi) { - this.values = new ArrayList(initialValues); - this.activeUi = activeUi; - this.activeUi.setContext(this); - - initWidget(activeUi.initWidget()); - activeUi.refresh(); - } - - @Override - public List getValue() { - return values; - } - - @Override - public void setValue(List newValues) { - setValue(newValues, true); - } - - @Override - public void setValue(List newValues, boolean fireEvents) { - this.values = newValues; - activeUi.refresh(); - if (fireEvents) { - onChange(); - } - } - - @Override - public HandlerRegistration addValueChangeHandler(ValueChangeHandler> handler) { - return addHandler(handler, ValueChangeEvent.getType()); - } - - public void onChange() { - ValueChangeEvent.fire(this, getValue()); - } - - public boolean isCollapsed() { - return activeUi.isCollapsed(); - } - -} diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/SeriesDTO.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/SeriesDTO.java index f3e164371db..1bac559ead3 100755 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/SeriesDTO.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/SeriesDTO.java @@ -14,19 +14,28 @@ public class SeriesDTO extends NamedDTO { private int[] discardThresholds; private Boolean startsWithZeroScore; private boolean firstColumnIsNonDiscardableCarryForward; + private boolean hasSplitFleetContiguousScoring; public SeriesDTO() {} - public SeriesDTO(String name, List fleets, List raceColumns, boolean isMedal, int[] discardThresholds, boolean startsWithZeroScore, boolean firstColumnIsNonDiscardableCarryForward) { + public SeriesDTO(String name, List fleets, List raceColumns, boolean isMedal, + int[] discardThresholds, boolean startsWithZeroScore, boolean firstColumnIsNonDiscardableCarryForward, + boolean hasSplitFleetContiguousScoring) { super(name); this.fleets = fleets; this.raceColumns = raceColumns; this.isMedal = isMedal; this.startsWithZeroScore = startsWithZeroScore; + this.hasSplitFleetContiguousScoring = hasSplitFleetContiguousScoring; this.discardThresholds = discardThresholds; this.firstColumnIsNonDiscardableCarryForward = firstColumnIsNonDiscardableCarryForward; } + + public boolean hasSplitFleetContiguousScoring() { + return hasSplitFleetContiguousScoring; + } + public boolean isMedal() { return isMedal; } @@ -83,4 +92,8 @@ public class SeriesDTO extends NamedDTO { public boolean isFirstColumnIsNonDiscardableCarryForward() { return firstColumnIsNonDiscardableCarryForward; } + + public void setSplitFleetContiguousScoring(Boolean hasSplitFleetContiguousScoring) { + this.hasSplitFleetContiguousScoring = hasSplitFleetContiguousScoring; + } } diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/racemap/BoatClassVectorGraphics.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/racemap/BoatClassVectorGraphics.java index 611d720d140..1158de92037 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/racemap/BoatClassVectorGraphics.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/racemap/BoatClassVectorGraphics.java @@ -18,9 +18,10 @@ import com.sap.sailing.domain.common.Tack; * */ public abstract class BoatClassVectorGraphics { - protected double boatLengthInMeters; + protected double boatOverallLengthInMeters; + protected double boatHullLengthInMeters; protected double boatBeamInMeters; - protected double boatCenterAlongLengthInMeters; +// protected double boatCenterAlongLengthInMeters; private final String mainBoatClassName; private final List compatibleBoatClassNames; @@ -28,17 +29,17 @@ public abstract class BoatClassVectorGraphics { protected final String SAIL_FILLCOLOR = "#555555"; protected final String SAIL_STROKECOLOR = "#000000"; - BoatClassVectorGraphics(String mainBoatClassName, double boatLengthInMeters, double boatBeamInMeters, double boatCenterAlongLengthInMeters) { + BoatClassVectorGraphics(String mainBoatClassName, double boatOverallLengthInMeters, double boatBeamInMeters, double boatHullLengthInMeters) { this.mainBoatClassName = mainBoatClassName; - this.boatLengthInMeters = boatLengthInMeters; + this.boatOverallLengthInMeters = boatOverallLengthInMeters; this.boatBeamInMeters = boatBeamInMeters; - this.boatCenterAlongLengthInMeters = boatCenterAlongLengthInMeters; + this.boatHullLengthInMeters = boatHullLengthInMeters; this.compatibleBoatClassNames = new ArrayList(); } - BoatClassVectorGraphics(String mainBoatClassName, double boatLengthInMeters, double boatBeamInMeters, double boatCenterAlongLengthInMeters, + BoatClassVectorGraphics(String mainBoatClassName, double boatOverallLengthInMeters, double boatBeamInMeters, double boatHullLengthInMeters, String...compatibleBoatClassNames) { - this(mainBoatClassName, boatLengthInMeters, boatBeamInMeters, boatCenterAlongLengthInMeters); + this(mainBoatClassName, boatOverallLengthInMeters, boatBeamInMeters, boatHullLengthInMeters); for(String compatibleBoatClass: compatibleBoatClassNames) { this.compatibleBoatClassNames.add(compatibleBoatClass); } @@ -112,7 +113,7 @@ public abstract class BoatClassVectorGraphics { ctx.translate(width / 2.0, height / 2.0); ctx.rotate(angleInRadians); ctx.scale(scaleFactor, scaleFactor); - ctx.translate(-boatCenterAlongLengthInMeters * 100,- boatBeamInMeters * 100 / 2.0); + ctx.translate(-boatHullLengthInMeters * 100 / 2.0,- boatBeamInMeters * 100 / 2.0); drawBoat(ctx, isSelected, color); drawSails(ctx, legType, tack); @@ -120,18 +121,18 @@ public abstract class BoatClassVectorGraphics { ctx.restore(); } - public double getBoatLengthInMeters() { - return boatLengthInMeters; + public double getBoatHullLengthInMeters() { + return boatHullLengthInMeters; + } + + public double getBoatOverallLengthInMeters() { + return boatOverallLengthInMeters; } public double getBoatBeamInMeters() { return boatBeamInMeters; } - public double getBoatCenterAlongLengthInMeters() { - return boatCenterAlongLengthInMeters; - } - public boolean isBoatClassNameCompatible(String boatClass) { boolean result = false; // remove all white space characters diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/racemap/CanvasOverlayV3.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/racemap/CanvasOverlayV3.java index d36af12c1a4..10d6ce10494 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/racemap/CanvasOverlayV3.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/racemap/CanvasOverlayV3.java @@ -86,6 +86,9 @@ public abstract class CanvasOverlayV3 { */ private long transitionTimeInMilliseconds; + private final int minZoomLevel = 1; + private final int maxZoomLevel = 21; + public CanvasOverlayV3(MapWidget map, int zIndex, String canvasId) { this.transitionTimeInMilliseconds = -1; // no animated position transition initially this.map = map; @@ -109,6 +112,18 @@ public abstract class CanvasOverlayV3 { return canvas; } + /** + * This method can be used to calculate a value in a min-max range according to the zoom level. + * Sample 1: minZoom = 1, maxZoom = 21, currentZoom = 21 will return maxValue + * Sample 2: minZoom = 1, maxZoom = 21, currentZoom = 1 will return minValue + * Sample 3: minZoom = 1, maxZoom = 21, currentZoom = 11, minValue = 1, maxValue = 2 will return 1.5 + */ + public double fitValueToMapZoom(double minValue, double maxValue) { + double dZoom = maxZoomLevel - minZoomLevel; + double zoomInPercentage = (map.getZoom() - minZoomLevel) / dZoom; + return minValue + (maxValue - minValue) * zoomInPercentage; + } + public boolean isVisible() { return getCanvas() != null && getCanvas().isVisible(); } diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/racemap/Extreme40VectorGraphics.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/racemap/Extreme40VectorGraphics.java index 2655b2a13d1..13c3a4f62c3 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/racemap/Extreme40VectorGraphics.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/racemap/Extreme40VectorGraphics.java @@ -6,7 +6,7 @@ import com.google.gwt.canvas.dom.client.Context2d.LineJoin; public class Extreme40VectorGraphics extends BoatClassVectorGraphics { public Extreme40VectorGraphics(String... compatibleBoatClassNames) { - super("EXTREME40", 16.0, 7.6, 6.1, compatibleBoatClassNames); + super("EXTREME40", 16.0, 7.6, 12.2, compatibleBoatClassNames); } @Override diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/racemap/LaserVectorGraphics.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/racemap/LaserVectorGraphics.java index 45aaa387e97..13609610c61 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/racemap/LaserVectorGraphics.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/racemap/LaserVectorGraphics.java @@ -5,17 +5,20 @@ import com.google.gwt.canvas.dom.client.Context2d; public class LaserVectorGraphics extends BoatClassVectorGraphics { public LaserVectorGraphics(String... compatibleBoatClassNames) { - super("LASER", 4.23, 1.37, 2.1, compatibleBoatClassNames); + super("LASER", 4.23, 1.37, 4.23, compatibleBoatClassNames); } @Override protected void drawBoat(Context2d ctx, boolean isSelected, String color) { + // outer part of the hull if(isSelected) { - ctx.setFillStyle("#FF0000"); + ctx.setFillStyle(color); + ctx.setStrokeStyle(color); } else { - ctx.setFillStyle("#FFFFFF"); + ctx.setFillStyle ("#FFFFFF"); + ctx.setStrokeStyle("#FFFFFF"); } - ctx.setStrokeStyle(color); + ctx.setLineWidth(2.0); ctx.beginPath(); ctx.moveTo(1.72,27); @@ -28,8 +31,15 @@ public class LaserVectorGraphics extends BoatClassVectorGraphics { ctx.fill(); ctx.stroke(); - ctx.setFillStyle(color); - ctx.setStrokeStyle(color); + // inner part of the hull + if(isSelected) { + ctx.setFillStyle ("#FFFFFF"); + ctx.setStrokeStyle("#FFFFFF"); + } else { + ctx.setFillStyle(color); + ctx.setStrokeStyle(color); + } + ctx.setLineWidth(1.0); ctx.beginPath(); ctx.moveTo(48.2,44.2); diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/racemap/MarkVectorGraphics.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/racemap/MarkVectorGraphics.java index 2738eb4a24c..38f7845a90b 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/racemap/MarkVectorGraphics.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/racemap/MarkVectorGraphics.java @@ -5,6 +5,8 @@ import com.sap.sailing.domain.common.MarkType; /** * A class for course mark graphics based on SVG graphics drawn to a HTML5 canvas + * The SVG files for the drawing can be found in the package com.sap.sailing.gwt.ui.svg.buys + * A general description how to convert SVG files to 'drawing commands' can be found at http://wiki.sapsailing.com/wiki/boatgraphicssvg * @author Frank * */ diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/racemap/SmallMultihullVectorGraphics.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/racemap/SmallMultihullVectorGraphics.java index 2533232027a..8524a6637c5 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/racemap/SmallMultihullVectorGraphics.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/racemap/SmallMultihullVectorGraphics.java @@ -6,7 +6,7 @@ import com.google.gwt.canvas.dom.client.Context2d.LineJoin; public class SmallMultihullVectorGraphics extends BoatClassVectorGraphics { public SmallMultihullVectorGraphics(String... compatibleBoatClassNames) { - super("Multihull", 7.1, 2.6, 2.62, compatibleBoatClassNames); + super("Multihull", 7.1, 2.6, 5.25, compatibleBoatClassNames); } @Override diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/racemap/_49erVectorGraphics.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/racemap/_49erVectorGraphics.java index 8ac5f7ec7bd..9af66dfa3bf 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/racemap/_49erVectorGraphics.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/racemap/_49erVectorGraphics.java @@ -6,7 +6,7 @@ import com.google.gwt.canvas.dom.client.Context2d.LineJoin; public class _49erVectorGraphics extends BoatClassVectorGraphics { public _49erVectorGraphics(String... compatibleBoatClassNames) { - super("49ER", 4.99, 2.90, 2.50, compatibleBoatClassNames); + super("49ER", 4.99, 2.90, 4.99, compatibleBoatClassNames); } @Override diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/spectator/LeaderboardGroupPanel.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/spectator/LeaderboardGroupPanel.java index ee0d5f4aba3..8a9d41101df 100755 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/spectator/LeaderboardGroupPanel.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/spectator/LeaderboardGroupPanel.java @@ -16,7 +16,9 @@ import com.google.gwt.user.cellview.client.Column; import com.google.gwt.user.client.rpc.AsyncCallback; import com.google.gwt.user.client.ui.Anchor; import com.google.gwt.user.client.ui.FlexTable; +import com.google.gwt.user.client.ui.Grid; import com.google.gwt.user.client.ui.HTML; +import com.google.gwt.user.client.ui.HTMLTable.CellFormatter; import com.google.gwt.user.client.ui.HasVerticalAlignment; import com.google.gwt.user.client.ui.HorizontalPanel; import com.google.gwt.user.client.ui.Label; @@ -238,7 +240,7 @@ public class LeaderboardGroupPanel extends SimplePanel implements HasWelcomeWidg racesCell) { @Override public SafeHtml getValue(StrippedLeaderboardDTO leaderboard) { - return leaderboardRacesToHtml(leaderboard); + return leaderboardStrutureToHtml(leaderboard); } }; leaderboardsTable.addColumn(racesColumn, stringMessages.races()); @@ -309,65 +311,75 @@ public class LeaderboardGroupPanel extends SimplePanel implements HasWelcomeWidg return legendPanel; } - private SafeHtml leaderboardRacesToHtml(StrippedLeaderboardDTO leaderboard) { + private SafeHtml leaderboardStrutureToHtml(StrippedLeaderboardDTO leaderboard) { SafeHtmlBuilder b = new SafeHtmlBuilder(); if (leaderboard.type.isRegattaLeaderboard()) { RegattaDTO regatta = regattasByName.get(leaderboard.regattaName); if (regatta != null) { - boolean renderSeriesName = Util.size(regatta.series) > 1; + int numberOfSeries = Util.size(regatta.series); + Grid seriesGrid = new Grid(numberOfSeries, 2); + CellFormatter seriesGridFormatter = seriesGrid.getCellFormatter(); + int seriesRow = 0; for (SeriesDTO series : regatta.series) { - b.appendHtmlConstant("
"); - renderSeriesToHtml(leaderboard, series, renderSeriesName, b); - b.appendHtmlConstant("
"); - b.appendHtmlConstant("
"); + // render the series name + if (! "Default".equals(series.getName())) { + seriesGrid.setHTML(seriesRow, 0, TEXTTEMPLATE.textWithClass(series.getName(), 50, STYLE_TABLE_TEXT)); + } + seriesGridFormatter.setVerticalAlignment(seriesRow, 0, HasVerticalAlignment.ALIGN_MIDDLE); + int numberOfFleets = series.getFleets().size(); + if(numberOfFleets > 1) { + // multiple fleets + Grid fleetsGrid = new Grid(numberOfFleets, 3); + CellFormatter fleetGridsFormatter = fleetsGrid.getCellFormatter(); + int fleetRow = 0; + for(FleetDTO fleet: series.getFleets()) { + Color color = fleet.getColor(); + if(color != null) { + fleetsGrid.setHTML(fleetRow, 0, COLORBOXTEMPLATE.colorBox(color.getAsHtml(), STYLE_COLORBOX)); + fleetGridsFormatter.setVerticalAlignment(fleetRow, 0, HasVerticalAlignment.ALIGN_MIDDLE); + } + fleetsGrid.setHTML(fleetRow, 1, TEXTTEMPLATE.textWithClass(fleet.getName(), 50, STYLE_TABLE_TEXT)); + fleetGridsFormatter.setVerticalAlignment(fleetRow, 1, HasVerticalAlignment.ALIGN_MIDDLE); + List raceColumnsOfSeries = getRacesOfFleet(leaderboard, series, fleet); + fleetsGrid.setHTML(fleetRow, 2, renderRacesToHTml(leaderboard.name, raceColumnsOfSeries, fleet)); + fleetRow++; + } + seriesGrid.setWidget(seriesRow, 1, fleetsGrid); + } else { + // single fleet + FleetDTO fleet = series.getFleets().get(0); + List raceColumnsOfSeries = getRacesOfFleet(leaderboard, series, fleet); + String displayName = fleet.getName(); + if (! "Default".equals(fleet.getName())) { + Grid fleetsGrid = new Grid(1, 2); + CellFormatter fleetGridsFormatter = fleetsGrid.getCellFormatter(); + fleetsGrid.setHTML(0, 0, TEXTTEMPLATE.textWithClass(displayName, 50, STYLE_TABLE_TEXT)); + fleetGridsFormatter.setVerticalAlignment(0, 0, HasVerticalAlignment.ALIGN_MIDDLE); + fleetsGrid.setHTML(0, 1, renderRacesToHTml(leaderboard.name, raceColumnsOfSeries, fleet)); + seriesGrid.setWidget(seriesRow, 1, fleetsGrid); + } else { + seriesGrid.setHTML(seriesRow, 1, renderRacesToHTml(leaderboard.name, raceColumnsOfSeries, fleet)); + } + } + seriesRow++; } + b.appendHtmlConstant(seriesGrid.getElement().getString()); } } else { List raceColumns = leaderboard.getRaceList(); - renderRacesToHTml(leaderboard.name, raceColumns, new FleetDTO(LeaderboardNameConstants.DEFAULT_FLEET_NAME, 0, null), b); + b.append(renderRacesToHTml(leaderboard.name, raceColumns, new FleetDTO(LeaderboardNameConstants.DEFAULT_FLEET_NAME, 0, null))); } return b.toSafeHtml(); } - - private void renderSeriesToHtml(StrippedLeaderboardDTO leaderboard, SeriesDTO series, boolean renderSeriesName, SafeHtmlBuilder b) { - boolean hasMultipleFleets = series.getFleets().size() > 1; - b.appendHtmlConstant("
"); - if(renderSeriesName) { - b.append(TEXTTEMPLATE.textWithClass(series.getName(), 50, STYLE_TABLE_TEXT)); - } - b.appendHtmlConstant("
"); - b.appendHtmlConstant("
"); - for(FleetDTO fleet: series.getFleets()) { - Color color = fleet.getColor(); - // show the "fleet" and the color only if there are more than one fleet in this fleet group and a color has been set - b.appendHtmlConstant("
"); - - if (hasMultipleFleets) { - if(color != null) { - b.append(COLORBOXTEMPLATE.colorBox(color.getAsHtml(), STYLE_COLORBOX)); - } - b.append(TEXTTEMPLATE.textWithClass(fleet.getName(), 50, STYLE_TABLE_TEXT)); - } else { - String displayName = fleet.getName(); - if (! "Default".equals(fleet.getName())) { - b.append(TEXTTEMPLATE.textWithClass(displayName, 50, STYLE_TABLE_TEXT)); - } - } - - List raceColumnsOfSeries = getRacesOfFleet(leaderboard, series, fleet); - renderRacesToHTml(leaderboard.name, raceColumnsOfSeries, fleet, b); - - b.appendHtmlConstant("
"); - } - b.appendHtmlConstant("
"); - } - private void renderRacesToHTml(String leaderboardName, List raceColumns, FleetDTO fleet, SafeHtmlBuilder b) { + private SafeHtml renderRacesToHTml(String leaderboardName, List raceColumns, FleetDTO fleet) { + SafeHtmlBuilder b = new SafeHtmlBuilder(); for (RaceColumnDTO raceColumn : raceColumns) { String raceColumnName = raceColumn.getRaceColumnName(); RaceDTO race = raceColumn.getRace(fleet); renderRaceLink(leaderboardName, race, raceColumn.isLive(fleet, timerForClientServerOffset.getLiveTimePointInMillis()), raceColumnName, b); } + return b.toSafeHtml(); } private List getRacesOfFleet(StrippedLeaderboardDTO leaderboard, SeriesDTO series, FleetDTO fleet) { diff --git a/java/com.sap.sailing.gwt.ui/src/main/resources/com/sap/sailing/gwt/ui/client/images/boats/class_470er/470er_DW_Port.png b/java/com.sap.sailing.gwt.ui/src/main/resources/com/sap/sailing/gwt/ui/client/images/boats/class_470er/470er_DW_Port.png deleted file mode 100644 index dcb004c32c1..00000000000 Binary files a/java/com.sap.sailing.gwt.ui/src/main/resources/com/sap/sailing/gwt/ui/client/images/boats/class_470er/470er_DW_Port.png and /dev/null differ diff --git a/java/com.sap.sailing.gwt.ui/src/main/resources/com/sap/sailing/gwt/ui/client/images/boats/class_470er/470er_DW_Port_Selected.png b/java/com.sap.sailing.gwt.ui/src/main/resources/com/sap/sailing/gwt/ui/client/images/boats/class_470er/470er_DW_Port_Selected.png deleted file mode 100644 index 23b42ffe5d4..00000000000 Binary files a/java/com.sap.sailing.gwt.ui/src/main/resources/com/sap/sailing/gwt/ui/client/images/boats/class_470er/470er_DW_Port_Selected.png and /dev/null differ diff --git a/java/com.sap.sailing.gwt.ui/src/main/resources/com/sap/sailing/gwt/ui/client/images/boats/class_470er/470er_DW_Starboard.png b/java/com.sap.sailing.gwt.ui/src/main/resources/com/sap/sailing/gwt/ui/client/images/boats/class_470er/470er_DW_Starboard.png deleted file mode 100644 index 5456ba13340..00000000000 Binary files a/java/com.sap.sailing.gwt.ui/src/main/resources/com/sap/sailing/gwt/ui/client/images/boats/class_470er/470er_DW_Starboard.png and /dev/null differ diff --git a/java/com.sap.sailing.gwt.ui/src/main/resources/com/sap/sailing/gwt/ui/client/images/boats/class_470er/470er_DW_Starboard_Selected.png b/java/com.sap.sailing.gwt.ui/src/main/resources/com/sap/sailing/gwt/ui/client/images/boats/class_470er/470er_DW_Starboard_Selected.png deleted file mode 100644 index 714f2dfc9a1..00000000000 Binary files a/java/com.sap.sailing.gwt.ui/src/main/resources/com/sap/sailing/gwt/ui/client/images/boats/class_470er/470er_DW_Starboard_Selected.png and /dev/null differ diff --git a/java/com.sap.sailing.gwt.ui/src/main/resources/com/sap/sailing/gwt/ui/client/images/boats/class_470er/470er_Reach_Port.png b/java/com.sap.sailing.gwt.ui/src/main/resources/com/sap/sailing/gwt/ui/client/images/boats/class_470er/470er_Reach_Port.png deleted file mode 100644 index 5fa56e31d31..00000000000 Binary files a/java/com.sap.sailing.gwt.ui/src/main/resources/com/sap/sailing/gwt/ui/client/images/boats/class_470er/470er_Reach_Port.png and /dev/null differ diff --git a/java/com.sap.sailing.gwt.ui/src/main/resources/com/sap/sailing/gwt/ui/client/images/boats/class_470er/470er_Reach_Port_Selected.png b/java/com.sap.sailing.gwt.ui/src/main/resources/com/sap/sailing/gwt/ui/client/images/boats/class_470er/470er_Reach_Port_Selected.png deleted file mode 100644 index 75d6c8040ac..00000000000 Binary files a/java/com.sap.sailing.gwt.ui/src/main/resources/com/sap/sailing/gwt/ui/client/images/boats/class_470er/470er_Reach_Port_Selected.png and /dev/null differ diff --git a/java/com.sap.sailing.gwt.ui/src/main/resources/com/sap/sailing/gwt/ui/client/images/boats/class_470er/470er_Reach_Starboard.png b/java/com.sap.sailing.gwt.ui/src/main/resources/com/sap/sailing/gwt/ui/client/images/boats/class_470er/470er_Reach_Starboard.png deleted file mode 100644 index 71d5144eb85..00000000000 Binary files a/java/com.sap.sailing.gwt.ui/src/main/resources/com/sap/sailing/gwt/ui/client/images/boats/class_470er/470er_Reach_Starboard.png and /dev/null differ diff --git a/java/com.sap.sailing.gwt.ui/src/main/resources/com/sap/sailing/gwt/ui/client/images/boats/class_470er/470er_Reach_Starboard_Selected.png b/java/com.sap.sailing.gwt.ui/src/main/resources/com/sap/sailing/gwt/ui/client/images/boats/class_470er/470er_Reach_Starboard_Selected.png deleted file mode 100644 index cc97925c22d..00000000000 Binary files a/java/com.sap.sailing.gwt.ui/src/main/resources/com/sap/sailing/gwt/ui/client/images/boats/class_470er/470er_Reach_Starboard_Selected.png and /dev/null differ diff --git a/java/com.sap.sailing.gwt.ui/src/main/resources/com/sap/sailing/gwt/ui/client/images/boats/class_470er/470er_UW_Port.png b/java/com.sap.sailing.gwt.ui/src/main/resources/com/sap/sailing/gwt/ui/client/images/boats/class_470er/470er_UW_Port.png deleted file mode 100644 index 24ea725cfc9..00000000000 Binary files a/java/com.sap.sailing.gwt.ui/src/main/resources/com/sap/sailing/gwt/ui/client/images/boats/class_470er/470er_UW_Port.png and /dev/null differ diff --git a/java/com.sap.sailing.gwt.ui/src/main/resources/com/sap/sailing/gwt/ui/client/images/boats/class_470er/470er_UW_Port_Selected.png b/java/com.sap.sailing.gwt.ui/src/main/resources/com/sap/sailing/gwt/ui/client/images/boats/class_470er/470er_UW_Port_Selected.png deleted file mode 100644 index 626e1881c92..00000000000 Binary files a/java/com.sap.sailing.gwt.ui/src/main/resources/com/sap/sailing/gwt/ui/client/images/boats/class_470er/470er_UW_Port_Selected.png and /dev/null differ diff --git a/java/com.sap.sailing.gwt.ui/src/main/resources/com/sap/sailing/gwt/ui/client/images/boats/class_470er/470er_UW_Starboard.png b/java/com.sap.sailing.gwt.ui/src/main/resources/com/sap/sailing/gwt/ui/client/images/boats/class_470er/470er_UW_Starboard.png deleted file mode 100644 index 19c3f1a38d4..00000000000 Binary files a/java/com.sap.sailing.gwt.ui/src/main/resources/com/sap/sailing/gwt/ui/client/images/boats/class_470er/470er_UW_Starboard.png and /dev/null differ diff --git a/java/com.sap.sailing.gwt.ui/src/main/resources/com/sap/sailing/gwt/ui/client/images/boats/class_470er/470er_UW_Starboard_Selected.png b/java/com.sap.sailing.gwt.ui/src/main/resources/com/sap/sailing/gwt/ui/client/images/boats/class_470er/470er_UW_Starboard_Selected.png deleted file mode 100644 index f75b0559170..00000000000 Binary files a/java/com.sap.sailing.gwt.ui/src/main/resources/com/sap/sailing/gwt/ui/client/images/boats/class_470er/470er_UW_Starboard_Selected.png and /dev/null differ diff --git a/java/com.sap.sailing.gwt.ui/src/main/resources/com/sap/sailing/gwt/ui/client/images/boats/class_49er/49er_DW_Port.png b/java/com.sap.sailing.gwt.ui/src/main/resources/com/sap/sailing/gwt/ui/client/images/boats/class_49er/49er_DW_Port.png deleted file mode 100644 index 495d62c1fd5..00000000000 Binary files a/java/com.sap.sailing.gwt.ui/src/main/resources/com/sap/sailing/gwt/ui/client/images/boats/class_49er/49er_DW_Port.png and /dev/null differ diff --git a/java/com.sap.sailing.gwt.ui/src/main/resources/com/sap/sailing/gwt/ui/client/images/boats/class_49er/49er_DW_Port_Selected.png b/java/com.sap.sailing.gwt.ui/src/main/resources/com/sap/sailing/gwt/ui/client/images/boats/class_49er/49er_DW_Port_Selected.png deleted file mode 100644 index 6cd2c2fe043..00000000000 Binary files a/java/com.sap.sailing.gwt.ui/src/main/resources/com/sap/sailing/gwt/ui/client/images/boats/class_49er/49er_DW_Port_Selected.png and /dev/null differ diff --git a/java/com.sap.sailing.gwt.ui/src/main/resources/com/sap/sailing/gwt/ui/client/images/boats/class_49er/49er_DW_Starboard.png b/java/com.sap.sailing.gwt.ui/src/main/resources/com/sap/sailing/gwt/ui/client/images/boats/class_49er/49er_DW_Starboard.png deleted file mode 100644 index 21b31cec569..00000000000 Binary files a/java/com.sap.sailing.gwt.ui/src/main/resources/com/sap/sailing/gwt/ui/client/images/boats/class_49er/49er_DW_Starboard.png and /dev/null differ diff --git a/java/com.sap.sailing.gwt.ui/src/main/resources/com/sap/sailing/gwt/ui/client/images/boats/class_49er/49er_DW_Starboard_Selected.png b/java/com.sap.sailing.gwt.ui/src/main/resources/com/sap/sailing/gwt/ui/client/images/boats/class_49er/49er_DW_Starboard_Selected.png deleted file mode 100644 index a13f5d2cef1..00000000000 Binary files a/java/com.sap.sailing.gwt.ui/src/main/resources/com/sap/sailing/gwt/ui/client/images/boats/class_49er/49er_DW_Starboard_Selected.png and /dev/null differ diff --git a/java/com.sap.sailing.gwt.ui/src/main/resources/com/sap/sailing/gwt/ui/client/images/boats/class_49er/49er_Reach_Port.png b/java/com.sap.sailing.gwt.ui/src/main/resources/com/sap/sailing/gwt/ui/client/images/boats/class_49er/49er_Reach_Port.png deleted file mode 100644 index 36055a92b27..00000000000 Binary files a/java/com.sap.sailing.gwt.ui/src/main/resources/com/sap/sailing/gwt/ui/client/images/boats/class_49er/49er_Reach_Port.png and /dev/null differ diff --git a/java/com.sap.sailing.gwt.ui/src/main/resources/com/sap/sailing/gwt/ui/client/images/boats/class_49er/49er_Reach_Port_Selected.png b/java/com.sap.sailing.gwt.ui/src/main/resources/com/sap/sailing/gwt/ui/client/images/boats/class_49er/49er_Reach_Port_Selected.png deleted file mode 100644 index b8253433195..00000000000 Binary files a/java/com.sap.sailing.gwt.ui/src/main/resources/com/sap/sailing/gwt/ui/client/images/boats/class_49er/49er_Reach_Port_Selected.png and /dev/null differ diff --git a/java/com.sap.sailing.gwt.ui/src/main/resources/com/sap/sailing/gwt/ui/client/images/boats/class_49er/49er_Reach_Starboard.png b/java/com.sap.sailing.gwt.ui/src/main/resources/com/sap/sailing/gwt/ui/client/images/boats/class_49er/49er_Reach_Starboard.png deleted file mode 100644 index ffd4c369d80..00000000000 Binary files a/java/com.sap.sailing.gwt.ui/src/main/resources/com/sap/sailing/gwt/ui/client/images/boats/class_49er/49er_Reach_Starboard.png and /dev/null differ diff --git a/java/com.sap.sailing.gwt.ui/src/main/resources/com/sap/sailing/gwt/ui/client/images/boats/class_49er/49er_Reach_Starboard_Selected.png b/java/com.sap.sailing.gwt.ui/src/main/resources/com/sap/sailing/gwt/ui/client/images/boats/class_49er/49er_Reach_Starboard_Selected.png deleted file mode 100644 index 31a6ef2cea3..00000000000 Binary files a/java/com.sap.sailing.gwt.ui/src/main/resources/com/sap/sailing/gwt/ui/client/images/boats/class_49er/49er_Reach_Starboard_Selected.png and /dev/null differ diff --git a/java/com.sap.sailing.gwt.ui/src/main/resources/com/sap/sailing/gwt/ui/client/images/boats/class_49er/49er_UW_Port.png b/java/com.sap.sailing.gwt.ui/src/main/resources/com/sap/sailing/gwt/ui/client/images/boats/class_49er/49er_UW_Port.png deleted file mode 100644 index d19bf5b5648..00000000000 Binary files a/java/com.sap.sailing.gwt.ui/src/main/resources/com/sap/sailing/gwt/ui/client/images/boats/class_49er/49er_UW_Port.png and /dev/null differ diff --git a/java/com.sap.sailing.gwt.ui/src/main/resources/com/sap/sailing/gwt/ui/client/images/boats/class_49er/49er_UW_Port_Selected.png b/java/com.sap.sailing.gwt.ui/src/main/resources/com/sap/sailing/gwt/ui/client/images/boats/class_49er/49er_UW_Port_Selected.png deleted file mode 100644 index 661cf4bc9b9..00000000000 Binary files a/java/com.sap.sailing.gwt.ui/src/main/resources/com/sap/sailing/gwt/ui/client/images/boats/class_49er/49er_UW_Port_Selected.png and /dev/null differ diff --git a/java/com.sap.sailing.gwt.ui/src/main/resources/com/sap/sailing/gwt/ui/client/images/boats/class_49er/49er_UW_Starboard.png b/java/com.sap.sailing.gwt.ui/src/main/resources/com/sap/sailing/gwt/ui/client/images/boats/class_49er/49er_UW_Starboard.png deleted file mode 100644 index 4211b106446..00000000000 Binary files a/java/com.sap.sailing.gwt.ui/src/main/resources/com/sap/sailing/gwt/ui/client/images/boats/class_49er/49er_UW_Starboard.png and /dev/null differ diff --git a/java/com.sap.sailing.gwt.ui/src/main/resources/com/sap/sailing/gwt/ui/client/images/boats/class_49er/49er_UW_Starboard_Selected.png b/java/com.sap.sailing.gwt.ui/src/main/resources/com/sap/sailing/gwt/ui/client/images/boats/class_49er/49er_UW_Starboard_Selected.png deleted file mode 100644 index 93ac0b9315c..00000000000 Binary files a/java/com.sap.sailing.gwt.ui/src/main/resources/com/sap/sailing/gwt/ui/client/images/boats/class_49er/49er_UW_Starboard_Selected.png and /dev/null differ diff --git a/java/com.sap.sailing.gwt.ui/src/main/resources/com/sap/sailing/gwt/ui/client/images/boats/class_extreme40/Extreme40_DW_Port.png b/java/com.sap.sailing.gwt.ui/src/main/resources/com/sap/sailing/gwt/ui/client/images/boats/class_extreme40/Extreme40_DW_Port.png deleted file mode 100644 index ec2702a6991..00000000000 Binary files a/java/com.sap.sailing.gwt.ui/src/main/resources/com/sap/sailing/gwt/ui/client/images/boats/class_extreme40/Extreme40_DW_Port.png and /dev/null differ diff --git a/java/com.sap.sailing.gwt.ui/src/main/resources/com/sap/sailing/gwt/ui/client/images/boats/class_extreme40/Extreme40_DW_Port_Selected.png b/java/com.sap.sailing.gwt.ui/src/main/resources/com/sap/sailing/gwt/ui/client/images/boats/class_extreme40/Extreme40_DW_Port_Selected.png deleted file mode 100644 index 1d63d72e666..00000000000 Binary files a/java/com.sap.sailing.gwt.ui/src/main/resources/com/sap/sailing/gwt/ui/client/images/boats/class_extreme40/Extreme40_DW_Port_Selected.png and /dev/null differ diff --git a/java/com.sap.sailing.gwt.ui/src/main/resources/com/sap/sailing/gwt/ui/client/images/boats/class_extreme40/Extreme40_DW_Starboard.png b/java/com.sap.sailing.gwt.ui/src/main/resources/com/sap/sailing/gwt/ui/client/images/boats/class_extreme40/Extreme40_DW_Starboard.png deleted file mode 100644 index 59d3af29d51..00000000000 Binary files a/java/com.sap.sailing.gwt.ui/src/main/resources/com/sap/sailing/gwt/ui/client/images/boats/class_extreme40/Extreme40_DW_Starboard.png and /dev/null differ diff --git a/java/com.sap.sailing.gwt.ui/src/main/resources/com/sap/sailing/gwt/ui/client/images/boats/class_extreme40/Extreme40_DW_Starboard_Selected.png b/java/com.sap.sailing.gwt.ui/src/main/resources/com/sap/sailing/gwt/ui/client/images/boats/class_extreme40/Extreme40_DW_Starboard_Selected.png deleted file mode 100644 index 2dad940b379..00000000000 Binary files a/java/com.sap.sailing.gwt.ui/src/main/resources/com/sap/sailing/gwt/ui/client/images/boats/class_extreme40/Extreme40_DW_Starboard_Selected.png and /dev/null differ diff --git a/java/com.sap.sailing.gwt.ui/src/main/resources/com/sap/sailing/gwt/ui/client/images/boats/class_extreme40/Extreme40_Reach_Port.png b/java/com.sap.sailing.gwt.ui/src/main/resources/com/sap/sailing/gwt/ui/client/images/boats/class_extreme40/Extreme40_Reach_Port.png deleted file mode 100644 index 8fb5e6824a0..00000000000 Binary files a/java/com.sap.sailing.gwt.ui/src/main/resources/com/sap/sailing/gwt/ui/client/images/boats/class_extreme40/Extreme40_Reach_Port.png and /dev/null differ diff --git a/java/com.sap.sailing.gwt.ui/src/main/resources/com/sap/sailing/gwt/ui/client/images/boats/class_extreme40/Extreme40_Reach_Port_Selected.png b/java/com.sap.sailing.gwt.ui/src/main/resources/com/sap/sailing/gwt/ui/client/images/boats/class_extreme40/Extreme40_Reach_Port_Selected.png deleted file mode 100644 index b3a90f26f24..00000000000 Binary files a/java/com.sap.sailing.gwt.ui/src/main/resources/com/sap/sailing/gwt/ui/client/images/boats/class_extreme40/Extreme40_Reach_Port_Selected.png and /dev/null differ diff --git a/java/com.sap.sailing.gwt.ui/src/main/resources/com/sap/sailing/gwt/ui/client/images/boats/class_extreme40/Extreme40_Reach_Starboard.png b/java/com.sap.sailing.gwt.ui/src/main/resources/com/sap/sailing/gwt/ui/client/images/boats/class_extreme40/Extreme40_Reach_Starboard.png deleted file mode 100644 index 69a4856069b..00000000000 Binary files a/java/com.sap.sailing.gwt.ui/src/main/resources/com/sap/sailing/gwt/ui/client/images/boats/class_extreme40/Extreme40_Reach_Starboard.png and /dev/null differ diff --git a/java/com.sap.sailing.gwt.ui/src/main/resources/com/sap/sailing/gwt/ui/client/images/boats/class_extreme40/Extreme40_Reach_Starboard_Selected.png b/java/com.sap.sailing.gwt.ui/src/main/resources/com/sap/sailing/gwt/ui/client/images/boats/class_extreme40/Extreme40_Reach_Starboard_Selected.png deleted file mode 100644 index 6dbd687fce7..00000000000 Binary files a/java/com.sap.sailing.gwt.ui/src/main/resources/com/sap/sailing/gwt/ui/client/images/boats/class_extreme40/Extreme40_Reach_Starboard_Selected.png and /dev/null differ diff --git a/java/com.sap.sailing.gwt.ui/src/main/resources/com/sap/sailing/gwt/ui/client/images/boats/class_extreme40/Extreme40_UW_Port.png b/java/com.sap.sailing.gwt.ui/src/main/resources/com/sap/sailing/gwt/ui/client/images/boats/class_extreme40/Extreme40_UW_Port.png deleted file mode 100644 index 383b4e6331b..00000000000 Binary files a/java/com.sap.sailing.gwt.ui/src/main/resources/com/sap/sailing/gwt/ui/client/images/boats/class_extreme40/Extreme40_UW_Port.png and /dev/null differ diff --git a/java/com.sap.sailing.gwt.ui/src/main/resources/com/sap/sailing/gwt/ui/client/images/boats/class_extreme40/Extreme40_UW_Port_Selected.png b/java/com.sap.sailing.gwt.ui/src/main/resources/com/sap/sailing/gwt/ui/client/images/boats/class_extreme40/Extreme40_UW_Port_Selected.png deleted file mode 100644 index e7b72cf420f..00000000000 Binary files a/java/com.sap.sailing.gwt.ui/src/main/resources/com/sap/sailing/gwt/ui/client/images/boats/class_extreme40/Extreme40_UW_Port_Selected.png and /dev/null differ diff --git a/java/com.sap.sailing.gwt.ui/src/main/resources/com/sap/sailing/gwt/ui/client/images/boats/class_extreme40/Extreme40_UW_Starboard.png b/java/com.sap.sailing.gwt.ui/src/main/resources/com/sap/sailing/gwt/ui/client/images/boats/class_extreme40/Extreme40_UW_Starboard.png deleted file mode 100644 index 34f6e6d5b12..00000000000 Binary files a/java/com.sap.sailing.gwt.ui/src/main/resources/com/sap/sailing/gwt/ui/client/images/boats/class_extreme40/Extreme40_UW_Starboard.png and /dev/null differ diff --git a/java/com.sap.sailing.gwt.ui/src/main/resources/com/sap/sailing/gwt/ui/client/images/boats/class_extreme40/Extreme40_UW_Starboard_Selected.png b/java/com.sap.sailing.gwt.ui/src/main/resources/com/sap/sailing/gwt/ui/client/images/boats/class_extreme40/Extreme40_UW_Starboard_Selected.png deleted file mode 100644 index 8cd47c9ac5f..00000000000 Binary files a/java/com.sap.sailing.gwt.ui/src/main/resources/com/sap/sailing/gwt/ui/client/images/boats/class_extreme40/Extreme40_UW_Starboard_Selected.png and /dev/null differ diff --git a/java/com.sap.sailing.gwt.ui/src/main/resources/com/sap/sailing/gwt/ui/client/images/buoys/buoy.png b/java/com.sap.sailing.gwt.ui/src/main/resources/com/sap/sailing/gwt/ui/client/images/buoys/buoy.png deleted file mode 100644 index 903f1a84fc5..00000000000 Binary files a/java/com.sap.sailing.gwt.ui/src/main/resources/com/sap/sailing/gwt/ui/client/images/buoys/buoy.png and /dev/null differ diff --git a/java/com.sap.sailing.gwt.ui/src/main/resources/com/sap/sailing/gwt/ui/client/images/buoys/buoy_black.png b/java/com.sap.sailing.gwt.ui/src/main/resources/com/sap/sailing/gwt/ui/client/images/buoys/buoy_black.png deleted file mode 100644 index 7459b7377af..00000000000 Binary files a/java/com.sap.sailing.gwt.ui/src/main/resources/com/sap/sailing/gwt/ui/client/images/buoys/buoy_black.png and /dev/null differ diff --git a/java/com.sap.sailing.gwt.ui/src/main/resources/com/sap/sailing/gwt/ui/client/images/buoys/buoy_black_cone.png b/java/com.sap.sailing.gwt.ui/src/main/resources/com/sap/sailing/gwt/ui/client/images/buoys/buoy_black_cone.png deleted file mode 100644 index bbc057930a2..00000000000 Binary files a/java/com.sap.sailing.gwt.ui/src/main/resources/com/sap/sailing/gwt/ui/client/images/buoys/buoy_black_cone.png and /dev/null differ diff --git a/java/com.sap.sailing.gwt.ui/src/main/resources/com/sap/sailing/gwt/ui/client/images/buoys/buoy_black_finish.png b/java/com.sap.sailing.gwt.ui/src/main/resources/com/sap/sailing/gwt/ui/client/images/buoys/buoy_black_finish.png deleted file mode 100644 index 4c987f1a0b9..00000000000 Binary files a/java/com.sap.sailing.gwt.ui/src/main/resources/com/sap/sailing/gwt/ui/client/images/buoys/buoy_black_finish.png and /dev/null differ diff --git a/java/com.sap.sailing.gwt.ui/src/main/resources/com/sap/sailing/gwt/ui/client/images/buoys/buoy_dark_orange.png b/java/com.sap.sailing.gwt.ui/src/main/resources/com/sap/sailing/gwt/ui/client/images/buoys/buoy_dark_orange.png deleted file mode 100644 index 602fce6936e..00000000000 Binary files a/java/com.sap.sailing.gwt.ui/src/main/resources/com/sap/sailing/gwt/ui/client/images/buoys/buoy_dark_orange.png and /dev/null differ diff --git a/java/com.sap.sailing.gwt.ui/src/main/resources/com/sap/sailing/gwt/ui/client/images/buoys/buoy_green.png b/java/com.sap.sailing.gwt.ui/src/main/resources/com/sap/sailing/gwt/ui/client/images/buoys/buoy_green.png deleted file mode 100644 index d1bda566f82..00000000000 Binary files a/java/com.sap.sailing.gwt.ui/src/main/resources/com/sap/sailing/gwt/ui/client/images/buoys/buoy_green.png and /dev/null differ diff --git a/java/com.sap.sailing.gwt.ui/src/main/resources/com/sap/sailing/gwt/ui/client/images/buoys/buoy_grey.png b/java/com.sap.sailing.gwt.ui/src/main/resources/com/sap/sailing/gwt/ui/client/images/buoys/buoy_grey.png deleted file mode 100644 index f2b8dd54c80..00000000000 Binary files a/java/com.sap.sailing.gwt.ui/src/main/resources/com/sap/sailing/gwt/ui/client/images/buoys/buoy_grey.png and /dev/null differ diff --git a/java/com.sap.sailing.gwt.ui/src/main/resources/com/sap/sailing/gwt/ui/client/images/buoys/buoy_red.png b/java/com.sap.sailing.gwt.ui/src/main/resources/com/sap/sailing/gwt/ui/client/images/buoys/buoy_red.png deleted file mode 100644 index 24b6691013f..00000000000 Binary files a/java/com.sap.sailing.gwt.ui/src/main/resources/com/sap/sailing/gwt/ui/client/images/buoys/buoy_red.png and /dev/null differ diff --git a/java/com.sap.sailing.gwt.ui/src/main/resources/com/sap/sailing/gwt/ui/client/images/buoys/buoy_white_grey.png b/java/com.sap.sailing.gwt.ui/src/main/resources/com/sap/sailing/gwt/ui/client/images/buoys/buoy_white_grey.png deleted file mode 100644 index 16b42738538..00000000000 Binary files a/java/com.sap.sailing.gwt.ui/src/main/resources/com/sap/sailing/gwt/ui/client/images/buoys/buoy_white_grey.png and /dev/null differ diff --git a/java/com.sap.sailing.gwt.ui/src/main/resources/com/sap/sailing/gwt/ui/client/images/buoys/buoy_white_grey_cone.png b/java/com.sap.sailing.gwt.ui/src/main/resources/com/sap/sailing/gwt/ui/client/images/buoys/buoy_white_grey_cone.png deleted file mode 100644 index 8a3dac826ce..00000000000 Binary files a/java/com.sap.sailing.gwt.ui/src/main/resources/com/sap/sailing/gwt/ui/client/images/buoys/buoy_white_grey_cone.png and /dev/null differ diff --git a/java/com.sap.sailing.gwt.ui/src/main/resources/com/sap/sailing/gwt/ui/client/images/buoys/buoy_yellow.png b/java/com.sap.sailing.gwt.ui/src/main/resources/com/sap/sailing/gwt/ui/client/images/buoys/buoy_yellow.png deleted file mode 100644 index f2b3eeb3643..00000000000 Binary files a/java/com.sap.sailing.gwt.ui/src/main/resources/com/sap/sailing/gwt/ui/client/images/buoys/buoy_yellow.png and /dev/null differ diff --git a/java/com.sap.sailing.gwt.ui/src/main/resources/com/sap/sailing/gwt/ui/client/images/buoys/landmark.png b/java/com.sap.sailing.gwt.ui/src/main/resources/com/sap/sailing/gwt/ui/client/images/buoys/landmark.png deleted file mode 100644 index 25ef4094066..00000000000 Binary files a/java/com.sap.sailing.gwt.ui/src/main/resources/com/sap/sailing/gwt/ui/client/images/buoys/landmark.png and /dev/null differ diff --git a/java/com.sap.sailing.gwt.ui/src/main/resources/com/sap/sailing/gwt/ui/client/svg/boats/49er_Hull.svg b/java/com.sap.sailing.gwt.ui/src/main/resources/com/sap/sailing/gwt/ui/client/svg/boats/49er_Hull.svg new file mode 100644 index 00000000000..cec2c2bce00 --- /dev/null +++ b/java/com.sap.sailing.gwt.ui/src/main/resources/com/sap/sailing/gwt/ui/client/svg/boats/49er_Hull.svg @@ -0,0 +1,81 @@ + + + + + + + + + + + + image/svg+xml + + + + + + + + + + diff --git a/java/com.sap.sailing.gwt.ui/src/main/resources/com/sap/sailing/gwt/ui/client/svg/boats/49er_WithSails.svg b/java/com.sap.sailing.gwt.ui/src/main/resources/com/sap/sailing/gwt/ui/client/svg/boats/49er_WithSails.svg new file mode 100644 index 00000000000..82ce08cd473 --- /dev/null +++ b/java/com.sap.sailing.gwt.ui/src/main/resources/com/sap/sailing/gwt/ui/client/svg/boats/49er_WithSails.svg @@ -0,0 +1,174 @@ + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + diff --git a/java/com.sap.sailing.gwt.ui/src/main/resources/com/sap/sailing/gwt/ui/client/svg/boats/Extreme40_Hull.svg b/java/com.sap.sailing.gwt.ui/src/main/resources/com/sap/sailing/gwt/ui/client/svg/boats/Extreme40_Hull.svg new file mode 100644 index 00000000000..fe6ee77ef16 --- /dev/null +++ b/java/com.sap.sailing.gwt.ui/src/main/resources/com/sap/sailing/gwt/ui/client/svg/boats/Extreme40_Hull.svg @@ -0,0 +1,107 @@ + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + diff --git a/java/com.sap.sailing.gwt.ui/src/main/resources/com/sap/sailing/gwt/ui/client/svg/boats/Extreme40_WithSails.svg b/java/com.sap.sailing.gwt.ui/src/main/resources/com/sap/sailing/gwt/ui/client/svg/boats/Extreme40_WithSails.svg new file mode 100644 index 00000000000..b5f98400da9 --- /dev/null +++ b/java/com.sap.sailing.gwt.ui/src/main/resources/com/sap/sailing/gwt/ui/client/svg/boats/Extreme40_WithSails.svg @@ -0,0 +1,167 @@ + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/java/com.sap.sailing.gwt.ui/src/main/resources/com/sap/sailing/gwt/ui/client/svg/boats/Laser_WithSails.svg b/java/com.sap.sailing.gwt.ui/src/main/resources/com/sap/sailing/gwt/ui/client/svg/boats/Laser_WithSails.svg new file mode 100644 index 00000000000..a408ae4ca32 --- /dev/null +++ b/java/com.sap.sailing.gwt.ui/src/main/resources/com/sap/sailing/gwt/ui/client/svg/boats/Laser_WithSails.svg @@ -0,0 +1,113 @@ + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + diff --git a/java/com.sap.sailing.gwt.ui/src/main/resources/com/sap/sailing/gwt/ui/client/svg/boats/Nacra17_WithSails.svg b/java/com.sap.sailing.gwt.ui/src/main/resources/com/sap/sailing/gwt/ui/client/svg/boats/Nacra17_WithSails.svg new file mode 100644 index 00000000000..d1941f6fa7b --- /dev/null +++ b/java/com.sap.sailing.gwt.ui/src/main/resources/com/sap/sailing/gwt/ui/client/svg/boats/Nacra17_WithSails.svg @@ -0,0 +1,167 @@ + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/java/com.sap.sailing.gwt.ui/src/main/resources/com/sap/sailing/gwt/ui/client/svg/buoys/conical_buoy.svg b/java/com.sap.sailing.gwt.ui/src/main/resources/com/sap/sailing/gwt/ui/client/svg/buoys/conical_buoy.svg new file mode 100644 index 00000000000..9ba7ee31d5e --- /dev/null +++ b/java/com.sap.sailing.gwt.ui/src/main/resources/com/sap/sailing/gwt/ui/client/svg/buoys/conical_buoy.svg @@ -0,0 +1,114 @@ + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + diff --git a/java/com.sap.sailing.gwt.ui/src/main/resources/com/sap/sailing/gwt/ui/client/svg/buoys/finish_buoy.svg b/java/com.sap.sailing.gwt.ui/src/main/resources/com/sap/sailing/gwt/ui/client/svg/buoys/finish_buoy.svg new file mode 100644 index 00000000000..f20cf04911d --- /dev/null +++ b/java/com.sap.sailing.gwt.ui/src/main/resources/com/sap/sailing/gwt/ui/client/svg/buoys/finish_buoy.svg @@ -0,0 +1,150 @@ + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + diff --git a/java/com.sap.sailing.gwt.ui/src/main/resources/com/sap/sailing/gwt/ui/client/svg/buoys/landmark.svg b/java/com.sap.sailing.gwt.ui/src/main/resources/com/sap/sailing/gwt/ui/client/svg/buoys/landmark.svg new file mode 100644 index 00000000000..aca29e0ef6d --- /dev/null +++ b/java/com.sap.sailing.gwt.ui/src/main/resources/com/sap/sailing/gwt/ui/client/svg/buoys/landmark.svg @@ -0,0 +1,82 @@ + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + diff --git a/java/com.sap.sailing.gwt.ui/src/main/resources/com/sap/sailing/gwt/ui/client/svg/buoys/single_buoy.svg b/java/com.sap.sailing.gwt.ui/src/main/resources/com/sap/sailing/gwt/ui/client/svg/buoys/single_buoy.svg new file mode 100644 index 00000000000..0eeccc08a34 --- /dev/null +++ b/java/com.sap.sailing.gwt.ui/src/main/resources/com/sap/sailing/gwt/ui/client/svg/buoys/single_buoy.svg @@ -0,0 +1,113 @@ + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + diff --git a/java/com.sap.sailing.server.gateway.serialization/META-INF/MANIFEST.MF b/java/com.sap.sailing.server.gateway.serialization/META-INF/MANIFEST.MF index 914432f6280..ba43a97aacb 100644 --- a/java/com.sap.sailing.server.gateway.serialization/META-INF/MANIFEST.MF +++ b/java/com.sap.sailing.server.gateway.serialization/META-INF/MANIFEST.MF @@ -13,12 +13,10 @@ Require-Bundle: com.sap.sailing.domain.common;bundle-version="1.0.0", Export-Package: com.sap.sailing.server.gateway.deserialization, com.sap.sailing.server.gateway.deserialization.coursedata.impl, com.sap.sailing.server.gateway.deserialization.impl, - com.sap.sailing.server.gateway.deserialization.masterdata.impl, com.sap.sailing.server.gateway.deserialization.racelog.impl, com.sap.sailing.server.gateway.serialization, com.sap.sailing.server.gateway.serialization.coursedata.impl, com.sap.sailing.server.gateway.serialization.impl, - com.sap.sailing.server.gateway.serialization.masterdata.impl, com.sap.sailing.server.gateway.serialization.racegroup.impl, com.sap.sailing.server.gateway.serialization.racelog.impl, com.sap.sailing.server.gateway.serialization.racelog.tracking, diff --git a/java/com.sap.sailing.server.gateway.serialization/src/com/sap/sailing/server/gateway/deserialization/masterdata/impl/CompetitorMasterDataDeserializer.java b/java/com.sap.sailing.server.gateway.serialization/src/com/sap/sailing/server/gateway/deserialization/masterdata/impl/CompetitorMasterDataDeserializer.java deleted file mode 100644 index ee2559bf857..00000000000 --- a/java/com.sap.sailing.server.gateway.serialization/src/com/sap/sailing/server/gateway/deserialization/masterdata/impl/CompetitorMasterDataDeserializer.java +++ /dev/null @@ -1,84 +0,0 @@ -package com.sap.sailing.server.gateway.deserialization.masterdata.impl; - -import java.io.Serializable; -import java.lang.reflect.Constructor; -import java.util.UUID; - -import org.json.simple.JSONObject; - -import com.sap.sailing.domain.base.BoatClass; -import com.sap.sailing.domain.base.Competitor; -import com.sap.sailing.domain.base.SharedDomainFactory; -import com.sap.sailing.domain.base.impl.BoatImpl; -import com.sap.sailing.domain.base.impl.DynamicBoat; -import com.sap.sailing.domain.base.impl.DynamicTeam; -import com.sap.sailing.domain.common.Color; -import com.sap.sailing.domain.common.impl.RGBColor; -import com.sap.sailing.server.gateway.deserialization.JsonDeserializationException; -import com.sap.sailing.server.gateway.deserialization.JsonDeserializer; -import com.sap.sailing.server.gateway.deserialization.impl.Helpers; -import com.sap.sailing.server.gateway.serialization.masterdata.impl.CompetitorMasterDataJsonSerializer; - -public class CompetitorMasterDataDeserializer implements JsonDeserializer { - - private final JsonDeserializer boatClassDeserializer; - - private final JsonDeserializer teamDeserializer; - - private final SharedDomainFactory domainFactory; - - public CompetitorMasterDataDeserializer(JsonDeserializer boatClassDeserializer, - JsonDeserializer teamDeserializer, SharedDomainFactory domainFactory) { - this.boatClassDeserializer = boatClassDeserializer; - this.teamDeserializer = teamDeserializer; - this.domainFactory = domainFactory; - } - - @Override - public Competitor deserialize(JSONObject object) throws JsonDeserializationException { - String name = (String) object.get(CompetitorMasterDataJsonSerializer.FIELD_NAME); - String rgbDisplayColor = (String) object.get(CompetitorMasterDataJsonSerializer.FIELD_DISPLAY_COLOR); - final Color displayColor; - if (rgbDisplayColor == null || rgbDisplayColor.isEmpty()) { - displayColor = null; - } else { - displayColor = new RGBColor(rgbDisplayColor); - } - Object idClassName = object.get(CompetitorMasterDataJsonSerializer.FIELD_ID_TYPE); - Serializable id = (Serializable) object.get(CompetitorMasterDataJsonSerializer.FIELD_ID); - if (idClassName != null) { - try { - Class idClass = Class.forName((String) idClassName); - if (Number.class.isAssignableFrom(idClass)) { - Constructor constructorFromString = idClass.getConstructor(String.class); - id = (Serializable) constructorFromString.newInstance(id.toString()); - } else if (UUID.class.isAssignableFrom(idClass)) { - id = Helpers.tryUuidConversion(id); - } - } catch (Exception e) { - throw new RuntimeException(e); - } - } else { - // To ensure some kind of a backward compability. - try { - id = UUID.fromString(id.toString()); - } catch (IllegalArgumentException e) { - id = id.toString(); - } - } - DynamicBoat boat = createBoatFromJson((JSONObject) object.get(CompetitorMasterDataJsonSerializer.FIELD_BOAT)); - DynamicTeam team = teamDeserializer.deserialize((JSONObject) object.get(CompetitorMasterDataJsonSerializer.FIELD_TEAM)); - Competitor competitor; - competitor = domainFactory.getOrCreateCompetitor(id, name, displayColor, team, boat); - return competitor; - - } - - private DynamicBoat createBoatFromJson(JSONObject object) throws JsonDeserializationException { - String name = (String) object.get(CompetitorMasterDataJsonSerializer.FIELD_NAME); - String sailID = (String) object.get(CompetitorMasterDataJsonSerializer.FIELD_SAIL_ID); - BoatClass boatClass = boatClassDeserializer.deserialize((JSONObject) object.get(CompetitorMasterDataJsonSerializer.FIELD_BOAT_CLASS)); - return new BoatImpl(name, boatClass, sailID); - } - -} diff --git a/java/com.sap.sailing.server.gateway.serialization/src/com/sap/sailing/server/gateway/deserialization/masterdata/impl/EventMasterDataJsonDeserializer.java b/java/com.sap.sailing.server.gateway.serialization/src/com/sap/sailing/server/gateway/deserialization/masterdata/impl/EventMasterDataJsonDeserializer.java deleted file mode 100644 index a9353569e89..00000000000 --- a/java/com.sap.sailing.server.gateway.serialization/src/com/sap/sailing/server/gateway/deserialization/masterdata/impl/EventMasterDataJsonDeserializer.java +++ /dev/null @@ -1,47 +0,0 @@ -package com.sap.sailing.server.gateway.deserialization.masterdata.impl; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.Comparator; -import java.util.List; - -import org.json.simple.JSONArray; -import org.json.simple.JSONObject; - -import com.sap.sailing.domain.common.impl.Util.Pair; -import com.sap.sailing.domain.masterdataimport.EventMasterData; -import com.sap.sailing.server.gateway.deserialization.JsonDeserializationException; -import com.sap.sailing.server.gateway.deserialization.JsonDeserializer; -import com.sap.sailing.server.gateway.serialization.masterdata.impl.EventMasterDataJsonSerializer; - -public class EventMasterDataJsonDeserializer implements JsonDeserializer { - - @Override - public EventMasterData deserialize(JSONObject object) throws JsonDeserializationException { - String id = (String) object.get(EventMasterDataJsonSerializer.FIELD_ID); - String name = (String) object.get(EventMasterDataJsonSerializer.FIELD_NAME); - String venueName = (String) object.get(EventMasterDataJsonSerializer.FIELD_VENUE_NAME); - String pubUrl = (String) object.get(EventMasterDataJsonSerializer.FIELD_PUB_URL); - boolean isPublic = (Boolean) object.get(EventMasterDataJsonSerializer.FIELD_IS_PUBLIC); - Iterable> courseAreas = deserializeCourseAreas((JSONArray) object.get(EventMasterDataJsonSerializer.FIELD_COURSE_AREAS)); - return new EventMasterData(id, name, venueName, pubUrl, courseAreas, isPublic); - } - - private Iterable> deserializeCourseAreas(JSONArray jsonArray) { - List> courseAreas = new ArrayList>(); - for (Object courseObject : jsonArray) { - JSONObject courseJson = (JSONObject) courseObject; - String id = (String) courseJson.get(EventMasterDataJsonSerializer.FIELD_ID); - String name = (String) courseJson.get(EventMasterDataJsonSerializer.FIELD_NAME); - courseAreas.add(new Pair(id, name)); - } - Collections.sort(courseAreas, new Comparator>() { - @Override - public int compare(Pair courseArea1, Pair courseArea2) { - return courseArea1.getB().compareTo(courseArea2.getB()); - } - }); - return courseAreas; - } - -} diff --git a/java/com.sap.sailing.server.gateway.serialization/src/com/sap/sailing/server/gateway/deserialization/masterdata/impl/LeaderboardGroupMasterDataJsonDeserializer.java b/java/com.sap.sailing.server.gateway.serialization/src/com/sap/sailing/server/gateway/deserialization/masterdata/impl/LeaderboardGroupMasterDataJsonDeserializer.java deleted file mode 100644 index 54234adc38c..00000000000 --- a/java/com.sap.sailing.server.gateway.serialization/src/com/sap/sailing/server/gateway/deserialization/masterdata/impl/LeaderboardGroupMasterDataJsonDeserializer.java +++ /dev/null @@ -1,133 +0,0 @@ -package com.sap.sailing.server.gateway.deserialization.masterdata.impl; - -import java.io.Serializable; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Set; - -import org.json.simple.JSONArray; -import org.json.simple.JSONObject; - -import com.sap.sailing.domain.base.BoatClass; -import com.sap.sailing.domain.base.Competitor; -import com.sap.sailing.domain.base.DomainFactory; -import com.sap.sailing.domain.base.Fleet; -import com.sap.sailing.domain.base.LeaderboardMasterData; -import com.sap.sailing.domain.base.Nationality; -import com.sap.sailing.domain.base.configuration.RegattaConfiguration; -import com.sap.sailing.domain.base.impl.DynamicPerson; -import com.sap.sailing.domain.base.impl.DynamicTeam; -import com.sap.sailing.domain.common.Color; -import com.sap.sailing.domain.leaderboard.ScoringScheme; -import com.sap.sailing.domain.masterdataimport.EventMasterData; -import com.sap.sailing.domain.masterdataimport.LeaderboardGroupMasterData; -import com.sap.sailing.domain.masterdataimport.RaceColumnMasterData; -import com.sap.sailing.domain.masterdataimport.RegattaMasterData; -import com.sap.sailing.domain.racelog.RaceLogEvent; -import com.sap.sailing.server.gateway.deserialization.JsonDeserializationException; -import com.sap.sailing.server.gateway.deserialization.JsonDeserializer; -import com.sap.sailing.server.gateway.deserialization.impl.BoatClassJsonDeserializer; -import com.sap.sailing.server.gateway.deserialization.impl.ColorDeserializer; -import com.sap.sailing.server.gateway.deserialization.impl.FleetDeserializer; -import com.sap.sailing.server.gateway.deserialization.impl.NationalityJsonDeserializer; -import com.sap.sailing.server.gateway.deserialization.impl.PersonJsonDeserializer; -import com.sap.sailing.server.gateway.deserialization.impl.RegattaConfigurationJsonDeserializer; -import com.sap.sailing.server.gateway.deserialization.impl.TeamJsonDeserializer; -import com.sap.sailing.server.gateway.deserialization.racelog.impl.RaceLogEventDeserializer; -import com.sap.sailing.server.gateway.serialization.masterdata.impl.LeaderboardGroupMasterDataJsonSerializer; - -public class LeaderboardGroupMasterDataJsonDeserializer implements JsonDeserializer { - - private final JsonDeserializer leaderboardDeserializer; - - private final JsonDeserializer eventDeserializer; - - private final JsonDeserializer regattaDeserializer; - - private final DomainFactory domainFactory; - - public static JsonDeserializer create(DomainFactory domainFactory) { - JsonDeserializer boatClassDeserializer = new BoatClassJsonDeserializer(domainFactory); - JsonDeserializer nationalityDeserializer = new NationalityJsonDeserializer(domainFactory); - JsonDeserializer personDeserializer = new PersonJsonDeserializer(nationalityDeserializer); - JsonDeserializer teamDeserializer = new TeamJsonDeserializer(personDeserializer); - JsonDeserializer competitorDeserializer = new CompetitorMasterDataDeserializer( - boatClassDeserializer, teamDeserializer, domainFactory); - JsonDeserializer raceLogEventDeserializer = RaceLogEventDeserializer.create(domainFactory); - JsonDeserializer leaderboardDeserializer = new LeaderboardMasterDataJsonDeserializer( - competitorDeserializer, domainFactory, raceLogEventDeserializer); - JsonDeserializer eventDeserializer = new EventMasterDataJsonDeserializer(); - JsonDeserializer colorDeserializer = new ColorDeserializer(); - JsonDeserializer fleetDeserializer = new FleetDeserializer(colorDeserializer); - JsonDeserializer configurationDeserializer = RegattaConfigurationJsonDeserializer.create(); - JsonDeserializer raceColumnDeserializer = new RaceColumnMasterDataJsonDeserializer(); - JsonDeserializer regattaDeserializer = new RegattaMasterDataJsonDeserializer( - fleetDeserializer, raceColumnDeserializer, configurationDeserializer); - JsonDeserializer leaderboardGroupMasterDataDeserializer = new LeaderboardGroupMasterDataJsonDeserializer( - leaderboardDeserializer, eventDeserializer, regattaDeserializer, domainFactory); - return leaderboardGroupMasterDataDeserializer; - } - - public LeaderboardGroupMasterDataJsonDeserializer(JsonDeserializer leaderboardDeserializer, - JsonDeserializer eventDeserializer, JsonDeserializer regattaDeserializer, DomainFactory domainFactory) { - this.leaderboardDeserializer = leaderboardDeserializer; - this.eventDeserializer = eventDeserializer; - this.regattaDeserializer = regattaDeserializer; - this.domainFactory = domainFactory; - } - - @Override - public LeaderboardGroupMasterData deserialize(JSONObject object) throws JsonDeserializationException { - List leaderboards = new ArrayList(); - JSONArray leaderboardsJson = (JSONArray) object.get(LeaderboardGroupMasterDataJsonSerializer.FIELD_LEADERBOARDS); - for (Object leaderboardObject : leaderboardsJson) { - JSONObject leaderboardJson = (JSONObject) leaderboardObject; - leaderboards.add(leaderboardDeserializer.deserialize(leaderboardJson)); - } - JSONArray eventsJson = (JSONArray) object.get(LeaderboardGroupMasterDataJsonSerializer.FIELD_EVENTS); - Set events = new HashSet(); - for (Object eventObject : eventsJson) { - JSONObject eventJson = (JSONObject) eventObject; - events.add(eventDeserializer.deserialize(eventJson)); - } - JSONArray regattasJson = (JSONArray) object.get(LeaderboardGroupMasterDataJsonSerializer.FIELD_REGATTAS); - Set regattas = new HashSet(); - for (Object regattaObject : regattasJson) { - JSONObject regattaJson = (JSONObject) regattaObject; - regattas.add(regattaDeserializer.deserialize(regattaJson)); - } - String name = (String) object.get(LeaderboardGroupMasterDataJsonSerializer.FIELD_NAME); - String description = (String) object.get(LeaderboardGroupMasterDataJsonSerializer.FIELD_DESCRIPTION); - boolean displayGroupsReverse = (Boolean) object.get(LeaderboardGroupMasterDataJsonSerializer.FIELD_DISPLAY_GROUPS_REVERSE); - Boolean hasOverallLeaderboard = (Boolean) object.get(LeaderboardGroupMasterDataJsonSerializer.FIELD_HAS_OVERALL_LEADERBOARD); - if (hasOverallLeaderboard == null) { - hasOverallLeaderboard = false; - } - ScoringScheme overallLeaderboardScoringScheme = !hasOverallLeaderboard ? null : LeaderboardMasterDataJsonDeserializer.deserializeScoringScheme((JSONObject) object.get(LeaderboardGroupMasterDataJsonSerializer.FIELD_OVERALL_LEADERBOARD_SCORING_SCHEME), domainFactory); - int[] overallLeaderboardResultDiscardingThresholds = !hasOverallLeaderboard ? null : LeaderboardMasterDataJsonDeserializer.deserializeResultDesicardingRule((JSONObject) object.get(LeaderboardGroupMasterDataJsonSerializer.FIELD_OVERALL_LEADERBOARD_DISCARDING_THRESHOLDS)); - Map metaColumnsWithFactors = !hasOverallLeaderboard ? null : deserializeMetaColumnsWithFactor((JSONArray) object.get(LeaderboardGroupMasterDataJsonSerializer.FIELD_OVERALL_LEADERBOARD_META_COLUMNS)); - List overallLeaderboardSuppressedCompetitorsIds = !hasOverallLeaderboard ? null - : LeaderboardMasterDataJsonDeserializer - .deserializeSuppressedCompetitors((JSONArray) object - .get(LeaderboardGroupMasterDataJsonSerializer.FIELD_OVERALL_LEADERBOARD_SUPPRESSED_COMPETITORS)); - return new LeaderboardGroupMasterData(name, description, displayGroupsReverse, hasOverallLeaderboard, overallLeaderboardScoringScheme, overallLeaderboardResultDiscardingThresholds, overallLeaderboardSuppressedCompetitorsIds, metaColumnsWithFactors, leaderboards, events, regattas); - } - - private Map deserializeMetaColumnsWithFactor(JSONArray jsonArray) { - Map metaColumnsWithFactors = new HashMap(); - if (jsonArray != null) { - for (Object obj : jsonArray) { - JSONObject jsonObj = (JSONObject) obj; - String name = (String) jsonObj.get(LeaderboardGroupMasterDataJsonSerializer.FIELD_NAME); - Double explicitFactor = (Double) jsonObj - .get(LeaderboardGroupMasterDataJsonSerializer.FIELD_EXPLICIT_FACTOR); - metaColumnsWithFactors.put(name, explicitFactor); - } - } - return metaColumnsWithFactors; - } - -} diff --git a/java/com.sap.sailing.server.gateway.serialization/src/com/sap/sailing/server/gateway/deserialization/masterdata/impl/LeaderboardMasterDataJsonDeserializer.java b/java/com.sap.sailing.server.gateway.serialization/src/com/sap/sailing/server/gateway/deserialization/masterdata/impl/LeaderboardMasterDataJsonDeserializer.java deleted file mode 100644 index 2d39a69e570..00000000000 --- a/java/com.sap.sailing.server.gateway.serialization/src/com/sap/sailing/server/gateway/deserialization/masterdata/impl/LeaderboardMasterDataJsonDeserializer.java +++ /dev/null @@ -1,303 +0,0 @@ -package com.sap.sailing.server.gateway.deserialization.masterdata.impl; - -import java.io.Serializable; -import java.lang.reflect.Constructor; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.UUID; - -import org.json.simple.JSONArray; -import org.json.simple.JSONObject; - -import com.sap.sailing.domain.base.Competitor; -import com.sap.sailing.domain.base.DomainFactory; -import com.sap.sailing.domain.base.LeaderboardMasterData; -import com.sap.sailing.domain.common.ScoringSchemeType; -import com.sap.sailing.domain.leaderboard.ScoringScheme; -import com.sap.sailing.domain.masterdataimport.FlexibleLeaderboardMasterData; -import com.sap.sailing.domain.masterdataimport.RaceColumnMasterData; -import com.sap.sailing.domain.masterdataimport.RegattaLeaderboardMasterData; -import com.sap.sailing.domain.masterdataimport.ScoreCorrectionMasterData; -import com.sap.sailing.domain.masterdataimport.SingleScoreCorrectionMasterData; -import com.sap.sailing.domain.racelog.RaceLogEvent; -import com.sap.sailing.server.gateway.deserialization.JsonDeserializationException; -import com.sap.sailing.server.gateway.deserialization.JsonDeserializer; -import com.sap.sailing.server.gateway.deserialization.impl.Helpers; -import com.sap.sailing.server.gateway.serialization.masterdata.impl.LeaderboardMasterDataJsonSerializer; - -public class LeaderboardMasterDataJsonDeserializer implements JsonDeserializer { - - private final JsonDeserializer competitorDeserializer; - private final DomainFactory domainFactory; - private final JsonDeserializer raceLogEventDeseriaizer; - private final JsonDeserializer raceColumnDeserializer = new RaceColumnMasterDataJsonDeserializer(); - - public LeaderboardMasterDataJsonDeserializer(JsonDeserializer competitorDeserializer, - DomainFactory domainFactory, JsonDeserializer raceLogEventDeseriaizer) { - this.competitorDeserializer = competitorDeserializer; - this.domainFactory = domainFactory; - this.raceLogEventDeseriaizer = raceLogEventDeseriaizer; - } - - @Override - public LeaderboardMasterData deserialize(JSONObject object) throws JsonDeserializationException { - if (object == null) { - return null; - } - String name = (String) object.get(LeaderboardMasterDataJsonSerializer.FIELD_NAME); - String displayName = (String) object.get(LeaderboardMasterDataJsonSerializer.FIELD_DISPLAY_NAME); - Map displayNamesByCompetitorId = deserializeCompetitorDisplayNames((JSONArray) object - .get(LeaderboardMasterDataJsonSerializer.FIELD_COMPETITOR_DISPLAY_NAMES)); - ScoreCorrectionMasterData scoreCorrection = deserializeScoreCorrection((JSONObject) object - .get(LeaderboardMasterDataJsonSerializer.FIELD_SCORE_CORRECTION)); - Map carriedPoints = deserializeCarriedPoints((JSONArray) object - .get(LeaderboardMasterDataJsonSerializer.FIELD_CARRIED_POINTS)); - List suppressedCompetitors = deserializeSuppressedCompetitors((JSONArray) object - .get(LeaderboardMasterDataJsonSerializer.FIELD_SUPPRESSED_COMPETITORS)); - Map>> raceLogEvents = deserializeRaceLogEvents((JSONArray) object - .get(LeaderboardMasterDataJsonSerializer.FIELD_RACE_LOG_EVENTS)); - int[] resultDiscardingRule = deserializeResultDesicardingRule((JSONObject) object - .get(LeaderboardMasterDataJsonSerializer.FIELD_RESULT_DISCARDING_RULE)); - boolean isRegattaLeaderBoard = (Boolean) object - .get(LeaderboardMasterDataJsonSerializer.FIELD_REGATTA_LEADERBOARD); - - Map competitorsById = new HashMap(); - JSONArray competitorsJsonArray = (JSONArray) object.get(LeaderboardMasterDataJsonSerializer.FIELD_COMPETITORS); - - for (Object obj : competitorsJsonArray) { - JSONObject competitorJson = (JSONObject) obj; - Competitor deserializedCompetitor = competitorDeserializer.deserialize(competitorJson); - competitorsById.put(deserializedCompetitor, deserializedCompetitor); - } - final LeaderboardMasterData result; - if (isRegattaLeaderBoard) { - String regattaName = (String) object.get(LeaderboardMasterDataJsonSerializer.FIELD_REGATTA_NAME); - result = new RegattaLeaderboardMasterData(name, displayName, resultDiscardingRule, competitorsById, - scoreCorrection, regattaName, carriedPoints, suppressedCompetitors, displayNamesByCompetitorId, - raceLogEvents); - - } else { - ScoringScheme scoringScheme = deserializeScoringScheme((JSONObject) object - .get(LeaderboardMasterDataJsonSerializer.FIELD_SCORING_SCHEME), domainFactory); - String courseAreaId = deserializeCourseAreaId((JSONObject) object - .get(LeaderboardMasterDataJsonSerializer.FIELD_COURSE_AREA)); - List raceColumns = deserializeRaceColumns((JSONArray) object - .get(LeaderboardMasterDataJsonSerializer.FIELD_RACE_COLUMNS)); - result = new FlexibleLeaderboardMasterData(name, displayName, resultDiscardingRule, competitorsById, - scoreCorrection, scoringScheme, courseAreaId, raceColumns, carriedPoints, suppressedCompetitors, - displayNamesByCompetitorId, raceLogEvents); - } - return result; - } - - private Map>> deserializeRaceLogEvents(JSONArray jsonArray) { - Map>> raceLogEvents = new HashMap>>(); - for (Object obj : jsonArray) { - JSONObject json = (JSONObject) obj; - String raceColumnName = (String) json.get(LeaderboardMasterDataJsonSerializer.FIELD_RACE_COLUMN_NAME); - Map> perFleet = deserializeRaceLogEventsForFleets((JSONArray) json - .get(LeaderboardMasterDataJsonSerializer.FIELD_FLEETS)); - raceLogEvents.put(raceColumnName, perFleet); - } - return raceLogEvents; - } - - private Map> deserializeRaceLogEventsForFleets(JSONArray fleets) { - Map> perFleet = new HashMap>(); - for (Object obj : fleets) { - JSONObject json = (JSONObject) obj; - String fleetName = (String) json.get(LeaderboardMasterDataJsonSerializer.FIELD_FLEET_NAME); - List logEvents = deserializeRaceLogEventArray((JSONArray) json - .get(LeaderboardMasterDataJsonSerializer.FIELD_RACE_LOG_EVENTS)); - perFleet.put(fleetName, logEvents); - } - return perFleet; - } - - private List deserializeRaceLogEventArray(JSONArray jsonArray) { - List logEvents = new ArrayList(); - for (Object obj : jsonArray) { - JSONObject json = (JSONObject) obj; - try { - logEvents.add(raceLogEventDeseriaizer.deserialize(json)); - } catch (JsonDeserializationException e) { - // TODO Exception handling - e.printStackTrace(); - } - } - return logEvents; - } - - private Map deserializeCompetitorDisplayNames(JSONArray jsonArray) { - Map result = new HashMap(); - for (Object obj : jsonArray) { - JSONObject json = (JSONObject) obj; - Serializable id; - try { - JSONObject object = (JSONObject) obj; - id = extractId(object); - } catch (Exception e) { - // Backward compability - id = (String) obj; - } - String displayName = (String) json.get(LeaderboardMasterDataJsonSerializer.FIELD_DISPLAY_NAME); - result.put(id, displayName); - } - return result; - } - - public static List deserializeSuppressedCompetitors(JSONArray jsonArray) { - List ids = new ArrayList(); - if (jsonArray != null) { - for (Object obj : jsonArray) { - Serializable id; - try { - JSONObject object = (JSONObject) obj; - id = extractId(object); - } catch (Exception e) { - // Backward compability - id = (String) obj; - } - ids.add(id); - } - } - return ids; - } - - private static Serializable extractId(JSONObject object) { - Serializable id; - Object idClassName = object.get(LeaderboardMasterDataJsonSerializer.FIELD_TYPE); - id = (Serializable) object.get(LeaderboardMasterDataJsonSerializer.FIELD_COMPETITOR_ID); - if (idClassName != null) { - try { - Class idClass = Class.forName((String) idClassName); - if (Number.class.isAssignableFrom(idClass)) { - Constructor constructorFromString = idClass.getConstructor(String.class); - id = (Serializable) constructorFromString.newInstance(id.toString()); - } else if (UUID.class.isAssignableFrom(idClass)) { - id = Helpers.tryUuidConversion(id); - } - } catch (Exception e) { - throw new RuntimeException(e); - } - } else { - // To ensure some kind of a backward compability. - try { - id = UUID.fromString(id.toString()); - } catch (IllegalArgumentException e) { - id = id.toString(); - } - } - return id; - } - - private Map deserializeCarriedPoints(JSONArray jsonArray) { - Map carriedPoints = new HashMap(); - for (Object obj : jsonArray) { - JSONObject jsonCarriedPoints = (JSONObject) obj; - Serializable id; - try { - id = extractId(jsonCarriedPoints); - } catch (Exception e) { - // Backward compability - id = (String) obj; - } - Double carried = (Double) jsonCarriedPoints.get(LeaderboardMasterDataJsonSerializer.FIELD_CARRIED); - carriedPoints.put(id, carried); - } - return carriedPoints; - } - - private ScoreCorrectionMasterData deserializeScoreCorrection(JSONObject jsonObject) { - String comment = (String) jsonObject.get(LeaderboardMasterDataJsonSerializer.FIELD_COMMENT); - Object timeObject = jsonObject.get(LeaderboardMasterDataJsonSerializer.FIELD_TIME_POINT); - Long timepointMillis = null; - if (timeObject != null) { - timepointMillis = (Long) timeObject; - } - - JSONArray forRaceColumns = (JSONArray) jsonObject - .get(LeaderboardMasterDataJsonSerializer.FIELD_FOR_RACE_COLUMNS); - Map> correctionForRaceColumns = new HashMap>(); - for (Object obj : forRaceColumns) { - JSONObject json = (JSONObject) obj; - String raceColumnName = (String) json.get(LeaderboardMasterDataJsonSerializer.FIELD_RACE_COLUMN_NAME); - Iterable correctionsForRaceColumn = deserializeScoreCorrectionForRaceColumn((JSONArray) json - .get(LeaderboardMasterDataJsonSerializer.FIELD_FOR_COMPETITORS)); - correctionForRaceColumns.put(raceColumnName, correctionsForRaceColumn); - } - return new ScoreCorrectionMasterData(comment, timepointMillis, correctionForRaceColumns); - } - - private Iterable deserializeScoreCorrectionForRaceColumn(JSONArray jsonArray) { - Set result = new HashSet(); - for (Object obj : jsonArray) { - JSONObject json = (JSONObject) obj; - result.add(deserializeScoreCorrectionForCompetitor(json)); - } - return result; - } - - private SingleScoreCorrectionMasterData deserializeScoreCorrectionForCompetitor(JSONObject json) { - Serializable competitorId = extractId(json); - Double explicitScoreCorrection = ((Double) json - .get(LeaderboardMasterDataJsonSerializer.FIELD_EXPLICIT_SCORE_CORRECTION)); - String maxPointsReason = (String) json.get(LeaderboardMasterDataJsonSerializer.FIELD_MAX_POINTS_REASON); - return new SingleScoreCorrectionMasterData(competitorId, explicitScoreCorrection, maxPointsReason); - } - - private List deserializeRaceColumns(JSONArray array) throws JsonDeserializationException { - List columns = new ArrayList(); - for (Object columnObj : array) { - JSONObject columnJson = (JSONObject) columnObj; - columns.add(raceColumnDeserializer.deserialize(columnJson)); - } - return columns; - } - - private String deserializeCourseAreaId(JSONObject jsonObject) { - if (jsonObject == null) { - return null; - } - String id = (String) jsonObject.get(LeaderboardMasterDataJsonSerializer.FIELD_ID); - return id; - - } - - public static ScoringScheme deserializeScoringScheme(JSONObject jsonObject, DomainFactory domainFactory) { - final ScoringScheme result; - if (jsonObject == null) { - result = null; - } else { - String type = (String) jsonObject.get(LeaderboardMasterDataJsonSerializer.FIELD_TYPE); - if (type == null) { - result = null; - } else { - result = domainFactory.createScoringScheme(ScoringSchemeType.valueOf(type)); - } - } - return result; - } - - public static int[] deserializeResultDesicardingRule(JSONObject jsonObject) { - final int[] result; - if (jsonObject == null) { - result = null; - } else { - JSONArray indeces = (JSONArray) jsonObject.get(LeaderboardMasterDataJsonSerializer.FIELD_INDICES); - if (indeces == null) { - result = null; - } else { - result = new int[indeces.size()]; - for (int i = 0; i < result.length; i++) { - result[i] = ((Long) indeces.get(i)).intValue(); - } - } - } - return result; - } -} diff --git a/java/com.sap.sailing.server.gateway.serialization/src/com/sap/sailing/server/gateway/deserialization/masterdata/impl/MediaTrackJsonDeserializer.java b/java/com.sap.sailing.server.gateway.serialization/src/com/sap/sailing/server/gateway/deserialization/masterdata/impl/MediaTrackJsonDeserializer.java deleted file mode 100644 index e0ee293ca34..00000000000 --- a/java/com.sap.sailing.server.gateway.serialization/src/com/sap/sailing/server/gateway/deserialization/masterdata/impl/MediaTrackJsonDeserializer.java +++ /dev/null @@ -1,31 +0,0 @@ -package com.sap.sailing.server.gateway.deserialization.masterdata.impl; - -import java.util.Date; - -import org.json.simple.JSONObject; - -import com.sap.sailing.domain.common.media.MediaTrack; -import com.sap.sailing.server.gateway.deserialization.JsonDeserializationException; -import com.sap.sailing.server.gateway.deserialization.JsonDeserializer; -import com.sap.sailing.server.gateway.serialization.masterdata.impl.MediaTrackJsonSerializer; - -public class MediaTrackJsonDeserializer implements JsonDeserializer { - - @Override - public MediaTrack deserialize(JSONObject object) throws JsonDeserializationException { - String dbId = (String) object.get(MediaTrackJsonSerializer.FIELD_DB_ID); - int durationInMillis = ((Long) object.get(MediaTrackJsonSerializer.FIELD_DURATION)).intValue(); - MediaTrack.MimeType mimeType = MediaTrack.MimeType.valueOf((String) object - .get(MediaTrackJsonSerializer.FIELD_MIME_TYPE)); - long startTimeInMillis = (Long) object.get(MediaTrackJsonSerializer.FIELD_START_TIME); - Date startTime = new Date(startTimeInMillis); - MediaTrack.Status status = MediaTrack.Status - .valueOf((String) object.get(MediaTrackJsonSerializer.FIELD_STATUS)); - String title = (String) object.get(MediaTrackJsonSerializer.FIELD_TITLE); - String url = (String) object.get(MediaTrackJsonSerializer.FIELD_URL); - MediaTrack mediaTrack = new MediaTrack(dbId, title, url, startTime, durationInMillis, mimeType); - mediaTrack.status = status; - return mediaTrack; - } - -} diff --git a/java/com.sap.sailing.server.gateway.serialization/src/com/sap/sailing/server/gateway/deserialization/masterdata/impl/RaceColumnMasterDataJsonDeserializer.java b/java/com.sap.sailing.server.gateway.serialization/src/com/sap/sailing/server/gateway/deserialization/masterdata/impl/RaceColumnMasterDataJsonDeserializer.java deleted file mode 100644 index 06bc2cd3ba7..00000000000 --- a/java/com.sap.sailing.server.gateway.serialization/src/com/sap/sailing/server/gateway/deserialization/masterdata/impl/RaceColumnMasterDataJsonDeserializer.java +++ /dev/null @@ -1,60 +0,0 @@ -package com.sap.sailing.server.gateway.deserialization.masterdata.impl; - -import java.util.HashMap; -import java.util.HashSet; -import java.util.Map; -import java.util.Set; - -import org.json.simple.JSONArray; -import org.json.simple.JSONObject; - -import com.sap.sailing.domain.common.RaceIdentifier; -import com.sap.sailing.domain.common.RegattaNameAndRaceName; -import com.sap.sailing.domain.masterdataimport.RaceColumnMasterData; -import com.sap.sailing.domain.masterdataimport.WindTrackMasterData; -import com.sap.sailing.server.gateway.deserialization.JsonDeserializationException; -import com.sap.sailing.server.gateway.deserialization.JsonDeserializer; -import com.sap.sailing.server.gateway.serialization.masterdata.impl.RaceColumnMasterDataJsonSerializer; - -public class RaceColumnMasterDataJsonDeserializer implements JsonDeserializer { - - private final JsonDeserializer windtrackDeserializer; - - public RaceColumnMasterDataJsonDeserializer() { - windtrackDeserializer = new WindTrackMasterDataJsonDeserializer(); - } - - @Override - public RaceColumnMasterData deserialize(JSONObject columnJson) throws JsonDeserializationException { - String columnName = (String) columnJson - .get(RaceColumnMasterDataJsonSerializer.FIELD_NAME); - Boolean medal = (Boolean) columnJson - .get(RaceColumnMasterDataJsonSerializer.FIELD_MEDAL_RACE); - Map raceIdentifiers = new HashMap(); - Double factor = (Double) columnJson.get(RaceColumnMasterDataJsonSerializer.FIELD_FACTOR); - JSONArray jsonRaceIdentifiers = (JSONArray) columnJson.get(RaceColumnMasterDataJsonSerializer.FIELD_RACE_IDENTIFIERS); - for (Object raceIdentifierObject : jsonRaceIdentifiers) { - JSONObject jsonRaceIdentifier = (JSONObject) raceIdentifierObject; - String fleetName = (String) jsonRaceIdentifier.get(RaceColumnMasterDataJsonSerializer.FIELD_FLEET_NAME); - String raceName = (String) jsonRaceIdentifier.get(RaceColumnMasterDataJsonSerializer.FIELD_RACE_NAME); - String regattaName = (String) jsonRaceIdentifier.get(RaceColumnMasterDataJsonSerializer.FIELD_REGATTA_NAME); - RaceIdentifier raceIdentifier = new RegattaNameAndRaceName(regattaName, raceName); - raceIdentifiers.put(fleetName, raceIdentifier); - } - JSONArray windJson = (JSONArray) columnJson.get(RaceColumnMasterDataJsonSerializer.FIELD_WIND); - Set windTracks = null; - if (windJson != null) { - windTracks = deserializeWindTracks(windJson); - } - return new RaceColumnMasterData(columnName, medal, raceIdentifiers, factor, windTracks); - } - - private Set deserializeWindTracks(JSONArray windJson) throws JsonDeserializationException { - Set tracks = new HashSet(); - for (Object obj : windJson) { - JSONObject json = (JSONObject) obj; - tracks.add(windtrackDeserializer.deserialize(json)); - } - return tracks; - } -} diff --git a/java/com.sap.sailing.server.gateway.serialization/src/com/sap/sailing/server/gateway/deserialization/masterdata/impl/RegattaMasterDataJsonDeserializer.java b/java/com.sap.sailing.server.gateway.serialization/src/com/sap/sailing/server/gateway/deserialization/masterdata/impl/RegattaMasterDataJsonDeserializer.java deleted file mode 100644 index 2e7be0956cc..00000000000 --- a/java/com.sap.sailing.server.gateway.serialization/src/com/sap/sailing/server/gateway/deserialization/masterdata/impl/RegattaMasterDataJsonDeserializer.java +++ /dev/null @@ -1,144 +0,0 @@ -package com.sap.sailing.server.gateway.deserialization.masterdata.impl; - -import java.io.Serializable; -import java.lang.reflect.Constructor; -import java.util.ArrayList; -import java.util.HashSet; -import java.util.List; -import java.util.Set; -import java.util.UUID; - -import org.json.simple.JSONArray; -import org.json.simple.JSONObject; - -import com.sap.sailing.domain.base.Fleet; -import com.sap.sailing.domain.base.configuration.RegattaConfiguration; -import com.sap.sailing.domain.masterdataimport.RaceColumnMasterData; -import com.sap.sailing.domain.masterdataimport.RegattaMasterData; -import com.sap.sailing.domain.masterdataimport.SeriesMasterData; -import com.sap.sailing.server.gateway.deserialization.JsonDeserializationException; -import com.sap.sailing.server.gateway.deserialization.JsonDeserializer; -import com.sap.sailing.server.gateway.deserialization.impl.Helpers; -import com.sap.sailing.server.gateway.serialization.masterdata.impl.LeaderboardMasterDataJsonSerializer; -import com.sap.sailing.server.gateway.serialization.masterdata.impl.RegattaMasterDataJsonSerializer; - -public class RegattaMasterDataJsonDeserializer implements JsonDeserializer { - - private final JsonDeserializer fleetDeserializer; - private final JsonDeserializer raceColumnDeserializer; - private final JsonDeserializer configurationDeserializer; - - public RegattaMasterDataJsonDeserializer(JsonDeserializer fleetDeserializer, JsonDeserializer raceColumnDeserializer, - JsonDeserializer configurationDeserializer) { - this.fleetDeserializer = fleetDeserializer; - this.raceColumnDeserializer = raceColumnDeserializer; - this.configurationDeserializer = configurationDeserializer; - } - - @Override - public RegattaMasterData deserialize(JSONObject object) throws JsonDeserializationException { - Object idClassName = object.get(RegattaMasterDataJsonSerializer.FIELD_ID_TYPE); - Serializable id = (Serializable) object.get(RegattaMasterDataJsonSerializer.FIELD_ID); - if (idClassName != null) { - try { - Class idClass = Class.forName((String) idClassName); - if (Number.class.isAssignableFrom(idClass)) { - Constructor constructorFromString = idClass.getConstructor(String.class); - id = (Serializable) constructorFromString.newInstance(id.toString()); - } else if (UUID.class.isAssignableFrom(idClass)) { - id = Helpers.tryUuidConversion(id); - } - } catch (Exception e) { - throw new RuntimeException(e); - } - } else { - // To ensure some kind of a backward compability. - try { - id = UUID.fromString(id.toString()); - } catch (IllegalArgumentException e) { - id = id.toString(); - } - } - String regattaName = (String) object.get(RegattaMasterDataJsonSerializer.FIELD_REGATTA_NAME); - String baseName = (String) object.get(RegattaMasterDataJsonSerializer.FIELD_BASE_NAME); - String defaultCourseAreaId = (String) object.get(RegattaMasterDataJsonSerializer.FIELD_DEFAULT_COURSE_AREA_ID); - String boatClassName = (String) object.get(RegattaMasterDataJsonSerializer.FIELD_BOAT_CLASS_NAME); - String scoringSchemeType = (String) object.get(RegattaMasterDataJsonSerializer.FIELD_SCORING_SCHEME_TYPE); - boolean isPersistent = (Boolean) object.get(RegattaMasterDataJsonSerializer.FIELD_IS_PERSISTENT); - Iterable series = deserializeSeries((JSONArray) object.get(RegattaMasterDataJsonSerializer.FIELD_SERIES)); - Iterable raceIdsAsStrings = deserializeRaceIds((JSONArray) object.get(RegattaMasterDataJsonSerializer.FIELD_REGATTA_RACE_IDS)); - - RegattaConfiguration regattaConfiguration = null; - if (object.containsKey(RegattaMasterDataJsonSerializer.FIELD_REGATTA_CONFIGURATION)) { - regattaConfiguration = configurationDeserializer.deserialize( - Helpers.getNestedObjectSafe(object, RegattaMasterDataJsonSerializer.FIELD_REGATTA_CONFIGURATION)); - } - - return new RegattaMasterData(id, baseName, defaultCourseAreaId, boatClassName, scoringSchemeType, - series, isPersistent, regattaName, raceIdsAsStrings, regattaConfiguration); - } - - private Iterable deserializeRaceIds(JSONArray jsonArray) { - Set raceIdStrings = new HashSet(); - for (Object obj : jsonArray) { - String id = (String) obj; - raceIdStrings.add(id); - } - return raceIdStrings; - } - - private Iterable deserializeSeries(JSONArray jsonArray) throws JsonDeserializationException { - List series = new ArrayList(); - for (Object seriesObject : jsonArray) { - JSONObject seriesJson = (JSONObject) seriesObject; - String name = (String) seriesJson.get(RegattaMasterDataJsonSerializer.FIELD_NAME); - boolean isMedal = (Boolean) seriesJson.get(RegattaMasterDataJsonSerializer.FIELD_IS_MEDAL); - Iterable fleets = deserializeFleets((JSONArray) seriesJson.get(RegattaMasterDataJsonSerializer.FIELD_FLEETS)); - Iterable raceColumnNames = deserializeRaceColumnNames((JSONArray) seriesJson.get(RegattaMasterDataJsonSerializer.FIELD_RACE_COLUMNS)); - int[] discardingRule = deserializeResultDesicardingRule((JSONObject) seriesJson.get(RegattaMasterDataJsonSerializer.FIELD_RESULT_DISCARDING_RULE)); - series.add(new SeriesMasterData(name, isMedal, fleets, raceColumnNames, discardingRule)); - } - - return series; - } - - private Iterable deserializeRaceColumnNames(JSONArray jsonArray) throws JsonDeserializationException { - List raceColumns = new ArrayList(); - for (Object raceColumnObject : jsonArray) { - JSONObject jsonRaceColumn = (JSONObject) raceColumnObject; - raceColumns.add(raceColumnDeserializer.deserialize(jsonRaceColumn)); - } - return raceColumns; - } - - private Iterable deserializeFleets(JSONArray jsonArray) { - List fleets = new ArrayList(); - for (Object fleetObject : jsonArray) { - JSONObject fleetJson = (JSONObject) fleetObject; - try { - fleets.add(fleetDeserializer.deserialize(fleetJson)); - } catch (JsonDeserializationException e) { - // TODO exception handling - e.printStackTrace(); - } - - } - return fleets; - } - - private int[] deserializeResultDesicardingRule(JSONObject jsonObject) { - if (jsonObject == null) { - return null; - } - JSONArray indeces = (JSONArray) jsonObject.get(LeaderboardMasterDataJsonSerializer.FIELD_INDICES); - if (indeces == null) { - return null; - } - int[] result = new int[indeces.size()]; - for (int i = 0; i < result.length; i++) { - result[i] = ((Long) indeces.get(i)).intValue(); - } - return result; - } - -} diff --git a/java/com.sap.sailing.server.gateway.serialization/src/com/sap/sailing/server/gateway/deserialization/masterdata/impl/WindTrackMasterDataJsonDeserializer.java b/java/com.sap.sailing.server.gateway.serialization/src/com/sap/sailing/server/gateway/deserialization/masterdata/impl/WindTrackMasterDataJsonDeserializer.java deleted file mode 100644 index 5f248e3f898..00000000000 --- a/java/com.sap.sailing.server.gateway.serialization/src/com/sap/sailing/server/gateway/deserialization/masterdata/impl/WindTrackMasterDataJsonDeserializer.java +++ /dev/null @@ -1,71 +0,0 @@ -package com.sap.sailing.server.gateway.deserialization.masterdata.impl; - -import java.io.Serializable; -import java.lang.reflect.Constructor; -import java.util.HashSet; -import java.util.Set; -import java.util.UUID; - -import org.json.simple.JSONArray; -import org.json.simple.JSONObject; - -import com.sap.sailing.domain.common.Position; -import com.sap.sailing.domain.masterdataimport.WindTrackMasterData; -import com.sap.sailing.domain.tracking.Wind; -import com.sap.sailing.server.gateway.deserialization.JsonDeserializationException; -import com.sap.sailing.server.gateway.deserialization.JsonDeserializer; -import com.sap.sailing.server.gateway.deserialization.impl.Helpers; -import com.sap.sailing.server.gateway.deserialization.impl.PositionJsonDeserializer; -import com.sap.sailing.server.gateway.deserialization.impl.WindJsonDeserializer; -import com.sap.sailing.server.gateway.serialization.masterdata.impl.WindTrackMasterDataJsonSerializer; - -public class WindTrackMasterDataJsonDeserializer implements JsonDeserializer { - - private final JsonDeserializer windDeserializer; - - public WindTrackMasterDataJsonDeserializer() { - JsonDeserializer positionDeserializer = new PositionJsonDeserializer(); - windDeserializer = new WindJsonDeserializer(positionDeserializer); - } - - @Override - public WindTrackMasterData deserialize(JSONObject object) throws JsonDeserializationException { - String windSourceTypeName = (String) object.get(WindTrackMasterDataJsonSerializer.FIELD_WIND_SOURCE_TYPE); - Serializable windSourceId = (Serializable) object.get(WindTrackMasterDataJsonSerializer.FIELD_WIND_SOURCE_ID); - JSONArray fixesJson = (JSONArray) object.get(WindTrackMasterDataJsonSerializer.FIELD_FIXES); - String regattaName = (String) object.get(WindTrackMasterDataJsonSerializer.FIELD_REGATTA_NAME); - String raceName = (String) object.get(WindTrackMasterDataJsonSerializer.FIELD_RACE_NAME); - Object idClassName = object.get(WindTrackMasterDataJsonSerializer.FIELD_ID_TYPE); - Serializable id = (Serializable) object.get(WindTrackMasterDataJsonSerializer.FIELD_RACE_ID); - if (id != null) { - if (idClassName != null) { - try { - Class idClass = Class.forName((String) idClassName); - if (Number.class.isAssignableFrom(idClass)) { - Constructor constructorFromString = idClass.getConstructor(String.class); - id = (Serializable) constructorFromString.newInstance(id.toString()); - } else if (UUID.class.isAssignableFrom(idClass)) { - id = Helpers.tryUuidConversion(id); - } - } catch (Exception e) { - throw new RuntimeException(e); - } - } else { - // To ensure some kind of a backward compability. - try { - id = UUID.fromString(id.toString()); - } catch (IllegalArgumentException e) { - id = id.toString(); - } - } - } - Set fixes = new HashSet(); - for (Object obj : fixesJson) { - JSONObject json = (JSONObject) obj; - Wind wind = windDeserializer.deserialize(json); - fixes.add(wind); - } - return new WindTrackMasterData(windSourceTypeName, windSourceId, fixes, regattaName, raceName, id); - } - -} diff --git a/java/com.sap.sailing.server.gateway.serialization/src/com/sap/sailing/server/gateway/serialization/impl/SeriesJsonSerializer.java b/java/com.sap.sailing.server.gateway.serialization/src/com/sap/sailing/server/gateway/serialization/impl/SeriesJsonSerializer.java index 2aa4889cc9f..56b0f92e76b 100644 --- a/java/com.sap.sailing.server.gateway.serialization/src/com/sap/sailing/server/gateway/serialization/impl/SeriesJsonSerializer.java +++ b/java/com.sap.sailing.server.gateway.serialization/src/com/sap/sailing/server/gateway/serialization/impl/SeriesJsonSerializer.java @@ -16,6 +16,7 @@ public class SeriesJsonSerializer implements JsonSerializer { public static final String FIELD_RACES = "races"; // TODO: 'races' is wrong here... it's actually 'raceColumns' public static final String FIELD_TRACKED_RACES = "trackedRaces"; public static final String FIELD_STARTS_WITH_ZERO_SCORE = "startsWithZeroScore"; + public static final String FIELD_HAS_SPLIT_FLEET_CONTIGUOUS_SCORING = "hasSplitFleetContiguousScoring"; public static final String FIELD_IS_MEDAL_SERIES = "isMedalSeries"; private final JsonSerializer fleetSerializer; @@ -30,6 +31,7 @@ public class SeriesJsonSerializer implements JsonSerializer { result.put(FIELD_NAME, series.getName()); result.put(FIELD_IS_MEDAL_SERIES, series.isMedal()); result.put(FIELD_STARTS_WITH_ZERO_SCORE, series.isStartsWithZeroScore()); + result.put(FIELD_HAS_SPLIT_FLEET_CONTIGUOUS_SCORING, series.hasSplitFleetContiguousScoring()); JSONArray fleetsJson = new JSONArray(); for (Fleet fleet : series.getFleets()) { diff --git a/java/com.sap.sailing.server.gateway.serialization/src/com/sap/sailing/server/gateway/serialization/masterdata/impl/CompetitorMasterDataJsonSerializer.java b/java/com.sap.sailing.server.gateway.serialization/src/com/sap/sailing/server/gateway/serialization/masterdata/impl/CompetitorMasterDataJsonSerializer.java deleted file mode 100644 index adb07cb6ba1..00000000000 --- a/java/com.sap.sailing.server.gateway.serialization/src/com/sap/sailing/server/gateway/serialization/masterdata/impl/CompetitorMasterDataJsonSerializer.java +++ /dev/null @@ -1,67 +0,0 @@ -package com.sap.sailing.server.gateway.serialization.masterdata.impl; - -import java.io.Serializable; -import java.util.UUID; - -import org.json.simple.JSONObject; - -import com.sap.sailing.domain.base.Boat; -import com.sap.sailing.domain.base.BoatClass; -import com.sap.sailing.domain.base.Competitor; -import com.sap.sailing.domain.base.Team; -import com.sap.sailing.server.gateway.serialization.JsonSerializer; - -public class CompetitorMasterDataJsonSerializer implements JsonSerializer { - - public static final String FIELD_BOAT_CLASS = "boatClass"; - public static final String FIELD_SAIL_ID = "sailID"; - public static final String FIELD_TEAM = "team"; - public static final String FIELD_BOAT = "boat"; - public static final String FIELD_ID = "id"; - public static final String FIELD_NAME = "name"; - public static final String FIELD_ID_TYPE = "idType"; - public static final String FIELD_DISPLAY_COLOR = "displayColor"; - private final JsonSerializer boatClassSerializer; - private final JsonSerializer teamSerializer; - - - - public CompetitorMasterDataJsonSerializer(JsonSerializer boatClassSerializer, - JsonSerializer teamSerializer) { - this.boatClassSerializer = boatClassSerializer; - this.teamSerializer = teamSerializer; - } - - @Override - public JSONObject serialize(Competitor competitor) { - //Check if it is null. This can happen for race log events that specify competitors - // but where the race is not tracked. - if (competitor == null) { - return null; - } - JSONObject jsonCompetitor = new JSONObject(); - jsonCompetitor.put(FIELD_NAME, competitor.getName()); - jsonCompetitor.put(FIELD_DISPLAY_COLOR, competitor.getColor()==null?null:competitor.getColor().getAsHtml()); - // Special treatment for UUIDs. They are represented as String because JSON doesn't have a way to represent them - // otherwise. However, other, e.g., numeric, types used to encode a serializable ID must be preserved according - // to JSON semantics. - // Also see the corresponding case distinction in the deserialized which first tries to parse a string as a UUID - // becore returning the ID as is. - jsonCompetitor.put(FIELD_ID_TYPE, competitor.getId().getClass().getName()); - Serializable competitorId = competitor.getId() instanceof UUID ? competitor.getId().toString() : competitor - .getId(); - jsonCompetitor.put(FIELD_ID, competitorId); - jsonCompetitor.put(FIELD_BOAT, createJsonForBoat(competitor.getBoat())); - jsonCompetitor.put(FIELD_TEAM, teamSerializer.serialize(competitor.getTeam())); - return jsonCompetitor; - } - - private JSONObject createJsonForBoat(Boat boat) { - JSONObject jsonBoat = new JSONObject(); - jsonBoat.put(FIELD_NAME, boat.getName()); - jsonBoat.put(FIELD_SAIL_ID, boat.getSailID()); - jsonBoat.put(FIELD_BOAT_CLASS, boatClassSerializer.serialize(boat.getBoatClass())); - return jsonBoat; - } - -} diff --git a/java/com.sap.sailing.server.gateway.serialization/src/com/sap/sailing/server/gateway/serialization/masterdata/impl/EventMasterDataJsonSerializer.java b/java/com.sap.sailing.server.gateway.serialization/src/com/sap/sailing/server/gateway/serialization/masterdata/impl/EventMasterDataJsonSerializer.java deleted file mode 100644 index f8bacf5f0f5..00000000000 --- a/java/com.sap.sailing.server.gateway.serialization/src/com/sap/sailing/server/gateway/serialization/masterdata/impl/EventMasterDataJsonSerializer.java +++ /dev/null @@ -1,49 +0,0 @@ -package com.sap.sailing.server.gateway.serialization.masterdata.impl; - -import org.json.simple.JSONArray; -import org.json.simple.JSONObject; - -import com.sap.sailing.domain.base.CourseArea; -import com.sap.sailing.domain.base.Event; -import com.sap.sailing.server.gateway.serialization.JsonSerializer; - -public class EventMasterDataJsonSerializer implements JsonSerializer { - - public static final String FIELD_ID = "id"; - public static final String FIELD_NAME = "name"; - public static final String FIELD_VENUE_NAME = "venueName"; - public static final String FIELD_PUB_URL = "publicationUrl"; - public static final String FIELD_COURSE_AREAS = "courseAreas"; - public static final String FIELD_IS_PUBLIC = "isPublic"; - - - @Override - public JSONObject serialize(Event event) { - JSONObject result = new JSONObject(); - result.put(FIELD_ID, event.getId().toString()); - result.put(FIELD_NAME, event.getName()); - result.put(FIELD_VENUE_NAME, event.getVenue().getName()); - result.put(FIELD_PUB_URL, event.getPublicationUrl()); - result.put(FIELD_IS_PUBLIC, event.isPublic()); - result.put(FIELD_COURSE_AREAS, createJsonArrayForCourseAreas(event.getVenue().getCourseAreas())); - //TODO Sadly event.getRegattas() returns an empty collection - //result.put(FIELD_REGATTAS, createJsonArrayForRegattas(event.getRegattas())); - return result; - } - - private JSONArray createJsonArrayForCourseAreas(Iterable courseAreas) { - JSONArray array = new JSONArray(); - for (CourseArea courseArea : courseAreas) { - array.add(createJsonForCourseArea(courseArea)); - } - return array; - } - - private JSONObject createJsonForCourseArea(CourseArea courseArea) { - JSONObject result = new JSONObject(); - result.put(FIELD_ID, courseArea.getId().toString()); - result.put(FIELD_NAME, courseArea.getName()); - return result; - } - -} diff --git a/java/com.sap.sailing.server.gateway.serialization/src/com/sap/sailing/server/gateway/serialization/masterdata/impl/LeaderboardGroupMasterDataJsonSerializer.java b/java/com.sap.sailing.server.gateway.serialization/src/com/sap/sailing/server/gateway/serialization/masterdata/impl/LeaderboardGroupMasterDataJsonSerializer.java deleted file mode 100644 index 09e593d2654..00000000000 --- a/java/com.sap.sailing.server.gateway.serialization/src/com/sap/sailing/server/gateway/serialization/masterdata/impl/LeaderboardGroupMasterDataJsonSerializer.java +++ /dev/null @@ -1,164 +0,0 @@ -package com.sap.sailing.server.gateway.serialization.masterdata.impl; - -import java.util.HashSet; -import java.util.Set; -import java.util.concurrent.ConcurrentHashMap; - -import org.json.simple.JSONArray; -import org.json.simple.JSONObject; - -import com.sap.sailing.domain.base.Competitor; -import com.sap.sailing.domain.base.CourseArea; -import com.sap.sailing.domain.base.Event; -import com.sap.sailing.domain.base.Fleet; -import com.sap.sailing.domain.base.RaceColumn; -import com.sap.sailing.domain.base.Regatta; -import com.sap.sailing.domain.base.configuration.RegattaConfiguration; -import com.sap.sailing.domain.common.Color; -import com.sap.sailing.domain.leaderboard.Leaderboard; -import com.sap.sailing.domain.leaderboard.LeaderboardGroup; -import com.sap.sailing.domain.leaderboard.meta.LeaderboardGroupMetaLeaderboard; -import com.sap.sailing.domain.racelog.RaceLogEvent; -import com.sap.sailing.server.gateway.serialization.JsonSerializer; -import com.sap.sailing.server.gateway.serialization.impl.BoatClassJsonSerializer; -import com.sap.sailing.server.gateway.serialization.impl.ColorJsonSerializer; -import com.sap.sailing.server.gateway.serialization.impl.FleetJsonSerializer; -import com.sap.sailing.server.gateway.serialization.impl.NationalityJsonSerializer; -import com.sap.sailing.server.gateway.serialization.impl.PersonJsonSerializer; -import com.sap.sailing.server.gateway.serialization.impl.RegattaConfigurationJsonSerializer; -import com.sap.sailing.server.gateway.serialization.impl.TeamJsonSerializer; -import com.sap.sailing.server.gateway.serialization.racelog.impl.RaceLogEventSerializer; - -public class LeaderboardGroupMasterDataJsonSerializer implements JsonSerializer { - - public static final String FIELD_LEADERBOARDS = "leaderboards"; - public static final String FIELD_HAS_OVERALL_LEADERBOARD = "overallLeaderboard"; - public static final String FIELD_OVERALL_LEADERBOARD_SCORING_SCHEME = "overallLeaderboardScoringScheme"; - public static final String FIELD_OVERALL_LEADERBOARD_DISCARDING_THRESHOLDS = "overallLeaderboardDiscardingThresholds"; - public static final String FIELD_DESCRIPTION = "description"; - public static final String FIELD_NAME = "name"; - public static final String FIELD_DISPLAY_GROUPS_REVERSE = "displayGroupsReverse"; - public static final String FIELD_EVENTS = "events"; - public static final String FIELD_REGATTAS = "regattas"; - public static final String FIELD_OVERALL_LEADERBOARD_META_COLUMNS = "overallLeaderboardMetaColumns"; - public static final String FIELD_OVERALL_LEADERBOARD_SUPPRESSED_COMPETITORS = "overallLeaderboardSuppressedCompetitors"; - public static final String FIELD_EXPLICIT_FACTOR = "explicitFactor"; - private final LeaderboardMasterDataJsonSerializer leadboardSerializer; - private final Iterable allEvents; - private final JsonSerializer eventSerializer; - private final JsonSerializer regattaSerializer; - - /** - * If masterdata is imported from a server where exported races are not tracked, data like race log competitor - * data may be lost in the process of serialization - * @param events - * @param regattaForRaceIdString - */ - public LeaderboardGroupMasterDataJsonSerializer(Iterable events, ConcurrentHashMap regattaForRaceIdStrings) { - this.allEvents = events; - NationalityJsonSerializer nationalityJsonSerializer = new NationalityJsonSerializer(); - PersonJsonSerializer personSerializer = new PersonJsonSerializer(nationalityJsonSerializer); - TeamJsonSerializer teamSerializer = new TeamJsonSerializer(personSerializer); - BoatClassJsonSerializer boatClassSerializer = new BoatClassJsonSerializer(); - CompetitorMasterDataJsonSerializer competitorSerializer = new CompetitorMasterDataJsonSerializer( - boatClassSerializer, teamSerializer); - JsonSerializer colorSerializer = new ColorJsonSerializer(); - JsonSerializer fleetSerializer = new FleetJsonSerializer(colorSerializer); - JsonSerializer raceColumnSerializer = new RaceColumnMasterDataJsonSerializer(); - JsonSerializer configurationSerializer = RegattaConfigurationJsonSerializer.create(); - JsonSerializer raceLogEventSerializer = RaceLogEventSerializer.create(competitorSerializer); - eventSerializer = new EventMasterDataJsonSerializer(); - leadboardSerializer = new LeaderboardMasterDataJsonSerializer(competitorSerializer, raceColumnSerializer, raceLogEventSerializer); - regattaSerializer = new RegattaMasterDataJsonSerializer(fleetSerializer, raceColumnSerializer, configurationSerializer, regattaForRaceIdStrings); - } - - @Override - public JSONObject serialize(LeaderboardGroup leaderboardGroup) { - JSONObject jsonLeaderboardGroup = new JSONObject(); - jsonLeaderboardGroup.put(FIELD_NAME, leaderboardGroup.getName()); - jsonLeaderboardGroup.put(FIELD_DESCRIPTION, leaderboardGroup.getDescription()); - jsonLeaderboardGroup.put(FIELD_HAS_OVERALL_LEADERBOARD, leaderboardGroup.getOverallLeaderboard() != null); - if (leaderboardGroup.getOverallLeaderboard() != null) { - LeaderboardGroupMetaLeaderboard metaLeader = (LeaderboardGroupMetaLeaderboard) leaderboardGroup - .getOverallLeaderboard(); - jsonLeaderboardGroup.put(FIELD_OVERALL_LEADERBOARD_DISCARDING_THRESHOLDS, - LeaderboardMasterDataJsonSerializer.createJsonForResultDiscardingRule(metaLeader - .getResultDiscardingRule())); - jsonLeaderboardGroup.put(FIELD_OVERALL_LEADERBOARD_SCORING_SCHEME, - LeaderboardMasterDataJsonSerializer.createJsonForScoringScheme(metaLeader.getScoringScheme())); - jsonLeaderboardGroup.put(FIELD_OVERALL_LEADERBOARD_META_COLUMNS, createJsonArrayForMetaColumns(metaLeader)); - jsonLeaderboardGroup.put(FIELD_OVERALL_LEADERBOARD_SUPPRESSED_COMPETITORS, createJsonArrayForSuppressedCompetitors(metaLeader.getSuppressedCompetitors())); - } - jsonLeaderboardGroup.put(FIELD_LEADERBOARDS, createJsonArrayForLeaderboards(leaderboardGroup.getLeaderboards())); - jsonLeaderboardGroup.put(FIELD_DISPLAY_GROUPS_REVERSE, leaderboardGroup.isDisplayGroupsInReverseOrder()); - // Important to call this after serializing leaderboards, as the leaderboard serializer has state - jsonLeaderboardGroup.put(FIELD_EVENTS, createJsonArrayForEvents()); - jsonLeaderboardGroup.put(FIELD_REGATTAS, createJsonArrayForRegattas()); - return jsonLeaderboardGroup; - } - - private JSONArray createJsonArrayForSuppressedCompetitors(Iterable suppressedCompetitors) { - JSONArray array = new JSONArray(); - for (Competitor competitor : suppressedCompetitors) { - array.add(competitor.getId().toString()); - } - return array; - } - - private JSONArray createJsonArrayForMetaColumns(LeaderboardGroupMetaLeaderboard metaLeader) { - JSONArray array = new JSONArray(); - for (RaceColumn column : metaLeader.getRaceColumns()) { - JSONObject metaColumn = new JSONObject(); - metaColumn.put(FIELD_NAME, column.getName()); - metaColumn.put(FIELD_EXPLICIT_FACTOR, column.getExplicitFactor()); - array.add(metaColumn); - } - return array; - } - - private JSONArray createJsonArrayForRegattas() { - JSONArray array = new JSONArray(); - Iterable regattas = leadboardSerializer.getRegattas(); - for (Regatta regatta : regattas) { - array.add(regattaSerializer.serialize(regatta)); - } - return array; - } - - /* - * TODO, this is a hack to find out which events are needed for the exported - * regatta leaderboards. should be replaced by a proper connection from regatta to event - */ - private JSONArray createJsonArrayForEvents() { - Set courseAreaIds = leadboardSerializer.getCourseAreaIds(); - Set eventsThatShouldBeExported = new HashSet(); - for (Event event : allEvents) { - boolean shouldBeExported = false; - for (CourseArea courseArea : event.getVenue().getCourseAreas()) { - if (courseAreaIds.contains(courseArea.getId().toString())) { - shouldBeExported = true; - break; - } - } - if (shouldBeExported) { - eventsThatShouldBeExported.add(event); - } - } - - JSONArray array = new JSONArray(); - for (Event event : eventsThatShouldBeExported) { - array.add(eventSerializer.serialize(event)); - } - return array; - } - - private JSONArray createJsonArrayForLeaderboards(Iterable leaderboards) { - JSONArray jsonLeaderBoards = new JSONArray(); - for (Leaderboard leaderboard : leaderboards) { - JSONObject jsonLeaderboard = leadboardSerializer.serialize(leaderboard); - jsonLeaderBoards.add(jsonLeaderboard); - } - return jsonLeaderBoards; - } - -} diff --git a/java/com.sap.sailing.server.gateway.serialization/src/com/sap/sailing/server/gateway/serialization/masterdata/impl/LeaderboardMasterDataJsonSerializer.java b/java/com.sap.sailing.server.gateway.serialization/src/com/sap/sailing/server/gateway/serialization/masterdata/impl/LeaderboardMasterDataJsonSerializer.java deleted file mode 100644 index d75cbf1700a..00000000000 --- a/java/com.sap.sailing.server.gateway.serialization/src/com/sap/sailing/server/gateway/serialization/masterdata/impl/LeaderboardMasterDataJsonSerializer.java +++ /dev/null @@ -1,339 +0,0 @@ -package com.sap.sailing.server.gateway.serialization.masterdata.impl; - -import java.io.Serializable; -import java.util.ArrayList; -import java.util.Collection; -import java.util.HashSet; -import java.util.Map; -import java.util.Map.Entry; -import java.util.Set; -import java.util.UUID; - -import org.json.simple.JSONArray; -import org.json.simple.JSONObject; - -import com.sap.sailing.domain.base.Competitor; -import com.sap.sailing.domain.base.CourseArea; -import com.sap.sailing.domain.base.Fleet; -import com.sap.sailing.domain.base.RaceColumn; -import com.sap.sailing.domain.base.Regatta; -import com.sap.sailing.domain.common.impl.MillisecondsTimePoint; -import com.sap.sailing.domain.leaderboard.FlexibleLeaderboard; -import com.sap.sailing.domain.leaderboard.Leaderboard; -import com.sap.sailing.domain.leaderboard.RegattaLeaderboard; -import com.sap.sailing.domain.leaderboard.ResultDiscardingRule; -import com.sap.sailing.domain.leaderboard.ScoringScheme; -import com.sap.sailing.domain.leaderboard.SettableScoreCorrection; -import com.sap.sailing.domain.leaderboard.ThresholdBasedResultDiscardingRule; -import com.sap.sailing.domain.racelog.RaceLog; -import com.sap.sailing.domain.racelog.RaceLogEvent; -import com.sap.sailing.server.gateway.serialization.JsonSerializer; - -public class LeaderboardMasterDataJsonSerializer implements JsonSerializer { - - public static final String FIELD_FOR_RACE_COLUMNS = "forRaceColumns"; - public static final String FIELD_TIME_POINT = "timePoint"; - public static final String FIELD_COMMENT = "comment"; - public static final String FIELD_MAX_POINTS_REASON = "maxPointsReason"; - public static final String FIELD_EXPLICIT_SCORE_CORRECTION = "explicitScoreCorrection"; - public static final String FIELD_FOR_COMPETITORS = "forCompetitors"; - public static final String FIELD_RACE_COLUMN_NAME = "raceColumnName"; - public static final String FIELD_RACE_COLUMNS = "raceColumns"; - public static final String FIELD_COMPETITORS = "competitors"; - public static final String FIELD_NAME = "name"; - public static final String FIELD_SCORE_CORRECTION = "scoreCorrection"; - public static final String FIELD_SCORING_SCHEME = "scoringScheme"; - public static final String FIELD_TYPE = "type"; - public static final String FIELD_REGATTA_LEADERBOARD = "regattaLeaderboard"; - public static final String FIELD_META_LEADERBOARD = "metaLeaderboard"; - public static final String FIELD_RESULT_DISCARDING_RULE = "resultDiscardingRule"; - public static final String FIELD_INDICES = "indices"; - public static final String FIELD_COURSE_AREA = "courseArea"; - public static final String FIELD_ID = "id"; - public static final String FIELD_REGATTA_NAME = "regattaName"; - public static final String FIELD_DISPLAY_NAME = "displayName"; - public static final String FIELD_COMPETITOR_ID = "competitorId"; - public static final String FIELD_CARRIED_POINTS = "carriedPoints"; - public static final String FIELD_CARRIED = "carried"; - public static final String FIELD_SUPPRESSED_COMPETITORS = "suppressedCompetitors"; - public static final String FIELD_COMPETITOR_DISPLAY_NAMES = "competitorDisplayNames"; - public static final String FIELD_RACE_LOG_EVENTS = "raceLogEvents"; - public static final String FIELD_FLEETS = "fleets"; - public static final String FIELD_FLEET_NAME = "fleetName"; - - private final JsonSerializer competitorSerializer; - private final JsonSerializer raceColumnSerializer; - private final JsonSerializer raceLogEventSerializer; - private final Set competitors = new HashSet(); - - /* - * TODO This is a hack to "remember" the course areas to allow finding the events which own the course areas. This - * way regatta leaderboard can be completely exported, because all events, their regattas, etc can be exported too. - * Their should be a proper connection between regatta and event soon. - */ - private final Set courseAreaIds = new HashSet(); - - private final Set regattas = new HashSet(); - - public LeaderboardMasterDataJsonSerializer(JsonSerializer competitorSerializer, - JsonSerializer raceColumnSerializer, JsonSerializer raceLogEventSerializer) { - this.competitorSerializer = competitorSerializer; - this.raceColumnSerializer = raceColumnSerializer; - this.raceLogEventSerializer = raceLogEventSerializer; - } - - @Override - public JSONObject serialize(Leaderboard leaderboard) { - if (leaderboard == null) { - return null; - } - JSONObject jsonLeaderboard = new JSONObject(); - jsonLeaderboard.put(FIELD_NAME, leaderboard.getName()); - jsonLeaderboard.put(FIELD_SCORE_CORRECTION, createJsonForScoreCorrection(leaderboard)); - jsonLeaderboard.put(FIELD_CARRIED_POINTS, createJsonArrayForCarriedPoints(leaderboard)); - jsonLeaderboard.put(FIELD_RESULT_DISCARDING_RULE, - createJsonForResultDiscardingRule(leaderboard.getResultDiscardingRule())); - jsonLeaderboard.put(FIELD_DISPLAY_NAME, leaderboard.getDisplayName()); - jsonLeaderboard.put(FIELD_RACE_LOG_EVENTS, createJsonArrayForRaceLogEventsPerRaceColumn(leaderboard)); - boolean isRegattaLeaderboard = false; - if (leaderboard instanceof FlexibleLeaderboard) { - FlexibleLeaderboard flexibleLeaderboard = (FlexibleLeaderboard) leaderboard; - jsonLeaderboard.put(FIELD_SCORING_SCHEME, createJsonForScoringScheme(leaderboard.getScoringScheme())); - jsonLeaderboard.put(FIELD_COURSE_AREA, createJsonForCourseArea(flexibleLeaderboard.getDefaultCourseArea())); - jsonLeaderboard.put(FIELD_RACE_COLUMNS, createJsonArrayForRaceColumns(leaderboard.getRaceColumns())); - } else if (leaderboard instanceof RegattaLeaderboard) { - RegattaLeaderboard regattaLeaderboard = (RegattaLeaderboard) leaderboard; - jsonLeaderboard.put(FIELD_REGATTA_NAME, regattaLeaderboard.getRegatta().getName()); - CourseArea courseArea = regattaLeaderboard.getRegatta().getDefaultCourseArea(); - if (courseArea != null) { - courseAreaIds.add(courseArea.getId().toString()); - } - regattas.add(regattaLeaderboard.getRegatta()); - isRegattaLeaderboard = true; - } - jsonLeaderboard.put(FIELD_REGATTA_LEADERBOARD, isRegattaLeaderboard); - jsonLeaderboard.put(FIELD_SUPPRESSED_COMPETITORS, - createJsonArrayForSuppressedCompetitors(leaderboard.getSuppressedCompetitors())); - - competitors.addAll(makeCollection(leaderboard.getAllCompetitors())); - jsonLeaderboard.put(FIELD_COMPETITOR_DISPLAY_NAMES, createJsonArrayForCompetitorDisplayNames(leaderboard)); - jsonLeaderboard.put(FIELD_COMPETITORS, createJsonArrayForCompetitors()); - return jsonLeaderboard; - } - - private JSONArray createJsonArrayForRaceLogEventsPerRaceColumn(Leaderboard leaderboard) { - JSONArray array = new JSONArray(); - for (RaceColumn raceColumn : leaderboard.getRaceColumns()) { - JSONObject raceColumnRaceLogJson = new JSONObject(); - raceColumnRaceLogJson.put(FIELD_RACE_COLUMN_NAME, raceColumn.getName()); - raceColumnRaceLogJson.put(FIELD_FLEETS, createJsonArrayForRaceLogEventsForFleets(raceColumn)); - array.add(raceColumnRaceLogJson); - } - return array; - } - - private JSONArray createJsonArrayForRaceLogEventsForFleets(RaceColumn raceColumn) { - JSONArray array = new JSONArray(); - for (Fleet fleet : raceColumn.getFleets()) { - JSONObject fleetRaceLogJson = new JSONObject(); - fleetRaceLogJson.put(FIELD_FLEET_NAME, fleet.getName()); - fleetRaceLogJson.put(FIELD_RACE_LOG_EVENTS, createRaceLogEventsForFleet(raceColumn, fleet)); - array.add(fleetRaceLogJson); - } - return array; - } - - private JSONArray createRaceLogEventsForFleet(RaceColumn raceColumn, Fleet fleet) { - JSONArray array = new JSONArray(); - RaceLog raceLog = raceColumn.getRaceLog(fleet); - if (raceLog != null) { - raceLog.lockForRead(); - try { - for (RaceLogEvent event : raceLog.getRawFixes()) { - array.add(raceLogEventSerializer.serialize(event)); - } - } finally { - raceLog.unlockAfterRead(); - } - } - return array; - } - - private JSONArray createJsonArrayForCompetitorDisplayNames(Leaderboard leaderboard) { - JSONArray array = new JSONArray(); - for (Competitor competitor : competitors) { - String displayName = leaderboard.getDisplayName(competitor); - if (displayName != null) { - JSONObject displayNameJson = new JSONObject(); - addCompetitorId(competitor, displayNameJson); - displayNameJson.put(FIELD_DISPLAY_NAME, displayName); - array.add(displayNameJson); - } - } - return array; - } - - private JSONArray createJsonArrayForSuppressedCompetitors(Iterable suppressedCompetitors) { - competitors.addAll(makeCollection(suppressedCompetitors)); - JSONArray array = new JSONArray(); - for (Competitor competitor : suppressedCompetitors) { - JSONObject obj = new JSONObject(); - addCompetitorId(competitor, obj); - array.add(obj); - } - return array; - } - - private void addCompetitorId(Competitor competitor, JSONObject obj) { - // Special treatment for UUIDs. They are represented as String because JSON doesn't have a way to represent - // them otherwise. However, other, e.g., numeric, types used to encode a serializable ID must be preserved - // according to JSON semantics. Also see the corresponding case distinction in the deserialized which first - // tries to parse a string as a UUID becore returning the ID as is. - obj.put(FIELD_TYPE, competitor.getId().getClass().getName()); - Serializable competitorId = competitor.getId() instanceof UUID ? competitor.getId().toString() : competitor - .getId(); - obj.put(FIELD_COMPETITOR_ID, competitorId); - } - - private JSONArray createJsonArrayForCarriedPoints(Leaderboard leaderboard) { - JSONArray jsonArray = new JSONArray(); - Map competitorsWithCarriedPoints = leaderboard - .getCompetitorsForWhichThereAreCarriedPoints(); - competitors.addAll(competitorsWithCarriedPoints.keySet()); - for (Entry entry : competitorsWithCarriedPoints.entrySet()) { - Double carriedPoints = entry.getValue(); - if (carriedPoints != 0) { - jsonArray.add(createJsonForCarriedPoints(entry.getKey(), carriedPoints)); - } - } - return jsonArray; - } - - private JSONObject createJsonForCarriedPoints(Competitor competitor, double carriedPoints) { - JSONObject jsonObject = new JSONObject(); - addCompetitorId(competitor, jsonObject); - jsonObject.put(FIELD_CARRIED, carriedPoints); - return jsonObject; - } - - private JSONObject createJsonForCourseArea(CourseArea defaultCourseArea) { - if (defaultCourseArea == null) { - return null; - } - JSONObject result = new JSONObject(); - result.put(FIELD_ID, defaultCourseArea.getId()); - result.put(FIELD_NAME, defaultCourseArea.getName()); - return null; - } - - public static JSONObject createJsonForResultDiscardingRule(ResultDiscardingRule resultDiscardingRule) { - JSONObject result = new JSONObject(); - if (resultDiscardingRule instanceof ThresholdBasedResultDiscardingRule) { - ThresholdBasedResultDiscardingRule rule = (ThresholdBasedResultDiscardingRule) resultDiscardingRule; - JSONArray indices = new JSONArray(); - int[] rawValues = rule.getDiscardIndexResultsStartingWithHowManyRaces(); - for (int i = 0; i < rawValues.length; i++) { - indices.add(new Integer(rawValues[i])); - } - result.put(FIELD_INDICES, indices); - } - return result; - } - - public static JSONObject createJsonForScoringScheme(ScoringScheme scoringScheme) { - JSONObject result = new JSONObject(); - result.put(FIELD_TYPE, scoringScheme.getType().name()); - return result; - } - - private JSONArray createJsonArrayForRaceColumns(Iterable raceColumns) { - JSONArray jsonRaceColumns = new JSONArray(); - for (RaceColumn raceColumn : raceColumns) { - JSONObject jsonRaceColumn = raceColumnSerializer.serialize(raceColumn); - jsonRaceColumns.add(jsonRaceColumn); - } - return jsonRaceColumns; - } - - private JSONArray createJsonArrayForCompetitors() { - JSONArray jsonCompetitors = new JSONArray(); - for (Competitor competitor : competitors) { - JSONObject jsonCompetitor = competitorSerializer.serialize(competitor); - jsonCompetitors.add(jsonCompetitor); - } - return jsonCompetitors; - } - - private JSONObject createJsonForScoreCorrection(Leaderboard leaderboard) { - SettableScoreCorrection correction = leaderboard.getScoreCorrection(); - JSONObject jsonScoreCorrection = new JSONObject(); - jsonScoreCorrection.put(FIELD_COMMENT, correction.getComment()); - if (correction.getTimePointOfLastCorrectionsValidity() != null) { - jsonScoreCorrection.put(FIELD_TIME_POINT, correction.getTimePointOfLastCorrectionsValidity().asMillis()); - } else { - jsonScoreCorrection.put(FIELD_TIME_POINT, null); - } - - jsonScoreCorrection.put(FIELD_FOR_RACE_COLUMNS, - createJSONArrayForScoreCorrectionsForRaceColumns(correction, leaderboard)); - - return jsonScoreCorrection; - } - - private JSONArray createJSONArrayForScoreCorrectionsForRaceColumns(SettableScoreCorrection correction, - Leaderboard leaderboard) { - JSONArray scoreCorrectionsForRaceColumns = new JSONArray(); - for (RaceColumn raceColumn : leaderboard.getRaceColumns()) { - if (correction.hasCorrectionFor(raceColumn)) { - JSONObject scoreCorrectionsForRaceColumn = new JSONObject(); - scoreCorrectionsForRaceColumn.put(FIELD_RACE_COLUMN_NAME, raceColumn.getName()); - scoreCorrectionsForRaceColumn.put(FIELD_FOR_COMPETITORS, - createJsonForScoreCorrectionsForRaceColumnAndCompetitors(correction, raceColumn, leaderboard)); - scoreCorrectionsForRaceColumns.add(scoreCorrectionsForRaceColumn); - } - - } - - return scoreCorrectionsForRaceColumns; - } - - private JSONArray createJsonForScoreCorrectionsForRaceColumnAndCompetitors(SettableScoreCorrection correction, - RaceColumn raceColumn, Leaderboard leaderboard) { - JSONArray scoreCorrectionsForCompetitors = new JSONArray(); - Iterable competitorsThatHaveCorrectionsIn = correction - .getCompetitorsThatHaveCorrectionsIn(raceColumn); - competitors.addAll(makeCollection(competitorsThatHaveCorrectionsIn)); - for (Competitor competitor : competitorsThatHaveCorrectionsIn) { - // TODO bug 655: score corrections shall be time dependent - final MillisecondsTimePoint now = MillisecondsTimePoint.now(); - if (correction.isScoreCorrected(competitor, raceColumn, now)) { - JSONObject scoreCorrectionForCompetitor = new JSONObject(); - scoreCorrectionForCompetitor.put(FIELD_EXPLICIT_SCORE_CORRECTION, - correction.getExplicitScoreCorrection(competitor, raceColumn)); - scoreCorrectionForCompetitor.put(FIELD_MAX_POINTS_REASON, - correction.getMaxPointsReason(competitor, raceColumn, now).toString()); - addCompetitorId(competitor, scoreCorrectionForCompetitor); - scoreCorrectionsForCompetitors.add(scoreCorrectionForCompetitor); - } - } - - return scoreCorrectionsForCompetitors; - } - - public Set getCourseAreaIds() { - return courseAreaIds; - } - - public Iterable getRegattas() { - return regattas; - } - - public static Collection makeCollection(Iterable iter) { - Collection list = new ArrayList(); - for (E item : iter) { - list.add(item); - } - return list; - } - -} diff --git a/java/com.sap.sailing.server.gateway.serialization/src/com/sap/sailing/server/gateway/serialization/masterdata/impl/MediaTrackJsonSerializer.java b/java/com.sap.sailing.server.gateway.serialization/src/com/sap/sailing/server/gateway/serialization/masterdata/impl/MediaTrackJsonSerializer.java deleted file mode 100644 index 7d9dcb3da2e..00000000000 --- a/java/com.sap.sailing.server.gateway.serialization/src/com/sap/sailing/server/gateway/serialization/masterdata/impl/MediaTrackJsonSerializer.java +++ /dev/null @@ -1,31 +0,0 @@ -package com.sap.sailing.server.gateway.serialization.masterdata.impl; - -import org.json.simple.JSONObject; - -import com.sap.sailing.domain.common.media.MediaTrack; -import com.sap.sailing.server.gateway.serialization.JsonSerializer; - -public class MediaTrackJsonSerializer implements JsonSerializer { - - public static final String FIELD_DB_ID = "dbId"; - public static final String FIELD_DURATION = "duration"; - public static final String FIELD_MIME_TYPE = "mimeType"; - public static final String FIELD_START_TIME = "startTime"; - public static final String FIELD_STATUS = "status"; - public static final String FIELD_TITLE = "title"; - public static final String FIELD_URL = "url"; - - @Override - public JSONObject serialize(MediaTrack mediaTrack) { - JSONObject result = new JSONObject(); - result.put(FIELD_DB_ID, mediaTrack.dbId); - result.put(FIELD_DURATION, mediaTrack.durationInMillis); - result.put(FIELD_MIME_TYPE, mediaTrack.mimeType.name()); - result.put(FIELD_START_TIME, mediaTrack.startTime.getTime()); - result.put(FIELD_STATUS, mediaTrack.status.name()); - result.put(FIELD_TITLE, mediaTrack.title); - result.put(FIELD_URL, mediaTrack.url); - return result; - } - -} diff --git a/java/com.sap.sailing.server.gateway.serialization/src/com/sap/sailing/server/gateway/serialization/masterdata/impl/RaceColumnMasterDataJsonSerializer.java b/java/com.sap.sailing.server.gateway.serialization/src/com/sap/sailing/server/gateway/serialization/masterdata/impl/RaceColumnMasterDataJsonSerializer.java deleted file mode 100644 index f0c8b721367..00000000000 --- a/java/com.sap.sailing.server.gateway.serialization/src/com/sap/sailing/server/gateway/serialization/masterdata/impl/RaceColumnMasterDataJsonSerializer.java +++ /dev/null @@ -1,71 +0,0 @@ -package com.sap.sailing.server.gateway.serialization.masterdata.impl; - -import java.io.Serializable; - -import org.json.simple.JSONArray; -import org.json.simple.JSONObject; - -import com.sap.sailing.domain.base.Fleet; -import com.sap.sailing.domain.base.RaceColumn; -import com.sap.sailing.domain.common.RaceIdentifier; -import com.sap.sailing.domain.common.WindSource; -import com.sap.sailing.domain.tracking.TrackedRace; -import com.sap.sailing.domain.tracking.WindTrack; -import com.sap.sailing.server.gateway.serialization.JsonSerializer; - -public class RaceColumnMasterDataJsonSerializer implements JsonSerializer { - - public static final String FIELD_MEDAL_RACE = "medalRace"; - public static final String FIELD_NAME = "name"; - public static final String FIELD_RACE_IDENTIFIERS = "raceIdentifiers"; - public static final String FIELD_FLEET_NAME = "fleetName"; - public static final String FIELD_RACE_NAME = "raceName"; - public static final String FIELD_REGATTA_NAME = "regattaName"; - public static final String FIELD_FACTOR = "factor"; - public static final String FIELD_WIND = "wind"; - - @Override - public JSONObject serialize(RaceColumn raceColumn) { - JSONObject jsonRaceColumn = new JSONObject(); - jsonRaceColumn.put(FIELD_NAME, raceColumn.getName()); - jsonRaceColumn.put(FIELD_MEDAL_RACE, raceColumn.isMedalRace()); - jsonRaceColumn.put(FIELD_FACTOR, raceColumn.getExplicitFactor()); - JSONArray raceIdentifiers = new JSONArray(); - jsonRaceColumn.put(FIELD_RACE_IDENTIFIERS, raceIdentifiers); - for (Fleet fleet : raceColumn.getFleets()) { - RaceIdentifier raceIdentifierForFleet = raceColumn.getRaceIdentifier(fleet); - if (raceIdentifierForFleet != null) { - JSONObject jsonRaceIdentifierForFleet = new JSONObject(); - jsonRaceIdentifierForFleet.put(FIELD_FLEET_NAME, fleet.getName()); - jsonRaceIdentifierForFleet.put(FIELD_RACE_NAME, raceIdentifierForFleet.getRaceName()); - jsonRaceIdentifierForFleet.put(FIELD_REGATTA_NAME, raceIdentifierForFleet.getRegattaName()); - raceIdentifiers.add(jsonRaceIdentifierForFleet); - } - TrackedRace trackedRace = raceColumn.getTrackedRace(fleet); - if (trackedRace != null) { - jsonRaceColumn.put(FIELD_WIND, serializeWindInformation(trackedRace)); - } - } - return jsonRaceColumn; - } - - private JSONArray serializeWindInformation(TrackedRace trackedRace) { - JSONArray jsonWindInfo = new JSONArray(); - Iterable windSources = trackedRace.getWindSources(); - String raceName = trackedRace.getRace().getName(); - Serializable raceId = trackedRace.getRace().getId(); - String regattaName = trackedRace.getTrackedRegatta().getRegatta().getName(); - if (windSources != null) { - for (WindSource source : windSources) { - if (source.canBeStored()) { - WindTrack track = trackedRace.getOrCreateWindTrack(source); - JsonSerializer windtrackSerializer = new WindTrackMasterDataJsonSerializer(source, - regattaName, raceName, raceId); - jsonWindInfo.add(windtrackSerializer.serialize(track)); - } - } - } - return jsonWindInfo; - } - -} diff --git a/java/com.sap.sailing.server.gateway.serialization/src/com/sap/sailing/server/gateway/serialization/masterdata/impl/RegattaMasterDataJsonSerializer.java b/java/com.sap.sailing.server.gateway.serialization/src/com/sap/sailing/server/gateway/serialization/masterdata/impl/RegattaMasterDataJsonSerializer.java deleted file mode 100644 index 829bdcb9b3e..00000000000 --- a/java/com.sap.sailing.server.gateway.serialization/src/com/sap/sailing/server/gateway/serialization/masterdata/impl/RegattaMasterDataJsonSerializer.java +++ /dev/null @@ -1,160 +0,0 @@ -package com.sap.sailing.server.gateway.serialization.masterdata.impl; - -import java.io.Serializable; -import java.util.Map.Entry; -import java.util.UUID; -import java.util.concurrent.ConcurrentHashMap; - -import org.json.simple.JSONArray; -import org.json.simple.JSONObject; - -import com.sap.sailing.domain.base.CourseArea; -import com.sap.sailing.domain.base.Fleet; -import com.sap.sailing.domain.base.RaceColumn; -import com.sap.sailing.domain.base.RaceColumnInSeries; -import com.sap.sailing.domain.base.Regatta; -import com.sap.sailing.domain.base.Series; -import com.sap.sailing.domain.base.configuration.RegattaConfiguration; -import com.sap.sailing.domain.common.RegattaName; -import com.sap.sailing.domain.leaderboard.ResultDiscardingRule; -import com.sap.sailing.domain.leaderboard.ThresholdBasedResultDiscardingRule; -import com.sap.sailing.server.gateway.serialization.JsonSerializer; - -public class RegattaMasterDataJsonSerializer implements JsonSerializer { - - public static final String FIELD_ID = "id"; - public static final String FIELD_ID_TYPE = "idType"; - public static final String FIELD_NAME = "name"; - public static final String FIELD_BASE_NAME = "baseName"; - public static final String FIELD_REGATTAS = "regattas"; - public static final String FIELD_BOAT_CLASS_NAME = "boatClass"; - public static final String FIELD_DEFAULT_COURSE_AREA_ID = "defaultCourseAreaId"; - public static final String FIELD_REGATTA_CONFIGURATION = "procedures"; - public static final String FIELD_SCORING_SCHEME_TYPE = "scoringSchemeType"; - public static final String FIELD_SERIES = "series"; - public static final String FIELD_RACE_COLUMNS = "raceColumns"; - public static final String FIELD_IS_MEDAL = "isMedal"; - public static final String FIELD_FLEETS = "fleets"; - public static final String FIELD_IS_PERSISTENT = "isPersistent"; - public static final String FIELD_REGATTA_NAME = "regattaName"; - public static final String FIELD_RESULT_DISCARDING_RULE = "resultDiscardingRule"; - public static final String FIELD_INDICES = "indices"; - public static final String FIELD_REGATTA_RACE_IDS = "regattaRaceIds"; - - private final JsonSerializer fleetSerializer; - private final JsonSerializer raceColumnSerializer; - private final JsonSerializer configurationSerializer; - private final ConcurrentHashMap regattaForRaceIdStrings; - - public RegattaMasterDataJsonSerializer(JsonSerializer fleetSerializer, - JsonSerializer raceColumnSerializer, - JsonSerializer configurationSerializer, - ConcurrentHashMap regattaForRaceIdStrings) { - this.fleetSerializer = fleetSerializer; - this.raceColumnSerializer = raceColumnSerializer; - this.configurationSerializer = configurationSerializer; - this.regattaForRaceIdStrings = regattaForRaceIdStrings; - } - - @Override - public JSONObject serialize(Regatta regatta) { - return createJsonForRegatta(regatta); - } - - private JSONObject createJsonForRegatta(Regatta regatta) { - JSONObject result = new JSONObject(); - // Special treatment for UUIDs. They are represented as String because JSON doesn't have a way to represent them - // otherwise. However, other, e.g., numeric, types used to encode a serializable ID must be preserved according - // to JSON semantics. - // Also see the corresponding case distinction in the deserialized which first tries to parse a string as a UUID - // becore returning the ID as is. - result.put(FIELD_ID_TYPE, regatta.getId().getClass().getName()); - Serializable regattaId = regatta.getId() instanceof UUID ? regatta.getId().toString() : regatta.getId(); - result.put(FIELD_ID, regattaId); - result.put(FIELD_BASE_NAME, regatta.getBaseName()); - result.put(FIELD_BOAT_CLASS_NAME, regatta.getBoatClass().getName()); - CourseArea defaultCourseArea = regatta.getDefaultCourseArea(); - if (defaultCourseArea != null) { - result.put(FIELD_DEFAULT_COURSE_AREA_ID, defaultCourseArea.getId().toString()); - } else { - result.put(FIELD_DEFAULT_COURSE_AREA_ID, null); - } - if (regatta.getRegattaConfiguration() != null) { - result.put(FIELD_REGATTA_CONFIGURATION, - configurationSerializer.serialize(regatta.getRegattaConfiguration())); - } - - result.put(FIELD_SCORING_SCHEME_TYPE, regatta.getScoringScheme().getType().toString()); - result.put(FIELD_SERIES, createJsonArrayForSeries(regatta.getSeries())); - result.put(FIELD_IS_PERSISTENT, regatta.isPersistent()); - result.put(FIELD_REGATTA_NAME, ((RegattaName) regatta.getRegattaIdentifier()).getRegattaName()); - result.put(FIELD_REGATTA_RACE_IDS, createJsonArrayForRaceIdStrings(regatta)); - return result; - } - - private JSONArray createJsonArrayForRaceIdStrings(Regatta regatta) { - JSONArray result = new JSONArray(); - for (Entry entry: regattaForRaceIdStrings.entrySet()) { - if (entry.getValue() == regatta) { - result.add(entry.getKey()); - } - } - return result; - } - - private JSONArray createJsonArrayForSeries(Iterable series) { - JSONArray array = new JSONArray(); - for (Series oneSeries : series) { - array.add(createJsonForSeries(oneSeries)); - } - return array; - } - - private JSONObject createJsonForSeries(Series series) { - JSONObject result = new JSONObject(); - result.put(FIELD_NAME, series.getName()); - result.put(FIELD_IS_MEDAL, series.isMedal()); - result.put(FIELD_FLEETS, createJsonArrayForFleets(series.getFleets())); - result.put(FIELD_RACE_COLUMNS, createJsonArrayForRaceColumns(series.getRaceColumns())); - result.put(FIELD_RESULT_DISCARDING_RULE, createJsonForResultDiscardingRule(series.getResultDiscardingRule())); - return result; - } - - private JSONObject createJsonForResultDiscardingRule(ResultDiscardingRule resultDiscardingRule) { - if (resultDiscardingRule == null) { - return null; - } - JSONObject result = new JSONObject(); - if (resultDiscardingRule instanceof ThresholdBasedResultDiscardingRule) { - ThresholdBasedResultDiscardingRule rule = (ThresholdBasedResultDiscardingRule) resultDiscardingRule; - JSONArray indices = new JSONArray(); - int[] rawValues = rule.getDiscardIndexResultsStartingWithHowManyRaces(); - for (int i = 0; i < rawValues.length; i++) { - indices.add(new Integer(rawValues[i])); - } - result.put(FIELD_INDICES, indices); - } - return result; - } - - private JSONArray createJsonArrayForFleets(Iterable fleets) { - JSONArray array = new JSONArray(); - for (Fleet fleet : fleets) { - array.add(fleetSerializer.serialize(fleet)); - } - return array; - } - - private JSONArray createJsonArrayForRaceColumns(Iterable raceColumns) { - JSONArray array = new JSONArray(); - for (RaceColumnInSeries raceColumn : raceColumns) { - array.add(createJsonForRaceColumn(raceColumn)); - } - return array; - } - - private JSONObject createJsonForRaceColumn(RaceColumnInSeries raceColumn) { - return raceColumnSerializer.serialize(raceColumn); - } - -} diff --git a/java/com.sap.sailing.server.gateway.serialization/src/com/sap/sailing/server/gateway/serialization/masterdata/impl/TopLevelMasterDataSerializer.java b/java/com.sap.sailing.server.gateway.serialization/src/com/sap/sailing/server/gateway/serialization/masterdata/impl/TopLevelMasterDataSerializer.java deleted file mode 100644 index bf65d736bd8..00000000000 --- a/java/com.sap.sailing.server.gateway.serialization/src/com/sap/sailing/server/gateway/serialization/masterdata/impl/TopLevelMasterDataSerializer.java +++ /dev/null @@ -1,72 +0,0 @@ -package com.sap.sailing.server.gateway.serialization.masterdata.impl; - -import java.util.Collection; -import java.util.Map; -import java.util.Set; -import java.util.concurrent.ConcurrentHashMap; - -import org.json.simple.JSONArray; -import org.json.simple.JSONObject; - -import com.sap.sailing.domain.base.Event; -import com.sap.sailing.domain.base.Regatta; -import com.sap.sailing.domain.common.media.MediaTrack; -import com.sap.sailing.domain.leaderboard.LeaderboardGroup; -import com.sap.sailing.server.gateway.serialization.JsonSerializer; - -/** - * Will take care of serializing all master data connected to a set of leaderboard groups. They - * are identified in {@link #serialize(Set)}. The serializer must be created with a reference to all - * leaderboard groups and all events, so that all necessary data can be found and serialized. - * - * @author Frederik Petersen (D054528) - * - */ -public class TopLevelMasterDataSerializer { - - public static final String FIELD_PER_LG = "perLg"; - public static final String FIELD_MEDIA = "media"; - private final Map allLeaderboardGroups; - private final Iterable allEvents; - private final ConcurrentHashMap regattaForRaceIdStrings; - private final Collection allMediaTracks; - - private final JsonSerializer mediaTrackSerializer; - - public TopLevelMasterDataSerializer(Map allLeaderboardGroups, Iterable allEvents, - ConcurrentHashMap regattaForRaceIdString, Collection allMediaTracks) { - this.allLeaderboardGroups = allLeaderboardGroups; - this.allEvents = allEvents; - this.regattaForRaceIdStrings = regattaForRaceIdString; - this.allMediaTracks = allMediaTracks; - mediaTrackSerializer = new MediaTrackJsonSerializer(); - } - - public JSONObject serialize(Set requestedLeaderboardGroupNames) { - JSONObject masterData = new JSONObject(); - - JSONArray masterDataPerLg = new JSONArray(); - - for (String name : requestedLeaderboardGroupNames) { - LeaderboardGroup leaderboardGroup = allLeaderboardGroups.get(name); - if (leaderboardGroup == null) { - continue; - } - JsonSerializer serializer = new LeaderboardGroupMasterDataJsonSerializer(allEvents, regattaForRaceIdStrings); - masterDataPerLg.add(serializer.serialize(leaderboardGroup)); - } - masterData.put(FIELD_PER_LG, masterDataPerLg); - masterData.put(FIELD_MEDIA, createJsonArrayForMediaTracks()); - - return masterData; - } - - private JSONArray createJsonArrayForMediaTracks() { - JSONArray array = new JSONArray(); - for (MediaTrack mediaTrack : allMediaTracks) { - array.add(mediaTrackSerializer.serialize(mediaTrack)); - } - return array; - } - -} diff --git a/java/com.sap.sailing.server.gateway.serialization/src/com/sap/sailing/server/gateway/serialization/masterdata/impl/WindTrackMasterDataJsonSerializer.java b/java/com.sap.sailing.server.gateway.serialization/src/com/sap/sailing/server/gateway/serialization/masterdata/impl/WindTrackMasterDataJsonSerializer.java deleted file mode 100644 index d891b326f7e..00000000000 --- a/java/com.sap.sailing.server.gateway.serialization/src/com/sap/sailing/server/gateway/serialization/masterdata/impl/WindTrackMasterDataJsonSerializer.java +++ /dev/null @@ -1,75 +0,0 @@ -package com.sap.sailing.server.gateway.serialization.masterdata.impl; - -import java.io.Serializable; -import java.util.UUID; - -import org.json.simple.JSONArray; -import org.json.simple.JSONObject; - -import com.sap.sailing.domain.common.Position; -import com.sap.sailing.domain.common.WindSource; -import com.sap.sailing.domain.tracking.Wind; -import com.sap.sailing.domain.tracking.WindTrack; -import com.sap.sailing.server.gateway.serialization.JsonSerializer; -import com.sap.sailing.server.gateway.serialization.impl.PositionJsonSerializer; -import com.sap.sailing.server.gateway.serialization.impl.WindJsonSerializer; - -public class WindTrackMasterDataJsonSerializer implements JsonSerializer{ - - public static final String FIELD_WIND_SOURCE_TYPE = "windSourceType"; - public static final String FIELD_WIND_SOURCE_ID = "windSourceId"; - public static final String FIELD_FIXES = "fixes"; - public static final String FIELD_RACE_NAME = "raceName"; - public static final String FIELD_RACE_ID = "raceId"; - public static final String FIELD_ID_TYPE = "idType"; - public static final String FIELD_REGATTA_NAME = "regattaName"; - - - private final WindSource source; - private final JsonSerializer windSerializer; - private final String regattaName; - private final String raceName; - private final Serializable raceId; - - public WindTrackMasterDataJsonSerializer(WindSource source, String regattaName, String raceName, Serializable raceId) { - this.source = source; - this.regattaName = regattaName; - this.raceName = raceName; - this.raceId = raceId; - JsonSerializer positionSerializer = new PositionJsonSerializer(); - this.windSerializer = new WindJsonSerializer(positionSerializer); - } - - @Override - public JSONObject serialize(WindTrack windTrack) { - JSONObject windTrackJson = new JSONObject(); - windTrack.lockForRead(); - try { - windTrackJson.put(FIELD_WIND_SOURCE_TYPE, source.getType().name()); - if (source.getId() != null) { - windTrackJson.put(FIELD_WIND_SOURCE_ID, source.getId().toString()); - } - windTrackJson.put(FIELD_RACE_NAME, raceName); - if (raceId != null) { - // Special treatment for UUIDs. They are represented as String because JSON doesn't have a way to - // otherwise. However, other, e.g., numeric, types used to encode a serializable ID must be preserved - // to JSON semantics. Also see the corresponding case distinction in the deserialized which first tries - // to parse a string as a UUID becore returning the ID as is. - windTrackJson.put(FIELD_ID_TYPE, raceId.getClass().getName()); - Serializable raceIdAdapted = raceId instanceof UUID ? raceId.toString() : raceId; - windTrackJson.put(FIELD_RACE_ID, raceIdAdapted); - } - windTrackJson.put(FIELD_REGATTA_NAME, regattaName); - JSONArray fixes = new JSONArray(); - Iterable fixesIterator = windTrack.getFixes(); - for (Wind wind : fixesIterator) { - fixes.add(windSerializer.serialize(wind)); - } - windTrackJson.put(FIELD_FIXES, fixes); - } finally { - windTrack.unlockAfterRead(); - } - return windTrackJson; - } - -} diff --git a/java/com.sap.sailing.server.gateway/WEB-INF/web.xml b/java/com.sap.sailing.server.gateway/WEB-INF/web.xml index 43aa36e7e28..4869bdc2392 100644 --- a/java/com.sap.sailing.server.gateway/WEB-INF/web.xml +++ b/java/com.sap.sailing.server.gateway/WEB-INF/web.xml @@ -1,253 +1,252 @@ - - - - - AdminApp - com.sap.sailing.server.gateway.impl.AdminApp - - - AdminApp - /admin - - - - RCConfiguration - com.sap.sailing.server.gateway.impl.rc.ConfigurationJsonGetServlet - - - RCConfiguration - /rc/configuration - - - - RaceGroups - com.sap.sailing.server.gateway.impl.rc.RaceGroupJsonExportServlet - - - RaceGroups - /rc/racegroups - - - - RCAddToRaceLog - com.sap.sailing.server.gateway.impl.rc.AddEntryToRaceLogJsonPostServlet - - - RCAddToRaceLog - /rc/racelog - - - - RCMarks - com.sap.sailing.server.gateway.impl.rc.MarksJsonExportServlet - - - RCMarks - /rc/marks - - - - RCMarkPositions - com.sap.sailing.server.gateway.impl.rc.MarkPositionsJsonExportServlet - - - RCMarkPositions - /rc/markpositions - - - - RCCurrentCourse - com.sap.sailing.server.gateway.impl.rc.CourseJsonExportServlet - - - RCCurrentCourse - /rc/currentcourse - - - - RCCompetitors - com.sap.sailing.server.gateway.impl.rc.CompetitorsJsonExportServlet - - - RCCompetitors - /rc/competitors - - - - - - RegattaAndRaceDataJsonGetServlet - com.sap.sailing.server.gateway.impl.RegattaAndRaceDataJsonGetServlet - - - RegattaAndRaceDataJsonGetServlet - /moderator - - - - ExpeditionThroughHttpPostServlet - com.sap.sailing.server.gateway.impl.ExpeditionThroughHttpPostServlet - - - ExpeditionThroughHttpPostServlet - /expedition - - - - EventsJsonGetServlet - com.sap.sailing.server.gateway.impl.EventsJsonGetServlet - - - EventsJsonGetServlet - /events - - - - EventRaceStatesServlet - com.sap.sailing.server.gateway.impl.EventRaceStatesJsonGetServlet - - - EventRaceStatesServlet - /eventRaceStates - - - - RegattasJsonGetServlet - com.sap.sailing.server.gateway.impl.RegattasJsonGetServlet - - - RegattasJsonGetServlet - /regattas - - - RegattaJsonGetServlet - com.sap.sailing.server.gateway.impl.RegattaJsonGetServlet - - - RegattaJsonGetServlet - /regatta - - - - LeaderboardsJsonGetServlet - com.sap.sailing.server.gateway.impl.LeaderboardsJsonGetServlet - - - LeaderboardsJsonGetServlet - /leaderboards - - - - LeaderboardJsonGetServlet - com.sap.sailing.server.gateway.impl.LeaderboardJsonGetServlet - - - LeaderboardJsonGetServlet - /leaderboard - - - - LeaderboardGroupJsonGetServlet - com.sap.sailing.server.gateway.impl.LeaderboardGroupJsonGetServlet - - - LeaderboardGroupJsonGetServlet - /leaderboardgroup - - - - LeaderboardGroupsJsonGetServlet - com.sap.sailing.server.gateway.impl.LeaderboardGroupsJsonGetServlet - - - LeaderboardGroupsJsonGetServlet - /leaderboardgroups - - - - WindJsonGetServlet - com.sap.sailing.server.gateway.impl.WindJsonGetServlet - - - WindJsonGetServlet - /wind - - - - WindImportServlet - com.sap.sailing.server.gateway.expeditionimport.WindImportServlet - - - WindImportServlet - /expedition-import - - - - ExpeditionWindMeasureStatusGetServlet - com.sap.sailing.server.gateway.impl.ExpeditionWindMeasureStatusGetServlet - - - ExpeditionWindMeasureStatusGetServlet - /expeditionWindStatus - - - - WindStatusServlet - com.sap.sailing.server.gateway.impl.WindStatusServlet - - - WindStatusServlet - /windStatus - - - TrackFilesExportPostServlet - com.sap.sailing.server.gateway.impl.TrackFilesExportPostServlet - - - TrackFilesExportPostServlet - /trackfiles - - - - websockettest - com.sap.sailing.server.gateway.impl.WebSocketTestServlet - - - - websockettest - /websockettest - - - - Jersey REST API - com.sap.sailing.server.gateway.jaxrs.RestServletContainer - - javax.ws.rs.Application - com.sap.sailing.server.gateway.jaxrs.api.RestApiApplication - - 1 - - - Jersey REST API - /api/* - - - - Jersey REST SPI - com.sap.sailing.server.gateway.jaxrs.RestServletContainer - - javax.ws.rs.Application - com.sap.sailing.server.gateway.jaxrs.spi.RestSpiApplication - - 1 - - - Jersey REST SPI - /spi/* - - - + + + + + AdminApp + com.sap.sailing.server.gateway.impl.AdminApp + + + AdminApp + /admin + + + + RCConfiguration + com.sap.sailing.server.gateway.impl.rc.ConfigurationJsonGetServlet + + + RCConfiguration + /rc/configuration + + + + RaceGroups + com.sap.sailing.server.gateway.impl.rc.RaceGroupJsonExportServlet + + + RaceGroups + /rc/racegroups + + + + RCAddToRaceLog + com.sap.sailing.server.gateway.impl.rc.AddEntryToRaceLogJsonPostServlet + + + RCAddToRaceLog + /rc/racelog + + + + RCMarks + com.sap.sailing.server.gateway.impl.rc.MarksJsonExportServlet + + + RCMarks + /rc/marks + + + + RCMarkPositions + com.sap.sailing.server.gateway.impl.rc.MarkPositionsJsonExportServlet + + + RCMarkPositions + /rc/markpositions + + + + RCCurrentCourse + com.sap.sailing.server.gateway.impl.rc.CourseJsonExportServlet + + + RCCurrentCourse + /rc/currentcourse + + + + RCCompetitors + com.sap.sailing.server.gateway.impl.rc.CompetitorsJsonExportServlet + + + RCCompetitors + /rc/competitors + + + + + + RegattaAndRaceDataJsonGetServlet + com.sap.sailing.server.gateway.impl.RegattaAndRaceDataJsonGetServlet + + + RegattaAndRaceDataJsonGetServlet + /moderator + + + + ExpeditionThroughHttpPostServlet + com.sap.sailing.server.gateway.impl.ExpeditionThroughHttpPostServlet + + + ExpeditionThroughHttpPostServlet + /expedition + + + + EventsJsonGetServlet + com.sap.sailing.server.gateway.impl.EventsJsonGetServlet + + + EventsJsonGetServlet + /events + + + + EventRaceStatesServlet + com.sap.sailing.server.gateway.impl.EventRaceStatesJsonGetServlet + + + EventRaceStatesServlet + /eventRaceStates + + + + RegattasJsonGetServlet + com.sap.sailing.server.gateway.impl.RegattasJsonGetServlet + + + RegattasJsonGetServlet + /regattas + + + RegattaJsonGetServlet + com.sap.sailing.server.gateway.impl.RegattaJsonGetServlet + + + RegattaJsonGetServlet + /regatta + + + + LeaderboardsJsonGetServlet + com.sap.sailing.server.gateway.impl.LeaderboardsJsonGetServlet + + + LeaderboardsJsonGetServlet + /leaderboards + + + + LeaderboardJsonGetServlet + com.sap.sailing.server.gateway.impl.LeaderboardJsonGetServlet + + + LeaderboardJsonGetServlet + /leaderboard + + + + LeaderboardGroupJsonGetServlet + com.sap.sailing.server.gateway.impl.LeaderboardGroupJsonGetServlet + + + LeaderboardGroupJsonGetServlet + /leaderboardgroup + + + + LeaderboardGroupsJsonGetServlet + com.sap.sailing.server.gateway.impl.LeaderboardGroupsJsonGetServlet + + + LeaderboardGroupsJsonGetServlet + /leaderboardgroups + + + + WindJsonGetServlet + com.sap.sailing.server.gateway.impl.WindJsonGetServlet + + + WindJsonGetServlet + /wind + + + + WindImportServlet + com.sap.sailing.server.gateway.expeditionimport.WindImportServlet + + + WindImportServlet + /expedition-import + + + + ExpeditionWindMeasureStatusGetServlet + com.sap.sailing.server.gateway.impl.ExpeditionWindMeasureStatusGetServlet + + + ExpeditionWindMeasureStatusGetServlet + /expeditionWindStatus + + + + WindStatusServlet + com.sap.sailing.server.gateway.impl.WindStatusServlet + + + WindStatusServlet + /windStatus + + + TrackFilesExportPostServlet + com.sap.sailing.server.gateway.impl.TrackFilesExportPostServlet + + + TrackFilesExportPostServlet + /trackfiles + + + + websockettest + com.sap.sailing.server.gateway.impl.WebSocketTestServlet + + + + websockettest + /websockettest + + + + Jersey REST API + com.sap.sailing.server.gateway.jaxrs.RestServletContainer + + javax.ws.rs.Application + com.sap.sailing.server.gateway.jaxrs.api.RestApiApplication + + 1 + + + Jersey REST API + /api/* + + + Jersey REST SPI + com.sap.sailing.server.gateway.jaxrs.RestServletContainer + + javax.ws.rs.Application + com.sap.sailing.server.gateway.jaxrs.spi.RestSpiApplication + + 1 + + + Jersey REST SPI + /spi/* + + + \ No newline at end of file diff --git a/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/jaxrs/api/MasterDataResource.java b/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/jaxrs/api/MasterDataResource.java deleted file mode 100644 index c2871a3d615..00000000000 --- a/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/jaxrs/api/MasterDataResource.java +++ /dev/null @@ -1,89 +0,0 @@ -package com.sap.sailing.server.gateway.jaxrs.api; - -import java.io.IOException; -import java.io.OutputStream; -import java.io.UnsupportedEncodingException; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.logging.Logger; -import java.util.zip.GZIPOutputStream; - -import javax.ws.rs.GET; -import javax.ws.rs.Path; -import javax.ws.rs.Produces; -import javax.ws.rs.QueryParam; -import javax.ws.rs.WebApplicationException; -import javax.ws.rs.core.MediaType; -import javax.ws.rs.core.Response; -import javax.ws.rs.core.Response.ResponseBuilder; -import javax.ws.rs.core.StreamingOutput; - -import org.json.simple.JSONObject; - -import com.sap.sailing.domain.leaderboard.LeaderboardGroup; -import com.sap.sailing.server.gateway.jaxrs.AbstractSailingServerResource; -import com.sap.sailing.server.gateway.serialization.masterdata.impl.TopLevelMasterDataSerializer; - -@Path("/v1/masterdata") -public class MasterDataResource extends AbstractSailingServerResource { - - private static final Logger logger = Logger.getLogger(MasterDataResource.class.getName()); - - @GET - @Produces("application/json;charset=UTF-8") - @Path("leaderboardgroups") - public Response getMasterDataByLeaderboardGroups(@QueryParam("names[]") List leaderboardGroupNames, - @QueryParam("compress") Boolean compress) throws UnsupportedEncodingException { - long startTime = System.currentTimeMillis(); - if (compress == null) { - compress = false; - } - Map leaderboardGroups = getService().getLeaderboardGroups(); - Set requestedLeaderboardGroupNames = new HashSet(); - - if (leaderboardGroupNames.size() > 0) { - for (String name : leaderboardGroupNames) { - requestedLeaderboardGroupNames.add(name); - } - } else { - // No range supplied. Export all for now - requestedLeaderboardGroupNames.addAll(leaderboardGroups.keySet()); - } - - TopLevelMasterDataSerializer masterSerializer = new TopLevelMasterDataSerializer(leaderboardGroups, - getService().getAllEvents(), getService().getPersistentRegattasForRaceIDs(), getService() - .getAllMediaTracks()); - - JSONObject masterData = masterSerializer.serialize(requestedLeaderboardGroupNames); - ResponseBuilder resp; - if (compress) { - final byte[] uncompressedResult = masterData.toJSONString().getBytes("UTF-8"); - - StreamingOutput streamingOutput = new StreamingOutput() { - - @Override - public void write(OutputStream output) throws IOException, WebApplicationException { - GZIPOutputStream gzip = null; - try { - gzip = new GZIPOutputStream(output); - gzip.write(uncompressedResult); - } finally { - gzip.close(); - } - } - }; - resp = Response.ok(streamingOutput, MediaType.APPLICATION_JSON).header("Content-Encoding", "gzip"); - } else { - String result = masterData.toJSONString(); - resp = Response.ok(result, MediaType.APPLICATION_JSON); - } - - Response builtResponse = resp.build(); - long timeToExport = System.currentTimeMillis() - startTime; - logger.info(String.format("Took %s ms to export master data.", timeToExport)); - return builtResponse; - } - -} diff --git a/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/jaxrs/api/RestApiApplication.java b/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/jaxrs/api/RestApiApplication.java index 7ef60dead92..a9e069c0797 100644 --- a/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/jaxrs/api/RestApiApplication.java +++ b/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/jaxrs/api/RestApiApplication.java @@ -13,7 +13,6 @@ public class RestApiApplication extends Application { classes.add(EventsResource.class); classes.add(RegattasResource.class); classes.add(LeaderboardsResource.class); - classes.add(MasterDataResource.class); // classes.add(WindResource.class); return classes; diff --git a/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/jaxrs/spi/LeaderboardGroupsStructureResource.java b/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/jaxrs/spi/LeaderboardGroupsStructureResource.java deleted file mode 100644 index fbaa684bfe7..00000000000 --- a/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/jaxrs/spi/LeaderboardGroupsStructureResource.java +++ /dev/null @@ -1,46 +0,0 @@ -package com.sap.sailing.server.gateway.jaxrs.spi; - -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Set; - -import javax.ws.rs.GET; -import javax.ws.rs.Path; -import javax.ws.rs.Produces; -import javax.ws.rs.QueryParam; -import javax.ws.rs.core.MediaType; -import javax.ws.rs.core.Response; - -import org.json.simple.JSONObject; - -import com.sap.sailing.domain.leaderboard.LeaderboardGroup; -import com.sap.sailing.server.gateway.jaxrs.AbstractSailingServerResource; -import com.sap.sailing.server.gateway.serialization.masterdata.impl.TopLevelMasterDataSerializer; - -@Path("/v1/leaderboardgroups/structure") -public class LeaderboardGroupsStructureResource extends AbstractSailingServerResource { - - @GET - @Produces("application/json;charset=UTF-8") - public Response getStructureOfLeaderboardGroups(@QueryParam("names") List leaderboardGroupNames) { - Map leaderboardGroups = getService().getLeaderboardGroups(); - Set requestedLeaderboardGroupNames = new HashSet(); - - if (leaderboardGroupNames != null && !leaderboardGroupNames.isEmpty()) { - requestedLeaderboardGroupNames.addAll(leaderboardGroupNames); - } else { - // No range supplied. Export all for now - requestedLeaderboardGroupNames.addAll(leaderboardGroups.keySet()); - } - - TopLevelMasterDataSerializer masterSerializer = new TopLevelMasterDataSerializer(leaderboardGroups, - getService().getAllEvents(), getService().getPersistentRegattasForRaceIDs(), getService().getAllMediaTracks()); - - JSONObject masterData = masterSerializer.serialize(requestedLeaderboardGroupNames); - - String json = masterData.toJSONString(); - return Response.ok(json, MediaType.APPLICATION_JSON).build(); - } -} - \ No newline at end of file diff --git a/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/jaxrs/spi/MasterDataResource.java b/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/jaxrs/spi/MasterDataResource.java new file mode 100644 index 00000000000..ed50ee8cbc5 --- /dev/null +++ b/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/jaxrs/spi/MasterDataResource.java @@ -0,0 +1,149 @@ +package com.sap.sailing.server.gateway.jaxrs.spi; + +import java.io.FilterOutputStream; +import java.io.IOException; +import java.io.ObjectOutputStream; +import java.io.OutputStream; +import java.io.UnsupportedEncodingException; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.logging.Logger; +import java.util.zip.GZIPOutputStream; + +import javax.ws.rs.GET; +import javax.ws.rs.Path; +import javax.ws.rs.Produces; +import javax.ws.rs.QueryParam; +import javax.ws.rs.WebApplicationException; +import javax.ws.rs.core.Response; +import javax.ws.rs.core.Response.ResponseBuilder; +import javax.ws.rs.core.StreamingOutput; + +import com.sap.sailing.domain.leaderboard.LeaderboardGroup; +import com.sap.sailing.domain.masterdataimport.TopLevelMasterData; +import com.sap.sailing.server.gateway.jaxrs.AbstractSailingServerResource; + +@Path("/v1/masterdata/leaderboardgroups") +public class MasterDataResource extends AbstractSailingServerResource { + + private static final Logger logger = Logger.getLogger(MasterDataResource.class.getName()); + + @GET + @Produces("application/x-java-serialized-object") + public Response getMasterDataByLeaderboardGroups(@QueryParam("names[]") List leaderboardGroupNames, + @QueryParam("compress") Boolean compress) throws UnsupportedEncodingException { + final long startTime = System.currentTimeMillis(); + logger.info("Masterdataexport has started"); + if (compress == null) { + compress = false; + } + logger.info(String.format("Masterdataexport gzip compression is turned %s", compress ? "on" : "off")); + Map allLeaderboardGroups = getService().getLeaderboardGroups(); + + Set groupsToExport = new HashSet(); + + if (leaderboardGroupNames.size() > 0) { + for (String name : leaderboardGroupNames) { + LeaderboardGroup group = allLeaderboardGroups.get(name); + if (group != null) { + groupsToExport.add(group); + } + } + } else { + groupsToExport = new HashSet(); + groupsToExport.addAll(allLeaderboardGroups.values()); + } + + final TopLevelMasterData masterData = new TopLevelMasterData(groupsToExport, + getService().getAllEvents(), getService().getPersistentRegattasForRaceIDs(), getService() + .getAllMediaTracks()); + + ResponseBuilder resp; + if (compress) { + StreamingOutput streamingOutput = new StreamingOutput() { + + @Override + public void write(OutputStream output) throws IOException, WebApplicationException { + ObjectOutputStream objectOutputStream = null; + try { + GZIPOutputStream gzip = new GZIPOutputStream(output); + OutputStream outputStreamWithByteCounter = new ByteCountOutputStreamDecorator(gzip); + objectOutputStream = new ObjectOutputStream(outputStreamWithByteCounter); + + masterData.setMasterDataExportFlagOnRaceColumns(true); + // Actual start of streaming + objectOutputStream.writeObject(masterData); + } finally { + objectOutputStream.close(); + masterData.setMasterDataExportFlagOnRaceColumns(false); + } + long timeToExport = System.currentTimeMillis() - startTime; + logger.info(String.format("Took %s ms to finish masterdataexport", timeToExport)); + } + }; + resp = Response.ok(streamingOutput).header("Content-Encoding", "gzip"); + } else { + StreamingOutput streamingOutput = new StreamingOutput() { + + @Override + public void write(OutputStream output) throws IOException, WebApplicationException { + ObjectOutputStream objectOutputStream = null; + try { + OutputStream outputStreamWithByteCounter = new ByteCountOutputStreamDecorator(output); + objectOutputStream = new ObjectOutputStream(outputStreamWithByteCounter); + + // Actual start of streaming + objectOutputStream.writeObject(masterData); + } finally { + objectOutputStream.close(); + long timeToExport = System.currentTimeMillis() - startTime; + logger.info(String.format("Took %s ms to finish masterdataexport", timeToExport)); + } + } + }; + resp = Response.ok(streamingOutput); + } + + Response builtResponse = resp.build(); + long timeToExport = System.currentTimeMillis() - startTime; + logger.info(String.format("Took %s ms to start masterdataexport-streaming.", timeToExport)); + return builtResponse; + } + + private class ByteCountOutputStreamDecorator extends FilterOutputStream { + + private long byteCount = 0; + + public ByteCountOutputStreamDecorator(OutputStream out) { + super(out); + } + + @Override + public void write(byte[] b) throws IOException { + byteCount++; + super.write(b); + } + + @Override + public void write(byte[] b, int off, int len) throws IOException { + byteCount = byteCount + len; + super.write(b, off, len); + } + + @Override + public void write(int b) throws IOException { + byteCount++; + super.write(b); + } + + @Override + public void close() throws IOException { + logger.info(String.format("Uncompressed data size of masterdataexport: %s bytes", byteCount)); + super.close(); + } + + } + +} diff --git a/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/jaxrs/spi/RestSpiApplication.java b/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/jaxrs/spi/RestSpiApplication.java index c84e93abd84..fe0f78675f6 100644 --- a/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/jaxrs/spi/RestSpiApplication.java +++ b/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/jaxrs/spi/RestSpiApplication.java @@ -9,8 +9,7 @@ import javax.ws.rs.core.Application; public class RestSpiApplication extends Application { public Set> getClasses() { HashSet> classes = new HashSet<>(); - classes.add(LeaderboardGroupsStructureResource.class); - + classes.add(MasterDataResource.class); return classes; } } diff --git a/java/com.sap.sailing.server.gateway/webservices/api/v1/regattaGetDoc.html b/java/com.sap.sailing.server.gateway/webservices/api/v1/regattaGetDoc.html index 0671ea6e291..2f5e6a4e7a4 100644 --- a/java/com.sap.sailing.server.gateway/webservices/api/v1/regattaGetDoc.html +++ b/java/com.sap.sailing.server.gateway/webservices/api/v1/regattaGetDoc.html @@ -37,7 +37,7 @@ Example: - http://www.sapsailing.com/sailingserver/api/v1/regatta/Kieler Woche (5o5) + http://www.sapsailing.com/sailingserver/api/v1/regatta/Kieler Woche (5o5)
diff --git a/java/com.sap.sailing.server.replication.test/src/com/sap/sailing/server/replication/test/TrackRaceReplicationTest.java b/java/com.sap.sailing.server.replication.test/src/com/sap/sailing/server/replication/test/TrackRaceReplicationTest.java index efb743e863f..09270f7e6ca 100755 --- a/java/com.sap.sailing.server.replication.test/src/com/sap/sailing/server/replication/test/TrackRaceReplicationTest.java +++ b/java/com.sap.sailing.server.replication.test/src/com/sap/sailing/server/replication/test/TrackRaceReplicationTest.java @@ -83,7 +83,7 @@ public class TrackRaceReplicationTest extends AbstractServerReplicationTest { }); trackingParams = com.sap.sailing.domain.tractracadapter.DomainFactory.INSTANCE.createTrackingConnectivityParameters(paramURL, liveURI, storedURI, courseDesignUpdateURI, startOfTracking, endOfTracking, /* delayToLiveInMillis */ - 0l, /* simulateWithStartTimeNow */false, EmptyRaceLogStore.INSTANCE, tracTracUsername, tracTracPassword); + 0l, /* simulateWithStartTimeNow */false, EmptyRaceLogStore.INSTANCE, tracTracUsername, tracTracPassword, ""); } private void startTracking() throws Exception, InterruptedException { diff --git a/java/com.sap.sailing.server.test/META-INF/MANIFEST.MF b/java/com.sap.sailing.server.test/META-INF/MANIFEST.MF index 7a646cd8493..621b9a12924 100755 --- a/java/com.sap.sailing.server.test/META-INF/MANIFEST.MF +++ b/java/com.sap.sailing.server.test/META-INF/MANIFEST.MF @@ -17,7 +17,6 @@ Require-Bundle: com.sap.sailing.domain, com.mongodb.driver;bundle-version="2.6.2", org.junit4;bundle-version="4.8.2", com.sap.sailing.domain.test, - org.hamcrest;bundle-version="1.1.0", - com.sap.sailing.server.gateway.serialization;bundle-version="1.0.0" + org.hamcrest;bundle-version="1.1.0" Import-Package: org.json.simple Export-Package: com.sap.sailing.server.impl diff --git a/java/com.sap.sailing.server.test/src/com/sap/sailing/server/test/MasterDataImportTest.java b/java/com.sap.sailing.server.test/src/com/sap/sailing/server/test/MasterDataImportTest.java index e939b393006..06ac694e331 100755 --- a/java/com.sap.sailing.server.test/src/com/sap/sailing/server/test/MasterDataImportTest.java +++ b/java/com.sap.sailing.server.test/src/com/sap/sailing/server/test/MasterDataImportTest.java @@ -3,7 +3,12 @@ package com.sap.sailing.server.test; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; import java.io.IOException; +import java.io.InputStream; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; import java.io.Serializable; import java.net.MalformedURLException; import java.util.ArrayList; @@ -19,7 +24,6 @@ import java.util.concurrent.ConcurrentHashMap; import junit.framework.Assert; -import org.json.simple.JSONObject; import org.junit.After; import org.junit.Test; @@ -65,14 +69,17 @@ import com.sap.sailing.domain.common.media.MediaTrack; import com.sap.sailing.domain.leaderboard.FlexibleLeaderboard; import com.sap.sailing.domain.leaderboard.Leaderboard; import com.sap.sailing.domain.leaderboard.LeaderboardGroup; +import com.sap.sailing.domain.leaderboard.RegattaLeaderboard; import com.sap.sailing.domain.leaderboard.ScoringScheme; import com.sap.sailing.domain.leaderboard.ThresholdBasedResultDiscardingRule; import com.sap.sailing.domain.leaderboard.impl.FlexibleLeaderboardImpl; import com.sap.sailing.domain.leaderboard.impl.LowPoint; import com.sap.sailing.domain.leaderboard.meta.LeaderboardGroupMetaLeaderboard; +import com.sap.sailing.domain.masterdataimport.TopLevelMasterData; import com.sap.sailing.domain.persistence.PersistenceFactory; import com.sap.sailing.domain.persistence.media.MediaDBFactory; import com.sap.sailing.domain.racelog.CompetitorResults; +import com.sap.sailing.domain.racelog.RaceLog; import com.sap.sailing.domain.racelog.RaceLogEventAuthor; import com.sap.sailing.domain.racelog.RaceLogEventFactory; import com.sap.sailing.domain.racelog.RaceLogFinishPositioningConfirmedEvent; @@ -87,10 +94,9 @@ import com.sap.sailing.domain.tracking.impl.EmptyWindStore; import com.sap.sailing.domain.tracking.impl.WindImpl; import com.sap.sailing.mongodb.MongoDBService; import com.sap.sailing.server.RacingEventService; -import com.sap.sailing.server.gateway.serialization.masterdata.impl.TopLevelMasterDataSerializer; import com.sap.sailing.server.impl.RacingEventServiceImpl; +import com.sap.sailing.server.masterdata.DummyTrackedRace; import com.sap.sailing.server.masterdata.MasterDataImporter; -import com.sap.sailing.server.operationaltransformation.DummyTrackedRace; public class MasterDataImportTest { @@ -139,7 +145,7 @@ public class MasterDataImportTest { service.removeRegatta(regatta); } DBCollection raceLogCollection = MongoDBService.INSTANCE.getDB().getCollection("RACE_LOGS"); - //Removes all race log events + // Removes all race log events DBCursor cursor = raceLogCollection.find(); while (cursor.hasNext()) { raceLogCollection.remove(cursor.next()); @@ -156,8 +162,8 @@ public class MasterDataImportTest { // raceLogCollection.remove(result.next()); // } // } - - //Remove all media tracks + + // Remove all media tracks Collection tracks = service.getAllMediaTracks(); for (MediaTrack track : tracks) { service.mediaTrackDeleted(track); @@ -165,7 +171,8 @@ public class MasterDataImportTest { } @Test - public void testMasterDataImportWithoutHttpStack() throws MalformedURLException, IOException, InterruptedException { + public void testMasterDataImportWithoutHttpStack() throws MalformedURLException, IOException, InterruptedException, + ClassNotFoundException { // Setup source service RacingEventService sourceService = new RacingEventServiceImpl(); Event event = sourceService.addEvent(TEST_EVENT_NAME, "testVenue", "", false, eventUUID); @@ -186,22 +193,22 @@ public class MasterDataImportTest { fleets.add(new FleetImpl("testFleet2")); series.add(new SeriesImpl("testSeries", false, fleets, emptyRaceColumnNamesList, sourceService)); UUID regattaUUID = UUID.randomUUID(); - Regatta regatta = sourceService.createRegatta(TEST_REGATTA_NAME, TEST_BOAT_CLASS_NAME, regattaUUID, series, true, new LowPoint(), - courseAreaUUID); + Regatta regatta = sourceService.createRegatta(TEST_REGATTA_NAME, TEST_BOAT_CLASS_NAME, regattaUUID, series, + true, new LowPoint(), courseAreaUUID); event.addRegatta(regatta); for (String name : raceColumnNames) { series.get(0).addRaceColumn(name, sourceService); } double factor = 3.0; series.get(0).getRaceColumnByName(raceColumnName).setFactor(factor); - - + int[] discardRule = { 1, 2, 3, 4 }; Leaderboard leaderboard = sourceService.addRegattaLeaderboard(regatta.getRegattaIdentifier(), "testDisplayName", discardRule); List leaderboardNames = new ArrayList(); leaderboardNames.add(leaderboard.getName()); - sourceService.addLeaderboardGroup(TEST_GROUP_NAME, "testGroupDesc", false, leaderboardNames, null, null); + LeaderboardGroup group = sourceService.addLeaderboardGroup(TEST_GROUP_NAME, "testGroupDesc", false, + leaderboardNames, null, null); // Set tracked Race with competitors List competitors = new ArrayList(); @@ -224,26 +231,24 @@ public class MasterDataImportTest { "Bester Coach"); DynamicTeam team2 = new TeamImpl("Noobs", sailors2, coach2); DynamicBoat boat2 = new BoatImpl("LahmeEnte", boatClass, "GER1337"); - CompetitorImpl competitorToSuppress = new CompetitorImpl(competitorToSuppressUUID, "Merkel", Color.RED, team2, boat2); + CompetitorImpl competitorToSuppress = new CompetitorImpl(competitorToSuppressUUID, "Merkel", Color.RED, team2, + boat2); competitors.add(competitorToSuppress); RaceColumn raceColumn = leaderboard.getRaceColumnByName(raceColumnName); TrackedRace trackedRace = new DummyTrackedRace(competitors, regatta, null); - raceColumn.setTrackedRace(testFleet1, trackedRace); // Set log event RaceLogEventFactory factory = new RaceLogEventFactoryImpl(); TimePoint logTimePoint = new MillisecondsTimePoint(1372489200000L); TimePoint logTimePoint2 = new MillisecondsTimePoint(1372489201000L); - RaceLogStartTimeEvent logEvent = factory.createStartTimeEvent(logTimePoint, author, 1, - logTimePoint); + RaceLogStartTimeEvent logEvent = factory.createStartTimeEvent(logTimePoint, author, 1, logTimePoint); raceColumn.getRaceLog(testFleet1).add(logEvent); Position p = new DegreePosition(3, 3); Wind wind = new WindImpl(p, logTimePoint2, new KnotSpeedWithBearingImpl(5, new DegreeBearingImpl(12))); RaceLogWindFixEvent windEvent = factory.createWindFixEvent(logTimePoint2, author, UUID.randomUUID(), - new ArrayList(), 2, - wind); + new ArrayList(), 2, wind); raceColumn.getRaceLog(testFleet1).add(windEvent); storedLogUUIDs.add(logEvent.getId()); storedLogUUIDs.add(windEvent.getId()); @@ -266,23 +271,42 @@ public class MasterDataImportTest { leaderboard.setDisplayName(competitorToSuppress, nickName); // Serialize - TopLevelMasterDataSerializer serializer = new TopLevelMasterDataSerializer( - sourceService.getLeaderboardGroups(), sourceService.getAllEvents(), + HashSet groupsToExport = new HashSet(); + groupsToExport.add(group); + TopLevelMasterData masterdata = new TopLevelMasterData(groupsToExport, sourceService.getAllEvents(), sourceService.getPersistentRegattasForRaceIDs(), sourceService.getAllMediaTracks()); - Set names = new HashSet(); - names.add(TEST_GROUP_NAME); - JSONObject masterDataOverallObject = serializer.serialize(names); - Assert.assertNotNull(masterDataOverallObject); + Assert.assertNotNull(masterdata); + ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); + ObjectOutputStream oos = new ObjectOutputStream(outputStream); + RacingEventService destService; + ObjectInputStream ois = null; + TopLevelMasterData deserializedMasterData; + DomainFactory domainFactory; + try { + masterdata.setMasterDataExportFlagOnRaceColumns(true); + oos.writeObject(masterdata); + + + outputStream.flush(); + // Delete all data above from the database, to allow recreating all of it on target server + deleteCreatedDataFromDatabase(); + // Import in new service + destService = new RacingEventServiceImplMock(); + domainFactory = destService.getBaseDomainFactory(); + InputStream inputStream = new ByteArrayInputStream(outputStream.toByteArray()); + + ois = domainFactory.createObjectInputStreamResolvingAgainstThisFactory(inputStream); + deserializedMasterData = (TopLevelMasterData) ois.readObject(); + } finally { + masterdata.setMasterDataExportFlagOnRaceColumns(false); + oos.close(); + ois.close(); + } - // Delete all data above from the database, to allow recreating all of it on target server - deleteCreatedDataFromDatabase(); - // Deserialization copied from doPost in MasterDataByLeaderboardGroupJsonPostServlet - RacingEventService destService = new RacingEventServiceImplMock(); - DomainFactory domainFactory = DomainFactory.INSTANCE; MasterDataImporter importer = new MasterDataImporter(domainFactory, destService); - MasterDataImportObjectCreationCount creationCount = importer.importMasterData( - masterDataOverallObject.toString(), false); + + MasterDataImportObjectCreationCount creationCount = importer.importMasterData(deserializedMasterData, false); Assert.assertNotNull(creationCount); Event eventOnTarget = destService.getEvent(eventUUID); @@ -298,6 +322,8 @@ public class MasterDataImportTest { RaceColumn raceColumnOnTarget = leaderboardOnTarget.getRaceColumnByName(raceColumnName); Assert.assertNotNull(raceColumnOnTarget); + raceColumnOnTarget.setTrackedRace(raceColumnOnTarget.getFleets().iterator().next(), new DummyTrackedRace( + competitors, regattaOnTarget, null)); Assert.assertTrue(leaderboardOnTarget.getScoreCorrection().hasCorrectionFor(raceColumnOnTarget)); Competitor competitorOnTarget = domainFactory.getExistingCompetitorById(competitorUUID); @@ -306,9 +332,9 @@ public class MasterDataImportTest { Fleet fleet1OnTarget = raceColumnOnTarget.getFleetByName(testFleet1.getName()); TrackedRace trackedRaceForTarget = new DummyTrackedRace(competitorsCreatedOnTarget, regattaOnTarget, null); - + raceColumnOnTarget.setTrackedRace(fleet1OnTarget, trackedRaceForTarget); - + Assert.assertEquals(factor, raceColumnOnTarget.getFactor()); Iterable competitorsOnTarget = leaderboardOnTarget.getAllCompetitors(); @@ -321,15 +347,18 @@ public class MasterDataImportTest { scoreCorrection, leaderboardOnTarget.getScoreCorrection().getExplicitScoreCorrection(competitorOnTarget, raceColumnOnTarget)); - Assert.assertEquals(maxPointsReason, - leaderboardOnTarget.getScoreCorrection().getMaxPointsReason(competitorOnTarget, raceColumnOnTarget, MillisecondsTimePoint.now())); + Assert.assertEquals( + maxPointsReason, + leaderboardOnTarget.getScoreCorrection().getMaxPointsReason(competitorOnTarget, raceColumnOnTarget, + MillisecondsTimePoint.now())); // Check for carried points Assert.assertEquals(carriedPoints, leaderboardOnTarget.getCarriedPoints(competitorOnTarget)); // Check for suppressed competitor Assert.assertTrue(leaderboardOnTarget.getSuppressedCompetitors().iterator().hasNext()); - Competitor suppressedCompetitorOnTarget = domainFactory.getCompetitorStore().getExistingCompetitorById(competitorToSuppressUUID); + Competitor suppressedCompetitorOnTarget = domainFactory.getCompetitorStore().getExistingCompetitorById( + competitorToSuppressUUID); Assert.assertEquals(suppressedCompetitorOnTarget, leaderboardOnTarget.getSuppressedCompetitors().iterator() .next()); @@ -338,15 +367,23 @@ public class MasterDataImportTest { // Check for race log event Assert.assertNotNull(raceColumnOnTarget.getRaceLog(fleet1OnTarget).getFirstRawFixAtOrAfter(logTimePoint)); - Assert.assertEquals(logEvent.getId(), raceColumnOnTarget.getRaceLog(fleet1OnTarget).getFirstRawFixAtOrAfter(logTimePoint).getId()); + Assert.assertEquals(logEvent.getId(), + raceColumnOnTarget.getRaceLog(fleet1OnTarget).getFirstRawFixAtOrAfter(logTimePoint).getId()); Assert.assertNotNull(raceColumnOnTarget.getRaceLog(fleet1OnTarget).getFirstFixAtOrAfter(logTimePoint2)); Assert.assertEquals(wind, ((RaceLogWindFixEvent) raceColumnOnTarget.getRaceLog(fleet1OnTarget) .getFirstFixAtOrAfter(logTimePoint2)).getWindFix()); + + // Check for persisting of race log events: + RacingEventService dest2 = new RacingEventServiceImplMock(); + Leaderboard lb2 = dest2.getLeaderboardByName(TEST_LEADERBOARD_NAME); + RaceColumn raceColumn2 = lb2.getRaceColumns().iterator().next(); + RaceLog raceLog2 = raceColumn2.getRaceLog(raceColumn2.getFleetByName(fleet1OnTarget.getName())); + Assert.assertEquals(logEvent.getId(), raceLog2.getFirstRawFixAtOrAfter(logTimePoint).getId()); } - + @Test public void testMasterDataImportForScoreCorrections() throws MalformedURLException, IOException, - InterruptedException { + InterruptedException, ClassNotFoundException { // Setup source service RacingEventService sourceService = new RacingEventServiceImpl(); Event event = sourceService.addEvent(TEST_EVENT_NAME, "testVenue", "", false, eventUUID); @@ -367,8 +404,8 @@ public class MasterDataImportTest { fleets.add(new FleetImpl("testFleet2")); series.add(new SeriesImpl("testSeries", false, fleets, emptyRaceColumnNamesList, sourceService)); UUID regattaUUID = UUID.randomUUID(); - Regatta regatta = sourceService.createRegatta(TEST_REGATTA_NAME, TEST_BOAT_CLASS_NAME, regattaUUID, series, true, new LowPoint(), - courseAreaUUID); + Regatta regatta = sourceService.createRegatta(TEST_REGATTA_NAME, TEST_BOAT_CLASS_NAME, regattaUUID, series, + true, new LowPoint(), courseAreaUUID); event.addRegatta(regatta); for (String name : raceColumnNames) { series.get(0).addRaceColumn(name, sourceService); @@ -379,7 +416,8 @@ public class MasterDataImportTest { "testDisplayName", discardRule); List leaderboardNames = new ArrayList(); leaderboardNames.add(leaderboard.getName()); - sourceService.addLeaderboardGroup(TEST_GROUP_NAME, "testGroupDesc", false, leaderboardNames, null, null); + LeaderboardGroup group = sourceService.addLeaderboardGroup(TEST_GROUP_NAME, "testGroupDesc", false, + leaderboardNames, null, null); // Set tracked Race with competitors Set competitors = new HashSet(); @@ -405,7 +443,6 @@ public class MasterDataImportTest { RaceColumn raceColumn = leaderboard.getRaceColumnByName(raceColumnName); TrackedRace trackedRace = new DummyTrackedRace(competitors, regatta, null); - raceColumn.setTrackedRace(testFleet1, trackedRace); // Set log event @@ -414,15 +451,6 @@ public class MasterDataImportTest { RaceLogStartTimeEvent logEvent = factory.createStartTimeEvent(logTimePoint, author, 1, logTimePoint); raceColumn.getRaceLog(testFleet1).add(logEvent); storedLogUUIDs.add(logEvent.getId()); - - // Add a competitor-related race log event to ensure that no competitor resolution is attempted while receiving - TimePoint logTimePoint2 = logTimePoint.plus(10); - CompetitorResults positionedCompetitors = new CompetitorResultsImpl(); - positionedCompetitors.add(new Triple(competitor.getId(), competitor.getName(), MaxPointsReason.BFD)); - positionedCompetitors.add(new Triple(competitor2.getId(), competitor2.getName(), MaxPointsReason.NONE)); - RaceLogFinishPositioningConfirmedEvent finishPositioningConfirmedEvent = factory.createFinishPositioningConfirmedEvent(logTimePoint2, author, 1, positionedCompetitors); - raceColumn.getRaceLog(testFleet1).add(finishPositioningConfirmedEvent); - storedLogUUIDs.add(finishPositioningConfirmedEvent.getId()); // Set score correction double scoreCorrection = 12.0; @@ -431,23 +459,39 @@ public class MasterDataImportTest { leaderboard.getScoreCorrection().setMaxPointsReason(competitor, raceColumn, maxPointsReason); // Serialize - TopLevelMasterDataSerializer serializer = new TopLevelMasterDataSerializer( - sourceService.getLeaderboardGroups(), sourceService.getAllEvents(), + HashSet groupsToExport = new HashSet(); + groupsToExport.add(group); + TopLevelMasterData masterdata = new TopLevelMasterData(groupsToExport, sourceService.getAllEvents(), sourceService.getPersistentRegattasForRaceIDs(), sourceService.getAllMediaTracks()); - Set names = new HashSet(); - names.add(TEST_GROUP_NAME); - JSONObject masterDataOverallObject = serializer.serialize(names); - Assert.assertNotNull(masterDataOverallObject); + Assert.assertNotNull(masterdata); - // Delete all data above from the database, to allow recreating all of it on target server - deleteCreatedDataFromDatabase(); + ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); + ObjectOutputStream oos = new ObjectOutputStream(outputStream); + RacingEventService destService; + ObjectInputStream ois = null; + TopLevelMasterData deserializedMasterData; + DomainFactory domainFactory; + try { + masterdata.setMasterDataExportFlagOnRaceColumns(true); + oos.writeObject(masterdata); - // Deserialization copied from doPost in MasterDataByLeaderboardGroupJsonPostServlet - RacingEventService destService = new RacingEventServiceImplMock(); - DomainFactory domainFactory = new DomainFactoryImpl(); // create a new, empty domain factory to ensure all competitors are removed + outputStream.flush(); + // Delete all data above from the database, to allow recreating all of it on target server + deleteCreatedDataFromDatabase(); + // Import in new service + destService = new RacingEventServiceImplMock(); + domainFactory = destService.getBaseDomainFactory(); + InputStream inputStream = new ByteArrayInputStream(outputStream.toByteArray()); + + ois = domainFactory.createObjectInputStreamResolvingAgainstThisFactory(inputStream); + deserializedMasterData = (TopLevelMasterData) ois.readObject(); + } finally { + masterdata.setMasterDataExportFlagOnRaceColumns(false); + oos.close(); + ois.close(); + } MasterDataImporter importer = new MasterDataImporter(domainFactory, destService); - MasterDataImportObjectCreationCount creationCount = importer.importMasterData( - masterDataOverallObject.toString(), false); + MasterDataImportObjectCreationCount creationCount = importer.importMasterData(deserializedMasterData, false); Assert.assertNotNull(creationCount); Event eventOnTarget = destService.getEvent(eventUUID); @@ -472,7 +516,7 @@ public class MasterDataImportTest { Fleet fleet1OnTarget = raceColumnOnTarget.getFleetByName(testFleet1.getName()); TrackedRace trackedRaceForTarget = new DummyTrackedRace(competitorsCreatedOnTarget, regattaOnTarget, null); - + raceColumnOnTarget.setTrackedRace(fleet1OnTarget, trackedRaceForTarget); Iterable competitorsOnTarget = leaderboardOnTarget.getAllCompetitors(); @@ -485,18 +529,19 @@ public class MasterDataImportTest { scoreCorrection, leaderboardOnTarget.getScoreCorrection().getExplicitScoreCorrection(competitorOnTarget, raceColumnOnTarget)); - Assert.assertEquals(maxPointsReason, - leaderboardOnTarget.getScoreCorrection().getMaxPointsReason(competitorOnTarget, raceColumnOnTarget, MillisecondsTimePoint.now())); + Assert.assertEquals( + maxPointsReason, + leaderboardOnTarget.getScoreCorrection().getMaxPointsReason(competitorOnTarget, raceColumnOnTarget, + MillisecondsTimePoint.now())); // Checks if score correction was not set if not set on source Assert.assertFalse(leaderboardOnTarget.getScoreCorrection().isScoreCorrected(competitorOnTarget2, raceColumnOnTarget, MillisecondsTimePoint.now())); } - @Test - public void testMasterDataImportForWind() throws MalformedURLException, IOException, - InterruptedException { + public void testMasterDataImportForWind() throws MalformedURLException, IOException, InterruptedException, + ClassNotFoundException { // Setup source service RacingEventService sourceService = new RacingEventServiceImpl(); Event event = sourceService.addEvent(TEST_EVENT_NAME, "testVenue", "", false, eventUUID); @@ -527,7 +572,8 @@ public class MasterDataImportTest { "testDisplayName", discardRule); List leaderboardNames = new ArrayList(); leaderboardNames.add(leaderboard.getName()); - sourceService.addLeaderboardGroup(TEST_GROUP_NAME, "testGroupDesc", false, leaderboardNames, null, null); + LeaderboardGroup group = sourceService.addLeaderboardGroup(TEST_GROUP_NAME, "testGroupDesc", false, + leaderboardNames, null, null); // Set tracked Race with competitors Set competitors = new HashSet(); @@ -546,28 +592,42 @@ public class MasterDataImportTest { RaceColumn raceColumn = leaderboard.getRaceColumnByName(raceColumnName); TrackedRace trackedRace = new DummyTrackedRace(competitors, regatta, null); - raceColumn.setTrackedRace(testFleet1, trackedRace); - // Serialize - TopLevelMasterDataSerializer serializer = new TopLevelMasterDataSerializer( - sourceService.getLeaderboardGroups(), sourceService.getAllEvents(), + HashSet groupsToExport = new HashSet(); + groupsToExport.add(group); + TopLevelMasterData masterdata = new TopLevelMasterData(groupsToExport, sourceService.getAllEvents(), sourceService.getPersistentRegattasForRaceIDs(), sourceService.getAllMediaTracks()); - Set names = new HashSet(); - names.add(TEST_GROUP_NAME); - JSONObject masterDataOverallObject = serializer.serialize(names); - Assert.assertNotNull(masterDataOverallObject); + Assert.assertNotNull(masterdata); - // Delete all data above from the database, to allow recreating all of it on target server - deleteCreatedDataFromDatabase(); + ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); + ObjectOutputStream oos = new ObjectOutputStream(outputStream); + RacingEventService destService; + ObjectInputStream ois = null; + TopLevelMasterData deserializedMasterData; + DomainFactory domainFactory; + try { + masterdata.setMasterDataExportFlagOnRaceColumns(true); + oos.writeObject(masterdata); - // Deserialization copied from doPost in MasterDataByLeaderboardGroupJsonPostServlet - RacingEventService destService = new RacingEventServiceImplMock(); - DomainFactory domainFactory = new DomainFactoryImpl(); // create a new, empty domain factory to ensure all competitors are removed + outputStream.flush(); + // Delete all data above from the database, to allow recreating all of it on target server + deleteCreatedDataFromDatabase(); + // Import in new service + destService = new RacingEventServiceImplMock(); + domainFactory = destService.getBaseDomainFactory(); + InputStream inputStream = new ByteArrayInputStream(outputStream.toByteArray()); + + ois = domainFactory.createObjectInputStreamResolvingAgainstThisFactory(inputStream); + deserializedMasterData = (TopLevelMasterData) ois.readObject(); + } finally { + masterdata.setMasterDataExportFlagOnRaceColumns(false); + oos.close(); + ois.close(); + } MasterDataImporter importer = new MasterDataImporter(domainFactory, destService); - MasterDataImportObjectCreationCount creationCount = importer.importMasterData( - masterDataOverallObject.toString(), false); + MasterDataImportObjectCreationCount creationCount = importer.importMasterData(deserializedMasterData, false); Assert.assertNotNull(creationCount); Event eventOnTarget = destService.getEvent(eventUUID); @@ -590,26 +650,22 @@ public class MasterDataImportTest { Fleet fleet1OnTarget = raceColumnOnTarget.getFleetByName(testFleet1.getName()); TrackedRace trackedRaceForTarget = new DummyTrackedRace(competitorsCreatedOnTarget, regattaOnTarget, null); - + raceColumnOnTarget.setTrackedRace(fleet1OnTarget, trackedRaceForTarget); - //TODO Somehow have check if wind was really imported. DummyTrackedRace not sufficient - + // TODO Somehow have check if wind was really imported. DummyTrackedRace not sufficient + } - - /** - * When a race log entry references a competitor, e.g., by its UUID, these cannot be resolved when the TrackedRace isn't - * connected to the race column / leaderboard yet. Such a resolution would occur if importing the race log event triggered - * a listener which would try to resolve the competitor ID. This test ensures that the import does not fail due to such a - * look-up. - */ + @Test public void testMasterDataImportForRaceLogEventsReferencingCompetitors() throws MalformedURLException, IOException, - InterruptedException { + InterruptedException, ClassNotFoundException { // Setup source service DomainFactory sourceDomainFactory = new DomainFactoryImpl(); - RacingEventService sourceService = new RacingEventServiceImpl(PersistenceFactory.INSTANCE.getDomainObjectFactory(MongoDBService.INSTANCE, sourceDomainFactory), - PersistenceFactory.INSTANCE.getMongoObjectFactory(MongoDBService.INSTANCE), MediaDBFactory.INSTANCE.getDefaultMediaDB(), EmptyWindStore.INSTANCE); + RacingEventService sourceService = new RacingEventServiceImpl( + PersistenceFactory.INSTANCE.getDomainObjectFactory(MongoDBService.INSTANCE, sourceDomainFactory), + PersistenceFactory.INSTANCE.getMongoObjectFactory(MongoDBService.INSTANCE), + MediaDBFactory.INSTANCE.getDefaultMediaDB(), EmptyWindStore.INSTANCE); Event event = sourceService.addEvent(TEST_EVENT_NAME, "testVenue", "", false, eventUUID); UUID courseAreaUUID = UUID.randomUUID(); CourseArea courseArea = new CourseAreaImpl("testArea", courseAreaUUID); @@ -628,8 +684,8 @@ public class MasterDataImportTest { fleets.add(new FleetImpl("testFleet2")); series.add(new SeriesImpl("testSeries", false, fleets, emptyRaceColumnNamesList, sourceService)); UUID regattaUUID = UUID.randomUUID(); - Regatta regatta = sourceService.createRegatta(TEST_REGATTA_NAME, TEST_BOAT_CLASS_NAME, regattaUUID, series, true, new LowPoint(), - courseAreaUUID); + Regatta regatta = sourceService.createRegatta(TEST_REGATTA_NAME, TEST_BOAT_CLASS_NAME, regattaUUID, series, + true, new LowPoint(), courseAreaUUID); event.addRegatta(regatta); for (String name : raceColumnNames) { series.get(0).addRaceColumn(name, sourceService); @@ -640,7 +696,8 @@ public class MasterDataImportTest { "testDisplayName", discardRule); List leaderboardNames = new ArrayList(); leaderboardNames.add(leaderboard.getName()); - sourceService.addLeaderboardGroup(TEST_GROUP_NAME, "testGroupDesc", false, leaderboardNames, null, null); + LeaderboardGroup group = sourceService.addLeaderboardGroup(TEST_GROUP_NAME, "testGroupDesc", false, + leaderboardNames, null, null); // Set tracked Race with competitors Set competitors = new HashSet(); @@ -653,7 +710,8 @@ public class MasterDataImportTest { DynamicTeam team = new TeamImpl("Pros", sailors, coach); BoatClass boatClass = new BoatClassImpl("H16", true); DynamicBoat boat = new BoatImpl("Wingy", boatClass, "GER70133"); - Competitor competitor = sourceDomainFactory.getOrCreateCompetitor(competitorUUID, "Froderik", Color.RED, team, boat); + Competitor competitor = sourceDomainFactory.getOrCreateCompetitor(competitorUUID, "Froderik", Color.RED, team, + boat); competitors.add(competitor); UUID competitor2UUID = UUID.randomUUID(); Set sailors2 = new HashSet(); @@ -661,12 +719,12 @@ public class MasterDataImportTest { Person coach2 = new PersonImpl("Max Test", new NationalityImpl("GER"), new Date(645487200000L), "desc"); DynamicTeam team2 = new TeamImpl("Pros2", sailors2, coach2); DynamicBoat boat2 = new BoatImpl("FastBoat", boatClass, "GER70133"); - Competitor competitor2 = sourceDomainFactory.getCompetitorStore().getOrCreateCompetitor(competitor2UUID, "Froderik", Color.RED, team2, boat2); + Competitor competitor2 = sourceDomainFactory.getCompetitorStore().getOrCreateCompetitor(competitor2UUID, + "Froderik", Color.RED, team2, boat2); competitors.add(competitor2); RaceColumn raceColumn = leaderboard.getRaceColumnByName(raceColumnName); TrackedRace trackedRace = new DummyTrackedRace(competitors, regatta, null); - raceColumn.setTrackedRace(testFleet1, trackedRace); // Set log event @@ -675,34 +733,53 @@ public class MasterDataImportTest { RaceLogStartTimeEvent logEvent = factory.createStartTimeEvent(logTimePoint, author, 1, logTimePoint); raceColumn.getRaceLog(testFleet1).add(logEvent); storedLogUUIDs.add(logEvent.getId()); - + // Add a competitor-related race log event to ensure that no competitor resolution is attempted while receiving TimePoint logTimePoint2 = logTimePoint.plus(10); CompetitorResults positionedCompetitors = new CompetitorResultsImpl(); - positionedCompetitors.add(new Triple(competitor.getId(), competitor.getName(), MaxPointsReason.DNS)); - positionedCompetitors.add(new Triple(competitor2.getId(), competitor2.getName(), MaxPointsReason.NONE)); - RaceLogFinishPositioningConfirmedEvent finishPositioningConfirmedEvent = factory.createFinishPositioningConfirmedEvent(logTimePoint2, author, 1, positionedCompetitors); + positionedCompetitors.add(new Triple(competitor.getId(), competitor + .getName(), MaxPointsReason.DNS)); + positionedCompetitors.add(new Triple(competitor2.getId(), competitor2 + .getName(), MaxPointsReason.NONE)); + RaceLogFinishPositioningConfirmedEvent finishPositioningConfirmedEvent = factory + .createFinishPositioningConfirmedEvent(logTimePoint2, author, 1, positionedCompetitors); raceColumn.getRaceLog(testFleet1).add(finishPositioningConfirmedEvent); storedLogUUIDs.add(finishPositioningConfirmedEvent.getId()); // Serialize - TopLevelMasterDataSerializer serializer = new TopLevelMasterDataSerializer( - sourceService.getLeaderboardGroups(), sourceService.getAllEvents(), + HashSet groupsToExport = new HashSet(); + groupsToExport.add(group); + TopLevelMasterData masterdata = new TopLevelMasterData(groupsToExport, sourceService.getAllEvents(), sourceService.getPersistentRegattasForRaceIDs(), sourceService.getAllMediaTracks()); - Set names = new HashSet(); - names.add(TEST_GROUP_NAME); - JSONObject masterDataOverallObject = serializer.serialize(names); - Assert.assertNotNull(masterDataOverallObject); + Assert.assertNotNull(masterdata); - // Delete all data above from the database, to allow recreating all of it on target server - deleteCreatedDataFromDatabase(); + ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); + ObjectOutputStream oos = new ObjectOutputStream(outputStream); + RacingEventService destService; + ObjectInputStream ois = null; + TopLevelMasterData deserializedMasterData; + DomainFactory domainFactory; + try { + masterdata.setMasterDataExportFlagOnRaceColumns(true); + oos.writeObject(masterdata); - // Deserialization copied from doPost in MasterDataByLeaderboardGroupJsonPostServlet - RacingEventService destService = new RacingEventServiceImplMock(); - DomainFactory domainFactory = new DomainFactoryImpl(); // create a new, empty domain factory to ensure all competitors are removed + outputStream.flush(); + // Delete all data above from the database, to allow recreating all of it on target server + deleteCreatedDataFromDatabase(); + // Import in new service + destService = new RacingEventServiceImplMock(); + domainFactory = destService.getBaseDomainFactory(); + InputStream inputStream = new ByteArrayInputStream(outputStream.toByteArray()); + + ois = domainFactory.createObjectInputStreamResolvingAgainstThisFactory(inputStream); + deserializedMasterData = (TopLevelMasterData) ois.readObject(); + } finally { + masterdata.setMasterDataExportFlagOnRaceColumns(false); + oos.close(); + ois.close(); + } MasterDataImporter importer = new MasterDataImporter(domainFactory, destService); - MasterDataImportObjectCreationCount creationCount = importer.importMasterData( - masterDataOverallObject.toString(), false); + MasterDataImportObjectCreationCount creationCount = importer.importMasterData(deserializedMasterData, false); Assert.assertNotNull(creationCount); Event eventOnTarget = destService.getEvent(eventUUID); @@ -726,7 +803,7 @@ public class MasterDataImportTest { Fleet fleet1OnTarget = raceColumnOnTarget.getFleetByName(testFleet1.getName()); TrackedRace trackedRaceForTarget = new DummyTrackedRace(competitorsCreatedOnTarget, regattaOnTarget, null); - + raceColumnOnTarget.setTrackedRace(fleet1OnTarget, trackedRaceForTarget); Iterable competitorsOnTarget = leaderboardOnTarget.getAllCompetitors(); @@ -735,189 +812,15 @@ public class MasterDataImportTest { Assert.assertEquals(competitorOnTarget, competitorIterator.next()); // Check for score corrections - Assert.assertEquals(MaxPointsReason.DNS, - leaderboardOnTarget.getScoreCorrection().getMaxPointsReason(competitorOnTarget, raceColumnOnTarget, MillisecondsTimePoint.now())); + Assert.assertEquals( + MaxPointsReason.DNS, + leaderboardOnTarget.getScoreCorrection().getMaxPointsReason(competitorOnTarget, raceColumnOnTarget, + MillisecondsTimePoint.now())); } @Test - public void testMasterDataImportWithoutOverrideWithoutHttpStack() throws MalformedURLException, IOException, InterruptedException { - // Setup source service - RacingEventService sourceService = new RacingEventServiceImpl(); - Event event = sourceService.addEvent(TEST_EVENT_NAME, "testVenue", "", false, eventUUID); - UUID courseAreaUUID = UUID.randomUUID(); - CourseArea courseArea = new CourseAreaImpl("testArea", courseAreaUUID); - event.getVenue().addCourseArea(courseArea); - - List raceColumnNames = new ArrayList(); - String raceColumnName = "T1"; - raceColumnNames.add(raceColumnName); - raceColumnNames.add("T2"); - List emptyRaceColumnNamesList = Collections.emptyList(); - - List series = new ArrayList(); - List fleets = new ArrayList(); - FleetImpl testFleet1 = new FleetImpl("testFleet1"); - fleets.add(testFleet1); - fleets.add(new FleetImpl("testFleet2")); - series.add(new SeriesImpl("testSeries", false, fleets, emptyRaceColumnNamesList, sourceService)); - UUID regattaUUID = UUID.randomUUID(); - Regatta regatta = sourceService.createRegatta(TEST_REGATTA_NAME, TEST_BOAT_CLASS_NAME, regattaUUID, series, true, new LowPoint(), - courseAreaUUID); - event.addRegatta(regatta); - for (String name : raceColumnNames) { - series.get(0).addRaceColumn(name, sourceService); - } - - - int[] discardRule = { 1, 2, 3, 4 }; - Leaderboard leaderboard = sourceService.addRegattaLeaderboard(regatta.getRegattaIdentifier(), - "testDisplayName", discardRule); - List leaderboardNames = new ArrayList(); - leaderboardNames.add(leaderboard.getName()); - sourceService.addLeaderboardGroup(TEST_GROUP_NAME, "testGroupDesc", false, leaderboardNames, null, null); - - // Set tracked Race with competitors - Set competitors = new HashSet(); - UUID competitorUUID = UUID.randomUUID(); - Set sailors = new HashSet(); - sailors.add(new PersonImpl("Froderik Poterson", new NationalityImpl("GER"), new Date(645487200000L), - "Oberhoschy")); - Person coach = new PersonImpl("Lennart Hensler", new NationalityImpl("GER"), new Date(645487200000L), - "Der Lennart halt"); - DynamicTeam team = new TeamImpl("Pros", sailors, coach); - BoatClass boatClass = new BoatClassImpl("H16", true); - DynamicBoat boat = new BoatImpl("Wingy", boatClass, "GER70133"); - CompetitorImpl competitor = new CompetitorImpl(competitorUUID, "Froderik", Color.RED, team, boat); - competitors.add(competitor); - UUID competitorToSuppressUUID = UUID.randomUUID(); - Set sailors2 = new HashSet(); - sailors2.add(new PersonImpl("Angela Merkel", new NationalityImpl("GER"), new Date(645487200000L), - "segelt auch mit")); - Person coach2 = new PersonImpl("Peer Steinbrueck", new NationalityImpl("GER"), new Date(645487200000L), - "Bester Coach"); - DynamicTeam team2 = new TeamImpl("Noobs", sailors2, coach2); - DynamicBoat boat2 = new BoatImpl("LahmeEnte", boatClass, "GER1337"); - CompetitorImpl competitorToSuppress = new CompetitorImpl(competitorToSuppressUUID, "Merkel", Color.RED, team2, boat2); - competitors.add(competitorToSuppress); - RaceColumn raceColumn = leaderboard.getRaceColumnByName(raceColumnName); - TrackedRace trackedRace = new DummyTrackedRace(competitors, regatta, null); - - - raceColumn.setTrackedRace(testFleet1, trackedRace); - - // Set log event - RaceLogEventFactory factory = new RaceLogEventFactoryImpl(); - TimePoint logTimePoint = new MillisecondsTimePoint(1372489200000L); - RaceLogStartTimeEvent logEvent = factory.createStartTimeEvent(logTimePoint, author, 1, - logTimePoint); - raceColumn.getRaceLog(testFleet1).add(logEvent); - storedLogUUIDs.add(logEvent.getId()); - - // Set score correction - double scoreCorrection = 12.0; - leaderboard.getScoreCorrection().correctScore(competitor, raceColumn, scoreCorrection); - MaxPointsReason maxPointsReason = MaxPointsReason.DNS; - leaderboard.getScoreCorrection().setMaxPointsReason(competitor, raceColumn, maxPointsReason); - - // Set carried Points - double carriedPoints = 2.0; - leaderboard.setCarriedPoints(competitor, carriedPoints); - - // Set suppressed competitor - leaderboard.setSuppressed(competitorToSuppress, true); - - // Set display name - String nickName = "Angie"; - leaderboard.setDisplayName(competitorToSuppress, nickName); - - // Serialize - TopLevelMasterDataSerializer serializer = new TopLevelMasterDataSerializer( - sourceService.getLeaderboardGroups(), sourceService.getAllEvents(), - sourceService.getPersistentRegattasForRaceIDs(), sourceService.getAllMediaTracks()); - Set names = new HashSet(); - names.add(TEST_GROUP_NAME); - JSONObject masterDataOverallObject = serializer.serialize(names); - Assert.assertNotNull(masterDataOverallObject); - - // Delete all data above from the database, to allow recreating all of it on target server - deleteCreatedDataFromDatabase(); - - // Create existing data on target - RacingEventService destService = new RacingEventServiceImplMock(); - String venueNameNotToOverride = "doNotOverride"; - Event eventNotToOverride = destService.addEvent(TEST_EVENT_NAME, venueNameNotToOverride, "", false, eventUUID); - CourseArea courseAreaNotToOverride = new CourseAreaImpl("testAreaNotToOverride", courseAreaUUID); - eventNotToOverride.getVenue().addCourseArea(courseAreaNotToOverride); - - List raceColumnNamesNotToOverride = new ArrayList(); - String raceColumnNameNotToOveride = "T1nottooverride"; - raceColumnNamesNotToOverride.add(raceColumnNameNotToOveride); - emptyRaceColumnNamesList = Collections.emptyList(); - - List seriesNotToOverride = new ArrayList(); - List fleetsNotToOverride = new ArrayList(); - FleetImpl testFleet1NotToOverride = new FleetImpl("testFleet1"); - fleetsNotToOverride.add(testFleet1NotToOverride); - seriesNotToOverride.add(new SeriesImpl("testSeries", false, fleetsNotToOverride, emptyRaceColumnNamesList, destService)); - Regatta regattaNotToOverride = destService.createRegatta(TEST_REGATTA_NAME, TEST_BOAT_CLASS_NAME, regattaUUID, seriesNotToOverride, true, new LowPoint(), - courseAreaUUID); - event.addRegatta(regattaNotToOverride); - for (String name : raceColumnNamesNotToOverride) { - seriesNotToOverride.get(0).addRaceColumn(name, destService); - } - - Leaderboard leaderboardNotToOverride = destService.addRegattaLeaderboard(regattaNotToOverride.getRegattaIdentifier(), - "testDisplayNameNotToOverride", discardRule); - List leaderboardNamesNotToOverride = new ArrayList(); - leaderboardNamesNotToOverride.add(leaderboardNotToOverride.getName()); - LeaderboardGroup groupNotToOverride = destService.addLeaderboardGroup(TEST_GROUP_NAME, - "testGroupDescNotToOverride", false, leaderboardNamesNotToOverride, null, null); - - // Deserialization copied from SailingServiceImpl - - DomainFactory domainFactory = DomainFactory.INSTANCE; - MasterDataImporter importer = new MasterDataImporter(domainFactory, destService); - MasterDataImportObjectCreationCount creationCount = importer.importMasterData( - masterDataOverallObject.toString(), false); - - - //---Asserts--- - //Test correct number of creations - Assert.assertNotNull(creationCount); - Assert.assertEquals(0,creationCount.getEventCount()); - Assert.assertEquals(0,creationCount.getRegattaCount()); - Assert.assertEquals(0,creationCount.getLeaderboardCount()); - Assert.assertEquals(0,creationCount.getLeaderboardGroupCount()); - - Event eventOnTarget = destService.getEvent(eventUUID); - Assert.assertNotNull(eventOnTarget); - - //Check if existing event survived import - Assert.assertEquals(venueNameNotToOverride, eventOnTarget.getVenue().getName()); - - //Check if existing course area survived import - Assert.assertEquals(courseAreaNotToOverride.getName(), eventOnTarget.getVenue().getCourseAreas().iterator().next().getName()); - LeaderboardGroup leaderboardGroupOnTarget = destService.getLeaderboardGroupByName(TEST_GROUP_NAME); - Assert.assertNotNull(leaderboardGroupOnTarget); - //Check if existing leaderboard group survived import - Assert.assertEquals(groupNotToOverride.getDescription(), leaderboardGroupOnTarget.getDescription()); - Leaderboard leaderboardOnTarget = destService.getLeaderboardByName(TEST_LEADERBOARD_NAME); - Assert.assertNotNull(leaderboardOnTarget); - Regatta regattaOnTarget = destService.getRegattaByName(TEST_LEADERBOARD_NAME); - Assert.assertNotNull(regattaOnTarget); - - Assert.assertEquals(courseAreaUUID, eventOnTarget.getVenue().getCourseAreas().iterator().next().getId()); - - RaceColumn raceColumnOnTarget = leaderboardOnTarget.getRaceColumnByName(raceColumnNameNotToOveride); - Assert.assertNotNull(raceColumnOnTarget); - //Check if existing leaderboard survived import - Assert.assertEquals(leaderboardNotToOverride.getDisplayName(), leaderboardOnTarget.getDisplayName()); - Assert.assertFalse(leaderboardOnTarget.getScoreCorrection().hasCorrectionFor(raceColumnOnTarget)); - - } - - @Test - public void testMasterDataImportWithOverrideWithoutHttpStack() throws MalformedURLException, IOException, InterruptedException { + public void testMasterDataImportWithoutOverrideWithoutHttpStack() throws MalformedURLException, IOException, + InterruptedException, ClassNotFoundException { // Setup source service RacingEventService sourceService = new RacingEventServiceImpl(); Event event = sourceService.addEvent(TEST_EVENT_NAME, "testVenue", "", false, eventUUID); @@ -938,13 +841,13 @@ public class MasterDataImportTest { fleets.add(new FleetImpl("testFleet2")); series.add(new SeriesImpl("testSeries", false, fleets, emptyRaceColumnNamesList, sourceService)); UUID regattaUUID = UUID.randomUUID(); - Regatta regatta = sourceService.createRegatta(TEST_REGATTA_NAME, TEST_BOAT_CLASS_NAME, regattaUUID, series, true, new LowPoint(), - courseAreaUUID); + Regatta regatta = sourceService.createRegatta(TEST_REGATTA_NAME, TEST_BOAT_CLASS_NAME, regattaUUID, series, + true, new LowPoint(), courseAreaUUID); event.addRegatta(regatta); for (String name : raceColumnNames) { series.get(0).addRaceColumn(name, sourceService); } - + int[] discardRule = { 1, 2, 3, 4 }; Leaderboard leaderboard = sourceService.addRegattaLeaderboard(regatta.getRegattaIdentifier(), "testDisplayName", discardRule); @@ -974,19 +877,18 @@ public class MasterDataImportTest { "Bester Coach"); DynamicTeam team2 = new TeamImpl("Noobs", sailors2, coach2); DynamicBoat boat2 = new BoatImpl("LahmeEnte", boatClass, "GER1337"); - CompetitorImpl competitorToSuppress = new CompetitorImpl(competitorToSuppressUUID, "Merkel", Color.RED, team2, boat2); + CompetitorImpl competitorToSuppress = new CompetitorImpl(competitorToSuppressUUID, "Merkel", Color.RED, team2, + boat2); competitors.add(competitorToSuppress); RaceColumn raceColumn = leaderboard.getRaceColumnByName(raceColumnName); TrackedRace trackedRace = new DummyTrackedRace(competitors, regatta, null); - raceColumn.setTrackedRace(testFleet1, trackedRace); // Set log event RaceLogEventFactory factory = new RaceLogEventFactoryImpl(); TimePoint logTimePoint = new MillisecondsTimePoint(1372489200000L); - RaceLogStartTimeEvent logEvent = factory.createStartTimeEvent(logTimePoint, author, 1, - logTimePoint); + RaceLogStartTimeEvent logEvent = factory.createStartTimeEvent(logTimePoint, author, 1, logTimePoint); raceColumn.getRaceLog(testFleet1).add(logEvent); storedLogUUIDs.add(logEvent.getId()); @@ -1008,148 +910,123 @@ public class MasterDataImportTest { leaderboard.setDisplayName(competitorToSuppress, nickName); // Serialize - TopLevelMasterDataSerializer serializer = new TopLevelMasterDataSerializer( - sourceService.getLeaderboardGroups(), sourceService.getAllEvents(), sourceService.getPersistentRegattasForRaceIDs(), - sourceService.getAllMediaTracks()); - Set names = new HashSet(); - names.add(TEST_GROUP_NAME); - JSONObject masterDataOverallObject = serializer.serialize(names); - Assert.assertNotNull(masterDataOverallObject); + HashSet groupsToExport = new HashSet(); + groupsToExport.add(group); + TopLevelMasterData masterdata = new TopLevelMasterData(groupsToExport, sourceService.getAllEvents(), + sourceService.getPersistentRegattasForRaceIDs(), sourceService.getAllMediaTracks()); + Assert.assertNotNull(masterdata); - // Delete all data above from the database, to allow recreating all of it on target server - deleteCreatedDataFromDatabase(); - - // Create existing data on target - RacingEventService destService = new RacingEventServiceImplMock(); - String venueNameToOverride = "Override"; - Event eventToOverride = destService.addEvent(TEST_EVENT_NAME, venueNameToOverride, "", false, eventUUID); - CourseArea courseAreaToOverride = new CourseAreaImpl("testAreaToOverride", courseAreaUUID); - eventToOverride.getVenue().addCourseArea(courseAreaToOverride); - - List raceColumnNamesToOverride = new ArrayList(); - String raceColumnNameToOveride = raceColumnName; - raceColumnNamesToOverride.add(raceColumnNameToOveride); - emptyRaceColumnNamesList = Collections.emptyList(); - - List seriesToOverride = new ArrayList(); - List fleetsToOverride = new ArrayList(); - FleetImpl testFleet1ToOverride = new FleetImpl("testFleet1"); - fleetsToOverride.add(testFleet1ToOverride); - seriesToOverride.add(new SeriesImpl("testSeries", false, fleetsToOverride, emptyRaceColumnNamesList, destService)); - Regatta regattaToOverride = destService.createRegatta(TEST_REGATTA_NAME, TEST_BOAT_CLASS_NAME, regattaUUID, seriesToOverride, true, new LowPoint(), - courseAreaUUID); - event.addRegatta(regattaToOverride); - for (String name : raceColumnNamesToOverride) { - seriesToOverride.get(0).addRaceColumn(name, destService); + + + ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); + ObjectOutputStream oos = new ObjectOutputStream(outputStream); + ObjectInputStream ois = null; + TopLevelMasterData deserializedMasterData; + DomainFactory domainFactory; + RacingEventServiceImplMock destService; + String venueNameNotToOverride; + CourseAreaImpl courseAreaNotToOverride; + RegattaLeaderboard leaderboardNotToOverride; + LeaderboardGroup groupNotToOverride; + String raceColumnNameNotToOveride; + try { + masterdata.setMasterDataExportFlagOnRaceColumns(true); + oos.writeObject(masterdata); + + outputStream.flush(); + // Delete all data above from the database, to allow recreating all of it on target server + deleteCreatedDataFromDatabase(); + // Import in new service + destService = new RacingEventServiceImplMock(); + domainFactory = destService.getBaseDomainFactory(); + // Create existing data on target + venueNameNotToOverride = "doNotOverride"; + Event eventNotToOverride = destService.addEvent(TEST_EVENT_NAME, venueNameNotToOverride, "", false, + eventUUID); + courseAreaNotToOverride = new CourseAreaImpl("testAreaNotToOverride", courseAreaUUID); + eventNotToOverride.getVenue().addCourseArea(courseAreaNotToOverride); + + List raceColumnNamesNotToOverride = new ArrayList(); + raceColumnNameNotToOveride = "T1nottooverride"; + raceColumnNamesNotToOverride.add(raceColumnNameNotToOveride); + emptyRaceColumnNamesList = Collections.emptyList(); + + List seriesNotToOverride = new ArrayList(); + List fleetsNotToOverride = new ArrayList(); + FleetImpl testFleet1NotToOverride = new FleetImpl("testFleet1"); + fleetsNotToOverride.add(testFleet1NotToOverride); + seriesNotToOverride.add(new SeriesImpl("testSeries", false, fleetsNotToOverride, emptyRaceColumnNamesList, + destService)); + Regatta regattaNotToOverride = destService.createRegatta(TEST_REGATTA_NAME, TEST_BOAT_CLASS_NAME, + regattaUUID, seriesNotToOverride, true, new LowPoint(), courseAreaUUID); + event.addRegatta(regattaNotToOverride); + for (String name : raceColumnNamesNotToOverride) { + seriesNotToOverride.get(0).addRaceColumn(name, destService); + } + + leaderboardNotToOverride = destService.addRegattaLeaderboard( + regattaNotToOverride.getRegattaIdentifier(), "testDisplayNameNotToOverride", discardRule); + List leaderboardNamesNotToOverride = new ArrayList(); + leaderboardNamesNotToOverride.add(leaderboardNotToOverride.getName()); + groupNotToOverride = destService.addLeaderboardGroup(TEST_GROUP_NAME, + "testGroupDescNotToOverride", false, leaderboardNamesNotToOverride, null, null); + InputStream inputStream = new ByteArrayInputStream(outputStream.toByteArray()); + + ois = domainFactory.createObjectInputStreamResolvingAgainstThisFactory(inputStream); + deserializedMasterData = (TopLevelMasterData) ois.readObject(); + } finally { + masterdata.setMasterDataExportFlagOnRaceColumns(false); + oos.close(); + ois.close(); } - - Leaderboard leaderboardToOverride = destService.addRegattaLeaderboard(regattaToOverride.getRegattaIdentifier(), - "testDisplayNameNotToOverride", discardRule); - TrackedRace trackedRace2 = new DummyTrackedRace(new HashSet(), regattaToOverride, null); - RaceColumn columnToOverride = leaderboardToOverride.getRaceColumns().iterator().next(); - columnToOverride.setTrackedRace(testFleet1ToOverride, trackedRace2); - RegattaAndRaceIdentifier identifierOfRegattaTrackedRace = regattaToOverride.getRaceIdentifier(columnToOverride - .getRaceDefinition(testFleet1ToOverride)); - - destService.addLeaderboardGroup(TEST_GROUP_NAME, "testGroupDescToOverride", false, new ArrayList(), - null, null); - destService.getLeaderboardGroupByName(TEST_GROUP_NAME).addLeaderboard(leaderboardToOverride); - destService.addLeaderboard(leaderboardToOverride); - - - // Deserialization copied from SailingServiceImpl - - DomainFactory domainFactory = DomainFactory.INSTANCE; MasterDataImporter importer = new MasterDataImporter(domainFactory, destService); - MasterDataImportObjectCreationCount creationCount = importer.importMasterData( - masterDataOverallObject.toString(), true); + MasterDataImportObjectCreationCount creationCount = importer.importMasterData(deserializedMasterData, false); - - //---Asserts--- - //Test correct number of creations + // ---Asserts--- + // Test correct number of creations Assert.assertNotNull(creationCount); - Assert.assertEquals(1,creationCount.getEventCount()); - Assert.assertEquals(1,creationCount.getRegattaCount()); - Assert.assertEquals(1,creationCount.getLeaderboardCount()); - Assert.assertEquals(1,creationCount.getLeaderboardGroupCount()); - - + Assert.assertEquals(0, creationCount.getEventCount()); + Assert.assertEquals(0, creationCount.getRegattaCount()); + Assert.assertEquals(0, creationCount.getLeaderboardCount()); + Assert.assertEquals(0, creationCount.getLeaderboardGroupCount()); + Event eventOnTarget = destService.getEvent(eventUUID); Assert.assertNotNull(eventOnTarget); - - //Check if existing event didn't survive import - Assert.assertEquals(event.getVenue().getName(), eventOnTarget.getVenue().getName()); - - //Check if existing course area survive import - Assert.assertEquals(courseArea.getName(), eventOnTarget.getVenue().getCourseAreas().iterator().next().getName()); + + // Check if existing event survived import + Assert.assertEquals(venueNameNotToOverride, eventOnTarget.getVenue().getName()); + + // Check if existing course area survived import + Assert.assertEquals(courseAreaNotToOverride.getName(), eventOnTarget.getVenue().getCourseAreas().iterator() + .next().getName()); LeaderboardGroup leaderboardGroupOnTarget = destService.getLeaderboardGroupByName(TEST_GROUP_NAME); Assert.assertNotNull(leaderboardGroupOnTarget); - //Check if existing leaderboard group didn't survive import - Assert.assertEquals(group.getDescription(), leaderboardGroupOnTarget.getDescription()); + // Check if existing leaderboard group survived import + Assert.assertEquals(groupNotToOverride.getDescription(), leaderboardGroupOnTarget.getDescription()); Leaderboard leaderboardOnTarget = destService.getLeaderboardByName(TEST_LEADERBOARD_NAME); Assert.assertNotNull(leaderboardOnTarget); - Regatta regattaOnTarget = destService.getRegattaByName(TEST_REGATTA_NAME + " (" + TEST_BOAT_CLASS_NAME + ")"); + Regatta regattaOnTarget = destService.getRegattaByName(TEST_LEADERBOARD_NAME); Assert.assertNotNull(regattaOnTarget); Assert.assertEquals(courseAreaUUID, eventOnTarget.getVenue().getCourseAreas().iterator().next().getId()); - RaceColumn raceColumnOnTarget = leaderboardOnTarget.getRaceColumnByName(raceColumnName); + RaceColumn raceColumnOnTarget = leaderboardOnTarget.getRaceColumnByName(raceColumnNameNotToOveride); Assert.assertNotNull(raceColumnOnTarget); - //Check if existing leaderboard didn't survive import - Assert.assertEquals(leaderboard.getDisplayName(), leaderboardOnTarget.getDisplayName()); - Assert.assertTrue(leaderboardOnTarget.getScoreCorrection().hasCorrectionFor(raceColumnOnTarget)); - - // Check that tracked race of regatta leaderboard has been removed - Assert.assertNull(destService.getTrackedRace(identifierOfRegattaTrackedRace)); + // Check if existing leaderboard survived import + Assert.assertEquals(leaderboardNotToOverride.getDisplayName(), leaderboardOnTarget.getDisplayName()); + Assert.assertFalse(leaderboardOnTarget.getScoreCorrection().hasCorrectionFor(raceColumnOnTarget)); } - - @Test - public void testMasterDataImportForRegattaDefaultProcedureAndDesigner() throws MalformedURLException, IOException, InterruptedException { - RacingEventService sourceService = new RacingEventServiceImpl(); - Regatta regatta = sourceService.createRegatta(TEST_REGATTA_NAME, TEST_BOAT_CLASS_NAME, UUID.randomUUID(), - new ArrayList(), true, new LowPoint(), null); - // Let's use the setters directly because we are not testing replication - RegattaConfigurationImpl configuration = new RegattaConfigurationImpl(); - configuration.setDefaultCourseDesignerMode(CourseDesignerMode.BY_MAP); - regatta.setRegattaConfiguration(configuration); - - - Leaderboard leaderboard = sourceService.addRegattaLeaderboard(regatta.getRegattaIdentifier(), - "testDisplayName", new int[] { 1, 2, 3, 4 }); - List leaderboardNames = new ArrayList(); - leaderboardNames.add(leaderboard.getName()); - sourceService.addLeaderboardGroup(TEST_GROUP_NAME, "testGroupDesc", false, leaderboardNames, null, null); - - // Serialize - TopLevelMasterDataSerializer serializer = new TopLevelMasterDataSerializer( - sourceService.getLeaderboardGroups(), sourceService.getAllEvents(), sourceService.getPersistentRegattasForRaceIDs(), - sourceService.getAllMediaTracks()); - Set names = new HashSet(); - names.add(TEST_GROUP_NAME); - JSONObject masterDataOverallObject = serializer.serialize(names); - Assert.assertNotNull(masterDataOverallObject); - // Delete all data above from the database, to allow recreating all of it on target server - deleteCreatedDataFromDatabase(); - - RacingEventService destService = new RacingEventServiceImplMock(); - - // Deserialization copied from SailingServiceImpl - DomainFactory domainFactory = DomainFactory.INSTANCE; - MasterDataImporter importer = new MasterDataImporter(domainFactory, destService); - importer.importMasterData(masterDataOverallObject.toString(), false); - - Regatta importedRegatta = destService.getRegattaByName(regatta.getName()); - - assertNotNull(importedRegatta.getRegattaConfiguration()); - assertEquals(CourseDesignerMode.BY_MAP, importedRegatta.getRegattaConfiguration().getDefaultCourseDesignerMode()); - } - @Test - public void testMasterDataImportForRegattaWithoutCourseArea() throws MalformedURLException, IOException, InterruptedException { + public void testMasterDataImportWithOverrideWithoutHttpStack() throws MalformedURLException, IOException, + InterruptedException, ClassNotFoundException { // Setup source service RacingEventService sourceService = new RacingEventServiceImpl(); + Event event = sourceService.addEvent(TEST_EVENT_NAME, "testVenue", "", false, eventUUID); + UUID courseAreaUUID = UUID.randomUUID(); + CourseArea courseArea = new CourseAreaImpl("testArea", courseAreaUUID); + event.getVenue().addCourseArea(courseArea); List raceColumnNames = new ArrayList(); String raceColumnName = "T1"; @@ -1164,17 +1041,20 @@ public class MasterDataImportTest { fleets.add(new FleetImpl("testFleet2")); series.add(new SeriesImpl("testSeries", false, fleets, emptyRaceColumnNamesList, sourceService)); UUID regattaUUID = UUID.randomUUID(); - Regatta regatta = sourceService.createRegatta(TEST_REGATTA_NAME, TEST_BOAT_CLASS_NAME, regattaUUID, series, true, new LowPoint(), - null); + Regatta regatta = sourceService.createRegatta(TEST_REGATTA_NAME, TEST_BOAT_CLASS_NAME, regattaUUID, series, + true, new LowPoint(), courseAreaUUID); + event.addRegatta(regatta); for (String name : raceColumnNames) { series.get(0).addRaceColumn(name, sourceService); } + int[] discardRule = { 1, 2, 3, 4 }; Leaderboard leaderboard = sourceService.addRegattaLeaderboard(regatta.getRegattaIdentifier(), "testDisplayName", discardRule); List leaderboardNames = new ArrayList(); leaderboardNames.add(leaderboard.getName()); - sourceService.addLeaderboardGroup(TEST_GROUP_NAME, "testGroupDesc", false, leaderboardNames, null, null); + LeaderboardGroup group = sourceService.addLeaderboardGroup(TEST_GROUP_NAME, "testGroupDesc", false, + leaderboardNames, null, null); // Set tracked Race with competitors Set competitors = new HashSet(); @@ -1197,19 +1077,18 @@ public class MasterDataImportTest { "Bester Coach"); DynamicTeam team2 = new TeamImpl("Noobs", sailors2, coach2); DynamicBoat boat2 = new BoatImpl("LahmeEnte", boatClass, "GER1337"); - CompetitorImpl competitorToSuppress = new CompetitorImpl(competitorToSuppressUUID, "Merkel", Color.RED, team2, boat2); + CompetitorImpl competitorToSuppress = new CompetitorImpl(competitorToSuppressUUID, "Merkel", Color.RED, team2, + boat2); competitors.add(competitorToSuppress); RaceColumn raceColumn = leaderboard.getRaceColumnByName(raceColumnName); TrackedRace trackedRace = new DummyTrackedRace(competitors, regatta, null); - raceColumn.setTrackedRace(testFleet1, trackedRace); // Set log event RaceLogEventFactory factory = new RaceLogEventFactoryImpl(); TimePoint logTimePoint = new MillisecondsTimePoint(1372489200000L); - RaceLogStartTimeEvent logEvent = factory.createStartTimeEvent(logTimePoint, author, 1, - logTimePoint); + RaceLogStartTimeEvent logEvent = factory.createStartTimeEvent(logTimePoint, author, 1, logTimePoint); raceColumn.getRaceLog(testFleet1).add(logEvent); storedLogUUIDs.add(logEvent.getId()); @@ -1231,42 +1110,306 @@ public class MasterDataImportTest { leaderboard.setDisplayName(competitorToSuppress, nickName); // Serialize - TopLevelMasterDataSerializer serializer = new TopLevelMasterDataSerializer( - sourceService.getLeaderboardGroups(), sourceService.getAllEvents(), sourceService.getPersistentRegattasForRaceIDs(), - sourceService.getAllMediaTracks()); - Set names = new HashSet(); - names.add(TEST_GROUP_NAME); - JSONObject masterDataOverallObject = serializer.serialize(names); - Assert.assertNotNull(masterDataOverallObject); + HashSet groupsToExport = new HashSet(); + groupsToExport.add(group); + TopLevelMasterData masterdata = new TopLevelMasterData(groupsToExport, sourceService.getAllEvents(), + sourceService.getPersistentRegattasForRaceIDs(), sourceService.getAllMediaTracks()); + Assert.assertNotNull(masterdata); - // Delete all data above from the database, to allow recreating all of it on target server - deleteCreatedDataFromDatabase(); - - RacingEventService destService = new RacingEventServiceImplMock(); - + ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); + ObjectOutputStream oos = new ObjectOutputStream(outputStream); + RacingEventService destService; + ObjectInputStream ois = null; + TopLevelMasterData deserializedMasterData; + DomainFactory domainFactory; + RegattaAndRaceIdentifier identifierOfRegattaTrackedRace; + try { + masterdata.setMasterDataExportFlagOnRaceColumns(true); + oos.writeObject(masterdata); - // Deserialization copied from SailingServiceImpl - - DomainFactory domainFactory = DomainFactory.INSTANCE; + outputStream.flush(); + // Delete all data above from the database, to allow recreating all of it on target server + deleteCreatedDataFromDatabase(); + // Import in new service + destService = new RacingEventServiceImplMock(); + domainFactory = destService.getBaseDomainFactory(); + // Create existing data on target + String venueNameToOverride = "Override"; + Event eventToOverride = destService.addEvent(TEST_EVENT_NAME, venueNameToOverride, "", false, eventUUID); + CourseArea courseAreaToOverride = new CourseAreaImpl("testAreaToOverride", courseAreaUUID); + eventToOverride.getVenue().addCourseArea(courseAreaToOverride); + + List raceColumnNamesToOverride = new ArrayList(); + String raceColumnNameToOveride = raceColumnName; + raceColumnNamesToOverride.add(raceColumnNameToOveride); + emptyRaceColumnNamesList = Collections.emptyList(); + + List seriesToOverride = new ArrayList(); + List fleetsToOverride = new ArrayList(); + FleetImpl testFleet1ToOverride = new FleetImpl("testFleet1"); + fleetsToOverride.add(testFleet1ToOverride); + seriesToOverride.add(new SeriesImpl("testSeries", false, fleetsToOverride, emptyRaceColumnNamesList, + destService)); + Regatta regattaToOverride = destService.createRegatta(TEST_REGATTA_NAME, TEST_BOAT_CLASS_NAME, regattaUUID, + seriesToOverride, true, new LowPoint(), courseAreaUUID); + event.addRegatta(regattaToOverride); + for (String name : raceColumnNamesToOverride) { + seriesToOverride.get(0).addRaceColumn(name, destService); + } + + Leaderboard leaderboardToOverride = destService.addRegattaLeaderboard( + regattaToOverride.getRegattaIdentifier(), "testDisplayNameNotToOverride", discardRule); + TrackedRace trackedRace2 = new DummyTrackedRace(new HashSet(), regattaToOverride, null); + RaceColumn columnToOverride = leaderboardToOverride.getRaceColumns().iterator().next(); + columnToOverride.setTrackedRace(testFleet1ToOverride, trackedRace2); + identifierOfRegattaTrackedRace = regattaToOverride + .getRaceIdentifier(columnToOverride.getRaceDefinition(testFleet1ToOverride)); + + destService.addLeaderboardGroup(TEST_GROUP_NAME, "testGroupDescToOverride", false, new ArrayList(), + null, null); + destService.getLeaderboardGroupByName(TEST_GROUP_NAME).addLeaderboard(leaderboardToOverride); + destService.addLeaderboard(leaderboardToOverride); + InputStream inputStream = new ByteArrayInputStream(outputStream.toByteArray()); + + ois = domainFactory.createObjectInputStreamResolvingAgainstThisFactory(inputStream); + deserializedMasterData = (TopLevelMasterData) ois.readObject(); + } finally { + masterdata.setMasterDataExportFlagOnRaceColumns(false); + oos.close(); + ois.close(); + } MasterDataImporter importer = new MasterDataImporter(domainFactory, destService); - MasterDataImportObjectCreationCount creationCount = importer.importMasterData( - masterDataOverallObject.toString(), false); + MasterDataImportObjectCreationCount creationCount = importer.importMasterData(deserializedMasterData, true); - - //---Asserts--- + // ---Asserts--- + // Test correct number of creations + Assert.assertNotNull(creationCount); + Assert.assertEquals(1, creationCount.getEventCount()); + Assert.assertEquals(1, creationCount.getRegattaCount()); + Assert.assertEquals(1, creationCount.getLeaderboardCount()); + Assert.assertEquals(1, creationCount.getLeaderboardGroupCount()); + + Event eventOnTarget = destService.getEvent(eventUUID); + Assert.assertNotNull(eventOnTarget); + + // Check if existing event didn't survive import + Assert.assertEquals(event.getVenue().getName(), eventOnTarget.getVenue().getName()); + + // Check if existing course area survive import + Assert.assertEquals(courseArea.getName(), eventOnTarget.getVenue().getCourseAreas().iterator().next().getName()); + LeaderboardGroup leaderboardGroupOnTarget = destService.getLeaderboardGroupByName(TEST_GROUP_NAME); + Assert.assertNotNull(leaderboardGroupOnTarget); + // Check if existing leaderboard group didn't survive import + Assert.assertEquals(group.getDescription(), leaderboardGroupOnTarget.getDescription()); + Leaderboard leaderboardOnTarget = destService.getLeaderboardByName(TEST_LEADERBOARD_NAME); + Assert.assertNotNull(leaderboardOnTarget); + Regatta regattaOnTarget = destService.getRegattaByName(TEST_REGATTA_NAME + " (" + TEST_BOAT_CLASS_NAME + ")"); + Assert.assertNotNull(regattaOnTarget); + + Assert.assertEquals(courseAreaUUID, eventOnTarget.getVenue().getCourseAreas().iterator().next().getId()); + + RaceColumn raceColumnOnTarget = leaderboardOnTarget.getRaceColumnByName(raceColumnName); + Assert.assertNotNull(raceColumnOnTarget); + // Check if existing leaderboard didn't survive import + Assert.assertEquals(leaderboard.getDisplayName(), leaderboardOnTarget.getDisplayName()); + Assert.assertTrue(leaderboardOnTarget.getScoreCorrection().hasCorrectionFor(raceColumnOnTarget)); + + // Check that tracked race of regatta leaderboard has been removed + Assert.assertNull(destService.getTrackedRace(identifierOfRegattaTrackedRace)); + + } + + @Test + public void testMasterDataImportForRegattaDefaultProcedureAndDesigner() throws MalformedURLException, IOException, + InterruptedException, ClassNotFoundException { + RacingEventService sourceService = new RacingEventServiceImpl(); + Regatta regatta = sourceService.createRegatta(TEST_REGATTA_NAME, TEST_BOAT_CLASS_NAME, UUID.randomUUID(), + new ArrayList(), true, new LowPoint(), null); + // Let's use the setters directly because we are not testing replication + RegattaConfigurationImpl configuration = new RegattaConfigurationImpl(); + configuration.setDefaultCourseDesignerMode(CourseDesignerMode.BY_MAP); + regatta.setRegattaConfiguration(configuration); + + Leaderboard leaderboard = sourceService.addRegattaLeaderboard(regatta.getRegattaIdentifier(), + "testDisplayName", new int[] { 1, 2, 3, 4 }); + List leaderboardNames = new ArrayList(); + leaderboardNames.add(leaderboard.getName()); + LeaderboardGroup group = sourceService.addLeaderboardGroup(TEST_GROUP_NAME, "testGroupDesc", false, + leaderboardNames, null, null); + + // Serialize + HashSet groupsToExport = new HashSet(); + groupsToExport.add(group); + TopLevelMasterData masterdata = new TopLevelMasterData(groupsToExport, sourceService.getAllEvents(), + sourceService.getPersistentRegattasForRaceIDs(), sourceService.getAllMediaTracks()); + Assert.assertNotNull(masterdata); + + ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); + ObjectOutputStream oos = new ObjectOutputStream(outputStream); + RacingEventService destService; + ObjectInputStream ois = null; + TopLevelMasterData deserializedMasterData; + DomainFactory domainFactory; + try { + masterdata.setMasterDataExportFlagOnRaceColumns(true); + oos.writeObject(masterdata); + + outputStream.flush(); + // Delete all data above from the database, to allow recreating all of it on target server + deleteCreatedDataFromDatabase(); + // Import in new service + destService = new RacingEventServiceImplMock(); + domainFactory = destService.getBaseDomainFactory(); + InputStream inputStream = new ByteArrayInputStream(outputStream.toByteArray()); + + ois = domainFactory.createObjectInputStreamResolvingAgainstThisFactory(inputStream); + deserializedMasterData = (TopLevelMasterData) ois.readObject(); + } finally { + masterdata.setMasterDataExportFlagOnRaceColumns(false); + oos.close(); + ois.close(); + } + MasterDataImporter importer = new MasterDataImporter(domainFactory, destService); + importer.importMasterData(deserializedMasterData, false); + + Regatta importedRegatta = destService.getRegattaByName(regatta.getName()); + + assertNotNull(importedRegatta.getRegattaConfiguration()); + assertEquals(CourseDesignerMode.BY_MAP, importedRegatta.getRegattaConfiguration() + .getDefaultCourseDesignerMode()); + } + + @Test + public void testMasterDataImportForRegattaWithoutCourseArea() throws MalformedURLException, IOException, + InterruptedException, ClassNotFoundException { + // Setup source service + RacingEventService sourceService = new RacingEventServiceImpl(); + + List raceColumnNames = new ArrayList(); + String raceColumnName = "T1"; + raceColumnNames.add(raceColumnName); + raceColumnNames.add("T2"); + List emptyRaceColumnNamesList = Collections.emptyList(); + + List series = new ArrayList(); + List fleets = new ArrayList(); + FleetImpl testFleet1 = new FleetImpl("testFleet1"); + fleets.add(testFleet1); + fleets.add(new FleetImpl("testFleet2")); + series.add(new SeriesImpl("testSeries", false, fleets, emptyRaceColumnNamesList, sourceService)); + UUID regattaUUID = UUID.randomUUID(); + Regatta regatta = sourceService.createRegatta(TEST_REGATTA_NAME, TEST_BOAT_CLASS_NAME, regattaUUID, series, + true, new LowPoint(), null); + for (String name : raceColumnNames) { + series.get(0).addRaceColumn(name, sourceService); + } + int[] discardRule = { 1, 2, 3, 4 }; + Leaderboard leaderboard = sourceService.addRegattaLeaderboard(regatta.getRegattaIdentifier(), + "testDisplayName", discardRule); + List leaderboardNames = new ArrayList(); + leaderboardNames.add(leaderboard.getName()); + LeaderboardGroup group = sourceService.addLeaderboardGroup(TEST_GROUP_NAME, "testGroupDesc", false, + leaderboardNames, null, null); + + // Set tracked Race with competitors + Set competitors = new HashSet(); + UUID competitorUUID = UUID.randomUUID(); + Set sailors = new HashSet(); + sailors.add(new PersonImpl("Froderik Poterson", new NationalityImpl("GER"), new Date(645487200000L), + "Oberhoschy")); + Person coach = new PersonImpl("Lennart Hensler", new NationalityImpl("GER"), new Date(645487200000L), + "Der Lennart halt"); + DynamicTeam team = new TeamImpl("Pros", sailors, coach); + BoatClass boatClass = new BoatClassImpl("H16", true); + DynamicBoat boat = new BoatImpl("Wingy", boatClass, "GER70133"); + CompetitorImpl competitor = new CompetitorImpl(competitorUUID, "Froderik", Color.RED, team, boat); + competitors.add(competitor); + UUID competitorToSuppressUUID = UUID.randomUUID(); + Set sailors2 = new HashSet(); + sailors2.add(new PersonImpl("Angela Merkel", new NationalityImpl("GER"), new Date(645487200000L), + "segelt auch mit")); + Person coach2 = new PersonImpl("Peer Steinbrueck", new NationalityImpl("GER"), new Date(645487200000L), + "Bester Coach"); + DynamicTeam team2 = new TeamImpl("Noobs", sailors2, coach2); + DynamicBoat boat2 = new BoatImpl("LahmeEnte", boatClass, "GER1337"); + CompetitorImpl competitorToSuppress = new CompetitorImpl(competitorToSuppressUUID, "Merkel", Color.RED, team2, + boat2); + competitors.add(competitorToSuppress); + RaceColumn raceColumn = leaderboard.getRaceColumnByName(raceColumnName); + TrackedRace trackedRace = new DummyTrackedRace(competitors, regatta, null); + + raceColumn.setTrackedRace(testFleet1, trackedRace); + + // Set log event + RaceLogEventFactory factory = new RaceLogEventFactoryImpl(); + TimePoint logTimePoint = new MillisecondsTimePoint(1372489200000L); + RaceLogStartTimeEvent logEvent = factory.createStartTimeEvent(logTimePoint, author, 1, logTimePoint); + raceColumn.getRaceLog(testFleet1).add(logEvent); + storedLogUUIDs.add(logEvent.getId()); + + // Set score correction + double scoreCorrection = 12.0; + leaderboard.getScoreCorrection().correctScore(competitor, raceColumn, scoreCorrection); + MaxPointsReason maxPointsReason = MaxPointsReason.DNS; + leaderboard.getScoreCorrection().setMaxPointsReason(competitor, raceColumn, maxPointsReason); + + // Set carried Points + double carriedPoints = 2.0; + leaderboard.setCarriedPoints(competitor, carriedPoints); + + // Set suppressed competitor + leaderboard.setSuppressed(competitorToSuppress, true); + + // Set display name + String nickName = "Angie"; + leaderboard.setDisplayName(competitorToSuppress, nickName); + + // Serialize + HashSet groupsToExport = new HashSet(); + groupsToExport.add(group); + TopLevelMasterData masterdata = new TopLevelMasterData(groupsToExport, sourceService.getAllEvents(), + sourceService.getPersistentRegattasForRaceIDs(), sourceService.getAllMediaTracks()); + Assert.assertNotNull(masterdata); + + ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); + ObjectOutputStream oos = new ObjectOutputStream(outputStream); + RacingEventService destService; + ObjectInputStream ois = null; + TopLevelMasterData deserializedMasterData; + DomainFactory domainFactory; + try { + masterdata.setMasterDataExportFlagOnRaceColumns(true); + oos.writeObject(masterdata); + + outputStream.flush(); + // Delete all data above from the database, to allow recreating all of it on target server + deleteCreatedDataFromDatabase(); + // Import in new service + destService = new RacingEventServiceImplMock(); + domainFactory = destService.getBaseDomainFactory(); + InputStream inputStream = new ByteArrayInputStream(outputStream.toByteArray()); + + ois = domainFactory.createObjectInputStreamResolvingAgainstThisFactory(inputStream); + deserializedMasterData = (TopLevelMasterData) ois.readObject(); + } finally { + masterdata.setMasterDataExportFlagOnRaceColumns(false); + oos.close(); + ois.close(); + } + MasterDataImporter importer = new MasterDataImporter(domainFactory, destService); + MasterDataImportObjectCreationCount creationCount = importer.importMasterData(deserializedMasterData, false); + + // ---Asserts--- Assert.assertNotNull(creationCount); - - //Check if existing event survived import + // Check if existing event survived import Assert.assertNotNull(destService.getRegattaByName(regatta.getName())); - - - + } - + @Test public void testMasterDataImportForPersistentRegattaRaceIDsWithoutHttpStack() throws MalformedURLException, - IOException, InterruptedException { + IOException, InterruptedException, ClassNotFoundException { // Setup source service RacingEventService sourceService = new RacingEventServiceImpl(); Event event = sourceService.addEvent(TEST_EVENT_NAME, "testVenue", "", false, eventUUID); @@ -1287,20 +1430,20 @@ public class MasterDataImportTest { fleets.add(new FleetImpl("testFleet2")); series.add(new SeriesImpl("testSeries", false, fleets, emptyRaceColumnNamesList, sourceService)); UUID regattaUUID = UUID.randomUUID(); - Regatta regatta = sourceService.createRegatta(TEST_REGATTA_NAME, TEST_BOAT_CLASS_NAME, regattaUUID, series, true, new LowPoint(), - courseAreaUUID); + Regatta regatta = sourceService.createRegatta(TEST_REGATTA_NAME, TEST_BOAT_CLASS_NAME, regattaUUID, series, + true, new LowPoint(), courseAreaUUID); event.addRegatta(regatta); for (String name : raceColumnNames) { series.get(0).addRaceColumn(name, sourceService); } - - + int[] discardRule = { 1, 2, 3, 4 }; Leaderboard leaderboard = sourceService.addRegattaLeaderboard(regatta.getRegattaIdentifier(), "testDisplayName", discardRule); List leaderboardNames = new ArrayList(); leaderboardNames.add(leaderboard.getName()); - sourceService.addLeaderboardGroup(TEST_GROUP_NAME, "testGroupDesc", false, leaderboardNames, null, null); + LeaderboardGroup group = sourceService.addLeaderboardGroup(TEST_GROUP_NAME, "testGroupDesc", false, + leaderboardNames, null, null); // Set tracked Race with competitors Set competitors = new HashSet(); @@ -1323,16 +1466,16 @@ public class MasterDataImportTest { "Bester Coach"); DynamicTeam team2 = new TeamImpl("Noobs", sailors2, coach2); DynamicBoat boat2 = new BoatImpl("LahmeEnte", boatClass, "GER1337"); - CompetitorImpl competitorToSuppress = new CompetitorImpl(competitorToSuppressUUID, "Merkel", Color.RED, team2, boat2); + CompetitorImpl competitorToSuppress = new CompetitorImpl(competitorToSuppressUUID, "Merkel", Color.RED, team2, + boat2); competitors.add(competitorToSuppress); RaceColumn raceColumn = leaderboard.getRaceColumnByName(raceColumnName); TrackedRace trackedRace = new DummyTrackedRace(competitors, regatta, null); - raceColumn.setTrackedRace(testFleet1, trackedRace); Set raceIds = new HashSet(); raceIds.add("dummy"); - + sourceService.setPersistentRegattaForRaceIDs(regatta, raceIds, false); // Set log event @@ -1360,25 +1503,39 @@ public class MasterDataImportTest { leaderboard.setDisplayName(competitorToSuppress, nickName); // Serialize - TopLevelMasterDataSerializer serializer = new TopLevelMasterDataSerializer( - sourceService.getLeaderboardGroups(), sourceService.getAllEvents(), + HashSet groupsToExport = new HashSet(); + groupsToExport.add(group); + TopLevelMasterData masterdata = new TopLevelMasterData(groupsToExport, sourceService.getAllEvents(), sourceService.getPersistentRegattasForRaceIDs(), sourceService.getAllMediaTracks()); - Set names = new HashSet(); - names.add(TEST_GROUP_NAME); - JSONObject masterDataOverallObject = serializer.serialize(names); - Assert.assertNotNull(masterDataOverallObject); + Assert.assertNotNull(masterdata); - // Delete all data above from the database, to allow recreating all of it on target server - deleteCreatedDataFromDatabase(); + ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); + ObjectOutputStream oos = new ObjectOutputStream(outputStream); + RacingEventService destService; + ObjectInputStream ois = null; + TopLevelMasterData deserializedMasterData; + DomainFactory domainFactory; + try { + masterdata.setMasterDataExportFlagOnRaceColumns(true); + oos.writeObject(masterdata); - // Deserialization copied from SailingServiceImpl + outputStream.flush(); + // Delete all data above from the database, to allow recreating all of it on target server + deleteCreatedDataFromDatabase(); + // Import in new service + destService = new RacingEventServiceImplMock(); + domainFactory = destService.getBaseDomainFactory(); + InputStream inputStream = new ByteArrayInputStream(outputStream.toByteArray()); - RacingEventService destService = new RacingEventServiceImplMock(); - DomainFactory domainFactory = DomainFactory.INSTANCE; + ois = domainFactory.createObjectInputStreamResolvingAgainstThisFactory(inputStream); + deserializedMasterData = (TopLevelMasterData) ois.readObject(); + } finally { + masterdata.setMasterDataExportFlagOnRaceColumns(false); + oos.close(); + ois.close(); + } MasterDataImporter importer = new MasterDataImporter(domainFactory, destService); - MasterDataImportObjectCreationCount creationCount = importer.importMasterData( - masterDataOverallObject.toString(), false); - + MasterDataImportObjectCreationCount creationCount = importer.importMasterData(deserializedMasterData, false); // ---Asserts--- @@ -1388,60 +1545,75 @@ public class MasterDataImportTest { Regatta regattaOnTarget = destService.getRegattaByName(TEST_LEADERBOARD_NAME); Assert.assertNotNull(regattaOnTarget); - - //Check if dummy race id has been imported to destination service + + // Check if dummy race id has been imported to destination service ConcurrentHashMap map = destService.getPersistentRegattasForRaceIDs(); Assert.assertEquals(regattaOnTarget, map.get("dummy")); } - + @Test - public void testMasterDataImportForMediaTracks() throws MalformedURLException, - IOException, InterruptedException { + public void testMasterDataImportForMediaTracks() throws MalformedURLException, IOException, InterruptedException, + ClassNotFoundException { // Setup source service RacingEventService sourceService = new RacingEventServiceImpl(); - MediaTrack trackOnSource = new MediaTrack("test", "testTitle", "http://test/test.mp4", new Date(0), - 2000, MediaTrack.MimeType.mp4); + MediaTrack trackOnSource = new MediaTrack("test", "testTitle", "http://test/test.mp4", new Date(0), 2000, + MediaTrack.MimeType.mp4); sourceService.mediaTrackAdded(trackOnSource); // Serialize - TopLevelMasterDataSerializer serializer = new TopLevelMasterDataSerializer( - sourceService.getLeaderboardGroups(), sourceService.getAllEvents(), + HashSet groupsToExport = new HashSet(); + TopLevelMasterData masterdata = new TopLevelMasterData(groupsToExport, sourceService.getAllEvents(), sourceService.getPersistentRegattasForRaceIDs(), sourceService.getAllMediaTracks()); - Set names = new HashSet(); - JSONObject masterDataOverallObject = serializer.serialize(names); - Assert.assertNotNull(masterDataOverallObject); + Assert.assertNotNull(masterdata); - // Delete all data above from the database, to allow recreating all of it on target server - deleteCreatedDataFromDatabase(); + ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); + ObjectOutputStream oos = new ObjectOutputStream(outputStream); + RacingEventService destService; + ObjectInputStream ois = null; + TopLevelMasterData deserializedMasterData; + DomainFactory domainFactory; + try { + masterdata.setMasterDataExportFlagOnRaceColumns(true); + oos.writeObject(masterdata); - // Deserialization copied from SailingServiceImpl + outputStream.flush(); + // Delete all data above from the database, to allow recreating all of it on target server + deleteCreatedDataFromDatabase(); + // Import in new service + destService = new RacingEventServiceImplMock(); + domainFactory = destService.getBaseDomainFactory(); + InputStream inputStream = new ByteArrayInputStream(outputStream.toByteArray()); - RacingEventService destService = new RacingEventServiceImplMock(); - DomainFactory domainFactory = DomainFactory.INSTANCE; + ois = domainFactory.createObjectInputStreamResolvingAgainstThisFactory(inputStream); + deserializedMasterData = (TopLevelMasterData) ois.readObject(); + } finally { + masterdata.setMasterDataExportFlagOnRaceColumns(false); + oos.close(); + ois.close(); + } MasterDataImporter importer = new MasterDataImporter(domainFactory, destService); - MasterDataImportObjectCreationCount creationCount = importer.importMasterData( - masterDataOverallObject.toString(), false); - + MasterDataImportObjectCreationCount creationCount = importer.importMasterData(deserializedMasterData, false); // ---Asserts--- Assert.assertNotNull(creationCount); - + Collection targetTracks = destService.getAllMediaTracks(); - + Assert.assertEquals(1, targetTracks.size()); - + MediaTrack trackOnTarget = targetTracks.iterator().next(); - + Assert.assertEquals(trackOnSource.dbId, trackOnTarget.dbId); - + Assert.assertEquals(trackOnSource.url, trackOnTarget.url); } - + @Test - public void testMasterDataImportWithTwoLgsWithSameLeaderboard() throws MalformedURLException, IOException, InterruptedException { + public void testMasterDataImportWithTwoLgsWithSameLeaderboard() throws MalformedURLException, IOException, + InterruptedException, ClassNotFoundException { // Setup source service RacingEventService sourceService = new RacingEventServiceImpl(); Event event = sourceService.addEvent(TEST_EVENT_NAME, "testVenue", "", false, eventUUID); @@ -1462,20 +1634,22 @@ public class MasterDataImportTest { fleets.add(new FleetImpl("testFleet2")); series.add(new SeriesImpl("testSeries", false, fleets, emptyRaceColumnNamesList, sourceService)); UUID regattaUUID = UUID.randomUUID(); - Regatta regatta = sourceService.createRegatta(TEST_REGATTA_NAME, TEST_BOAT_CLASS_NAME, regattaUUID, series, true, new LowPoint(), - courseAreaUUID); + Regatta regatta = sourceService.createRegatta(TEST_REGATTA_NAME, TEST_BOAT_CLASS_NAME, regattaUUID, series, + true, new LowPoint(), courseAreaUUID); event.addRegatta(regatta); for (String name : raceColumnNames) { series.get(0).addRaceColumn(name, sourceService); } - + int[] discardRule = { 1, 2, 3, 4 }; Leaderboard leaderboard = sourceService.addRegattaLeaderboard(regatta.getRegattaIdentifier(), "testDisplayName", discardRule); List leaderboardNames = new ArrayList(); leaderboardNames.add(leaderboard.getName()); - sourceService.addLeaderboardGroup(TEST_GROUP_NAME, "testGroupDesc", false, leaderboardNames, null, null); - sourceService.addLeaderboardGroup(TEST_GROUP_NAME2, "testGroupDesc2", false, leaderboardNames, null, null); + LeaderboardGroup group1 = sourceService.addLeaderboardGroup(TEST_GROUP_NAME, "testGroupDesc", false, + leaderboardNames, null, null); + LeaderboardGroup group2 = sourceService.addLeaderboardGroup(TEST_GROUP_NAME2, "testGroupDesc2", false, + leaderboardNames, null, null); // Set tracked Race with competitors Set competitors = new HashSet(); @@ -1498,44 +1672,58 @@ public class MasterDataImportTest { "Bester Coach"); DynamicTeam team2 = new TeamImpl("Noobs", sailors2, coach2); DynamicBoat boat2 = new BoatImpl("LahmeEnte", boatClass, "GER1337"); - CompetitorImpl competitorToSuppress = new CompetitorImpl(competitorToSuppressUUID, "Merkel", Color.RED, team2, boat2); + CompetitorImpl competitorToSuppress = new CompetitorImpl(competitorToSuppressUUID, "Merkel", Color.RED, team2, + boat2); competitors.add(competitorToSuppress); RaceColumn raceColumn = leaderboard.getRaceColumnByName(raceColumnName); TrackedRace trackedRace = new DummyTrackedRace(competitors, regatta, null); - raceColumn.setTrackedRace(testFleet1, trackedRace); // Serialize - TopLevelMasterDataSerializer serializer = new TopLevelMasterDataSerializer( - sourceService.getLeaderboardGroups(), sourceService.getAllEvents(), + HashSet groupsToExport = new HashSet(); + groupsToExport.add(group1); + groupsToExport.add(group2); + TopLevelMasterData masterdata = new TopLevelMasterData(groupsToExport, sourceService.getAllEvents(), sourceService.getPersistentRegattasForRaceIDs(), sourceService.getAllMediaTracks()); - Set names = new HashSet(); - names.add(TEST_GROUP_NAME); - names.add(TEST_GROUP_NAME2); - JSONObject masterDataOverallObject = serializer.serialize(names); - Assert.assertNotNull(masterDataOverallObject); + Assert.assertNotNull(masterdata); - // Delete all data above from the database, to allow recreating all of it on target server - deleteCreatedDataFromDatabase(); + ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); + ObjectOutputStream oos = new ObjectOutputStream(outputStream); + RacingEventService destService; + ObjectInputStream ois = null; + TopLevelMasterData deserializedMasterData; + DomainFactory domainFactory; + try { + masterdata.setMasterDataExportFlagOnRaceColumns(true); + oos.writeObject(masterdata); - // Deserialization copied from doPost in MasterDataByLeaderboardGroupJsonPostServlet - RacingEventService destService = new RacingEventServiceImplMock(); - DomainFactory domainFactory = DomainFactory.INSTANCE; + outputStream.flush(); + // Delete all data above from the database, to allow recreating all of it on target server + deleteCreatedDataFromDatabase(); + // Import in new service + destService = new RacingEventServiceImplMock(); + domainFactory = destService.getBaseDomainFactory(); + InputStream inputStream = new ByteArrayInputStream(outputStream.toByteArray()); + + ois = domainFactory.createObjectInputStreamResolvingAgainstThisFactory(inputStream); + deserializedMasterData = (TopLevelMasterData) ois.readObject(); + } finally { + masterdata.setMasterDataExportFlagOnRaceColumns(false); + oos.close(); + ois.close(); + } MasterDataImporter importer = new MasterDataImporter(domainFactory, destService); - //Test in override model, to find out if data that was created during import is overriden later on - // in the same import process. Number of creations is checked below. - MasterDataImportObjectCreationCount creationCount = importer.importMasterData( - masterDataOverallObject.toString(), true); + MasterDataImportObjectCreationCount creationCount = importer.importMasterData(deserializedMasterData, false); - //Test correct number of creations + // Test correct number of creations Assert.assertNotNull(creationCount); - Assert.assertEquals(1,creationCount.getEventCount()); - Assert.assertEquals(1,creationCount.getRegattaCount()); - Assert.assertEquals(1,creationCount.getLeaderboardCount()); - Assert.assertEquals(2,creationCount.getLeaderboardGroupCount()); - + Assert.assertEquals(1, creationCount.getEventCount()); + Assert.assertEquals(1, creationCount.getRegattaCount()); + Assert.assertEquals(1, creationCount.getLeaderboardCount()); + Assert.assertEquals(2, creationCount.getLeaderboardGroupCount()); + Event eventOnTarget = destService.getEvent(eventUUID); Assert.assertNotNull(eventOnTarget); LeaderboardGroup leaderboardGroupOnTarget = destService.getLeaderboardGroupByName(TEST_GROUP_NAME); @@ -1544,90 +1732,106 @@ public class MasterDataImportTest { LeaderboardGroup leaderboardGroup2OnTarget = destService.getLeaderboardGroupByName(TEST_GROUP_NAME2); Assert.assertNotNull(leaderboardGroup2OnTarget); Assert.assertTrue(leaderboardGroup2OnTarget.getLeaderboards().iterator().hasNext()); - + } - + @Test - public void testMasterDataImportWithOverallLeaderboard() throws MalformedURLException, IOException, InterruptedException { + public void testMasterDataImportWithOverallLeaderboard() throws MalformedURLException, IOException, + InterruptedException, ClassNotFoundException { // Setup source service RacingEventService sourceService = new RacingEventServiceImpl(); int[] discardRule = { 1, 2, 3, 4 }; ScoringScheme scheme = new LowPoint(); List leaderboardNames = new ArrayList(); - LeaderboardGroup sourceGroup = sourceService.addLeaderboardGroup(TEST_GROUP_NAME, "testGroupDesc", false, + LeaderboardGroup sourceGroup = sourceService.addLeaderboardGroup(TEST_GROUP_NAME, "testGroupDesc", false, leaderboardNames, discardRule, scheme.getType()); FlexibleLeaderboard sourceLeaderboard1 = new FlexibleLeaderboardImpl("Leaderboard1", null, scheme, null); sourceService.addLeaderboard(sourceLeaderboard1); sourceGroup.addLeaderboard(sourceLeaderboard1); - - LeaderboardGroupMetaLeaderboard metaLeaderboard = (LeaderboardGroupMetaLeaderboard) sourceGroup.getOverallLeaderboard(); + + LeaderboardGroupMetaLeaderboard metaLeaderboard = (LeaderboardGroupMetaLeaderboard) sourceGroup + .getOverallLeaderboard(); double factor = 2.6; metaLeaderboard.getRaceColumns().iterator().next().setFactor(factor); - + // Serialize - TopLevelMasterDataSerializer serializer = new TopLevelMasterDataSerializer( - sourceService.getLeaderboardGroups(), sourceService.getAllEvents(), + HashSet groupsToExport = new HashSet(); + groupsToExport.add(sourceGroup); + TopLevelMasterData masterdata = new TopLevelMasterData(groupsToExport, sourceService.getAllEvents(), sourceService.getPersistentRegattasForRaceIDs(), sourceService.getAllMediaTracks()); - Set names = new HashSet(); - names.add(TEST_GROUP_NAME); - JSONObject masterDataOverallObject = serializer.serialize(names); - Assert.assertNotNull(masterDataOverallObject); + Assert.assertNotNull(masterdata); - // Delete all data above from the database, to allow recreating all of it on target server - deleteCreatedDataFromDatabase(); + ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); + ObjectOutputStream oos = new ObjectOutputStream(outputStream); + RacingEventService destService; + ObjectInputStream ois = null; + TopLevelMasterData deserializedMasterData; + DomainFactory domainFactory; + try { + masterdata.setMasterDataExportFlagOnRaceColumns(true); + oos.writeObject(masterdata); - // Deserialization copied from doPost in MasterDataByLeaderboardGroupJsonPostServlet - RacingEventService destService = new RacingEventServiceImplMock(); - DomainFactory domainFactory = DomainFactory.INSTANCE; + outputStream.flush(); + // Delete all data above from the database, to allow recreating all of it on target server + deleteCreatedDataFromDatabase(); + // Import in new service + destService = new RacingEventServiceImplMock(); + domainFactory = destService.getBaseDomainFactory(); + InputStream inputStream = new ByteArrayInputStream(outputStream.toByteArray()); + + ois = domainFactory.createObjectInputStreamResolvingAgainstThisFactory(inputStream); + deserializedMasterData = (TopLevelMasterData) ois.readObject(); + } finally { + masterdata.setMasterDataExportFlagOnRaceColumns(false); + oos.close(); + ois.close(); + } MasterDataImporter importer = new MasterDataImporter(domainFactory, destService); - //Test in override model, to find out if data that was created during import is overriden later on - // in the same import process. Number of creations is checked below. - MasterDataImportObjectCreationCount creationCount = importer.importMasterData( - masterDataOverallObject.toString(), true); + MasterDataImportObjectCreationCount creationCount = importer.importMasterData(deserializedMasterData, false); + + // Test correct number of creations + Assert.assertEquals(1, creationCount.getLeaderboardGroupCount()); - //Test correct number of creations - Assert.assertEquals(1,creationCount.getLeaderboardGroupCount()); - LeaderboardGroup leaderboardGroupOnTarget = destService.getLeaderboardGroupByName(TEST_GROUP_NAME); Assert.assertNotNull(leaderboardGroupOnTarget); - LeaderboardGroupMetaLeaderboard overallLeaderboard = (LeaderboardGroupMetaLeaderboard) leaderboardGroupOnTarget.getOverallLeaderboard(); + LeaderboardGroupMetaLeaderboard overallLeaderboard = (LeaderboardGroupMetaLeaderboard) leaderboardGroupOnTarget + .getOverallLeaderboard(); Assert.assertNotNull(overallLeaderboard); - + Assert.assertNotNull(overallLeaderboard.getResultDiscardingRule()); - + Assert.assertNotNull(overallLeaderboard.getScoringScheme()); - + Assert.assertEquals(scheme.getType(), overallLeaderboard.getScoringScheme().getType()); Assert.assertEquals(3, ((ThresholdBasedResultDiscardingRule) overallLeaderboard.getResultDiscardingRule()) .getDiscardIndexResultsStartingWithHowManyRaces()[2]); - + Iterable metaColumns = overallLeaderboard.getRaceColumns(); - + RaceColumn metaColumn = metaColumns.iterator().next(); Assert.assertNotNull(metaColumn); Assert.assertEquals(factor, metaColumn.getFactor()); - - - //Verify that overall leaderboard data has been persisted + + // Verify that overall leaderboard data has been persisted RacingEventService persistenceVerifier = new RacingEventServiceImplMock(); LeaderboardGroup lg = persistenceVerifier.getLeaderboardGroupByName(TEST_GROUP_NAME); Assert.assertNotNull(lg); overallLeaderboard = (LeaderboardGroupMetaLeaderboard) lg.getOverallLeaderboard(); Assert.assertNotNull(overallLeaderboard); - + Assert.assertNotNull(overallLeaderboard.getResultDiscardingRule()); - + Assert.assertNotNull(overallLeaderboard.getScoringScheme()); - + Assert.assertEquals(scheme.getType(), overallLeaderboard.getScoringScheme().getType()); Assert.assertEquals(3, ((ThresholdBasedResultDiscardingRule) overallLeaderboard.getResultDiscardingRule()) .getDiscardIndexResultsStartingWithHowManyRaces()[2]); - + metaColumns = overallLeaderboard.getRaceColumns(); - + metaColumn = metaColumns.iterator().next(); Assert.assertNotNull(metaColumn); Assert.assertEquals(factor, metaColumn.getFactor()); diff --git a/java/com.sap.sailing.server.test/src/com/sap/sailing/server/test/RaceTrackerTest.java b/java/com.sap.sailing.server.test/src/com/sap/sailing/server/test/RaceTrackerTest.java index 2b6a666e2c9..7c63c50e959 100755 --- a/java/com.sap.sailing.server.test/src/com/sap/sailing/server/test/RaceTrackerTest.java +++ b/java/com.sap.sailing.server.test/src/com/sap/sailing/server/test/RaceTrackerTest.java @@ -72,7 +72,7 @@ public class RaceTrackerTest { tracTracAdapterFactory = new TracTracAdapterFactoryImpl(); raceHandle = tracTracAdapterFactory.getOrCreateTracTracAdapter(service.getBaseDomainFactory()) .addTracTracRace(service, paramUrl, liveUri, storedUri, courseDesignUpdateUri, EmptyRaceLogStore.INSTANCE, - /* timeoutInMilliseconds */60000, tracTracUsername, tracTracPassword); + /* timeoutInMilliseconds */60000, tracTracUsername, tracTracPassword, TracTracConnectionConstants.ONLINE_STATUS); logger.info("Calling raceHandle.getRaces()"); Set races = raceHandle.getRaces(); // wait for RaceDefinition to be completely wired in Regatta logger.info("Obtained races: "+races); @@ -130,7 +130,7 @@ public class RaceTrackerTest { service.removeRegatta(raceHandle.getRegatta()); RacesHandle myRaceHandle = tracTracAdapterFactory.getOrCreateTracTracAdapter(service.getBaseDomainFactory()) .addTracTracRace(service, paramUrl, liveUri, storedUri, courseDesignUpdateUri, EmptyRaceLogStore.INSTANCE, - /* timeoutInMilliseconds */60000, tracTracUsername, tracTracPassword); + /* timeoutInMilliseconds */60000, tracTracUsername, tracTracPassword, TracTracConnectionConstants.ONLINE_STATUS); TrackedRegatta newTrackedRegatta = myRaceHandle.getTrackedRegatta(); assertNotSame(oldTrackedRegatta, newTrackedRegatta); TrackedRace newTrackedRace = getTrackedRace(newTrackedRegatta); @@ -156,7 +156,7 @@ public class RaceTrackerTest { TrackedRace oldTrackedRace = getTrackedRace(oldTrackedRegatta); RacesHandle myRaceHandle = tracTracAdapterFactory.getOrCreateTracTracAdapter(service.getBaseDomainFactory()) .addTracTracRace(service, paramUrl, liveUri, storedUri, courseDesignUpdateUri, EmptyRaceLogStore.INSTANCE, - /* timeoutInMilliseconds */60000, tracTracUsername, tracTracPassword); + /* timeoutInMilliseconds */60000, tracTracUsername, tracTracPassword, TracTracConnectionConstants.ONLINE_STATUS); TrackedRegatta newTrackedEvent = myRaceHandle.getTrackedRegatta(); TrackedRace newTrackedRace = getTrackedRace(newTrackedEvent); // expecting a new tracked race to be created when starting over with tracking diff --git a/java/com.sap.sailing.server/META-INF/MANIFEST.MF b/java/com.sap.sailing.server/META-INF/MANIFEST.MF index 98e1cec5fe3..f3dd7173253 100755 --- a/java/com.sap.sailing.server/META-INF/MANIFEST.MF +++ b/java/com.sap.sailing.server/META-INF/MANIFEST.MF @@ -7,8 +7,6 @@ Bundle-Activator: com.sap.sailing.server.impl.Activator Bundle-Vendor: SAP Bundle-RequiredExecutionEnvironment: JavaSE-1.7 Import-Package: com.sap.sailing.server.gateway.deserialization, - com.sap.sailing.server.gateway.deserialization.masterdata.impl, - com.sap.sailing.server.gateway.serialization.masterdata.impl, org.json.simple, org.json.simple.parser, org.osgi.framework;version="1.3.0", diff --git a/java/com.sap.sailing.server/SailingServer (No Proxy, Remote Debug SAP VM).launch b/java/com.sap.sailing.server/SailingServer (No Proxy, Remote Debug SAP VM).launch index 6c9a2bda997..a423924c49b 100755 --- a/java/com.sap.sailing.server/SailingServer (No Proxy, Remote Debug SAP VM).launch +++ b/java/com.sap.sailing.server/SailingServer (No Proxy, Remote Debug SAP VM).launch @@ -25,5 +25,5 @@ - + diff --git a/java/com.sap.sailing.server/SailingServer (Proxy, Jetty on 8889).launch b/java/com.sap.sailing.server/SailingServer (Proxy, Jetty on 8889).launch index d60c09e3ea7..ac05fdf91a8 100755 --- a/java/com.sap.sailing.server/SailingServer (Proxy, Jetty on 8889).launch +++ b/java/com.sap.sailing.server/SailingServer (Proxy, Jetty on 8889).launch @@ -22,10 +22,10 @@ - + - + diff --git a/java/com.sap.sailing.server/src/com/sap/sailing/server/impl/RaceLogReplicator.java b/java/com.sap.sailing.server/src/com/sap/sailing/server/impl/RaceLogReplicator.java index 87729b18485..aa8433cc44f 100644 --- a/java/com.sap.sailing.server/src/com/sap/sailing/server/impl/RaceLogReplicator.java +++ b/java/com.sap.sailing.server/src/com/sap/sailing/server/impl/RaceLogReplicator.java @@ -76,6 +76,10 @@ public class RaceLogReplicator implements RaceColumnListener { public void isFirstColumnIsNonDiscardableCarryForwardChanged(RaceColumn raceColumn, boolean firstColumnIsNonDiscardableCarryForward) { } + @Override + public void hasSplitFleetContiguousScoringChanged(RaceColumn raceColumn, boolean hasSplitFleetContiguousScoring) { + } + @Override public boolean canAddRaceColumnToContainer(RaceColumn raceColumn) { return true; diff --git a/java/com.sap.sailing.server/src/com/sap/sailing/server/impl/RaceLogScoringReplicator.java b/java/com.sap.sailing.server/src/com/sap/sailing/server/impl/RaceLogScoringReplicator.java index 65ee7c2c25b..d1ea8b9a85c 100644 --- a/java/com.sap.sailing.server/src/com/sap/sailing/server/impl/RaceLogScoringReplicator.java +++ b/java/com.sap.sailing.server/src/com/sap/sailing/server/impl/RaceLogScoringReplicator.java @@ -55,6 +55,10 @@ public class RaceLogScoringReplicator implements RaceColumnListener { public void isStartsWithZeroScoreChanged(RaceColumn raceColumn, boolean newIsStartsWithZeroScore) { } + @Override + public void hasSplitFleetContiguousScoringChanged(RaceColumn raceColumn, boolean hasSplitFleetContiguousScoring) { + } + @Override public void isFirstColumnIsNonDiscardableCarryForwardChanged(RaceColumn raceColumn, boolean firstColumnIsNonDiscardableCarryForward) { } @@ -184,7 +188,7 @@ public class RaceLogScoringReplicator implements RaceColumnListener { public Integer call() { return numberOfCompetitorsInRace; } - }); + }, leaderboard.getNumberOfCompetitorsInLeaderboardFetcher()); // Do ALWAYS apply score corrections from race committee applyScoreCorrectionOperation(leaderboard, raceColumn, competitor, scoreByRaceCommittee, timePoint); diff --git a/java/com.sap.sailing.server/src/com/sap/sailing/server/impl/RacingEventServiceImpl.java b/java/com.sap.sailing.server/src/com/sap/sailing/server/impl/RacingEventServiceImpl.java index a7976e07f08..1834246ae4e 100755 --- a/java/com.sap.sailing.server/src/com/sap/sailing/server/impl/RacingEventServiceImpl.java +++ b/java/com.sap.sailing.server/src/com/sap/sailing/server/impl/RacingEventServiceImpl.java @@ -1006,7 +1006,7 @@ public class RacingEventServiceImpl implements RacingEventService, RegattaListen s.getName(), new SeriesCreationParametersDTO(fleetNamesAndOrdering, s.isMedal(), s.isStartsWithZeroScore(), s .isFirstColumnIsNonDiscardableCarryForward(), s.getResultDiscardingRule() == null ? null - : s.getResultDiscardingRule().getDiscardIndexResultsStartingWithHowManyRaces())); + : s.getResultDiscardingRule().getDiscardIndexResultsStartingWithHowManyRaces(), s.hasSplitFleetContiguousScoring())); } return new RegattaCreationParametersDTO(result); } diff --git a/java/com.sap.sailing.server/src/com/sap/sailing/server/operationaltransformation/DummyTrackedRace.java b/java/com.sap.sailing.server/src/com/sap/sailing/server/masterdata/DummyTrackedRace.java similarity index 99% rename from java/com.sap.sailing.server/src/com/sap/sailing/server/operationaltransformation/DummyTrackedRace.java rename to java/com.sap.sailing.server/src/com/sap/sailing/server/masterdata/DummyTrackedRace.java index e580862ca91..d6708367abf 100644 --- a/java/com.sap.sailing.server/src/com/sap/sailing/server/operationaltransformation/DummyTrackedRace.java +++ b/java/com.sap.sailing.server/src/com/sap/sailing/server/masterdata/DummyTrackedRace.java @@ -1,4 +1,4 @@ -package com.sap.sailing.server.operationaltransformation; +package com.sap.sailing.server.masterdata; import java.io.Serializable; import java.util.HashSet; diff --git a/java/com.sap.sailing.server/src/com/sap/sailing/server/masterdata/MasterDataImporter.java b/java/com.sap.sailing.server/src/com/sap/sailing/server/masterdata/MasterDataImporter.java index 847daabfd75..eb5f2d1d50a 100644 --- a/java/com.sap.sailing.server/src/com/sap/sailing/server/masterdata/MasterDataImporter.java +++ b/java/com.sap.sailing.server/src/com/sap/sailing/server/masterdata/MasterDataImporter.java @@ -1,26 +1,15 @@ package com.sap.sailing.server.masterdata; -import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; -import java.util.List; import java.util.Map; -import org.json.simple.JSONArray; -import org.json.simple.JSONObject; -import org.json.simple.parser.JSONParser; - import com.sap.sailing.domain.base.DomainFactory; import com.sap.sailing.domain.common.MasterDataImportObjectCreationCount; import com.sap.sailing.domain.common.impl.MasterDataImportObjectCreationCountImpl; import com.sap.sailing.domain.common.media.MediaTrack; -import com.sap.sailing.domain.masterdataimport.LeaderboardGroupMasterData; +import com.sap.sailing.domain.masterdataimport.TopLevelMasterData; import com.sap.sailing.server.RacingEventService; -import com.sap.sailing.server.gateway.deserialization.JsonDeserializationException; -import com.sap.sailing.server.gateway.deserialization.JsonDeserializer; -import com.sap.sailing.server.gateway.deserialization.masterdata.impl.LeaderboardGroupMasterDataJsonDeserializer; -import com.sap.sailing.server.gateway.deserialization.masterdata.impl.MediaTrackJsonDeserializer; -import com.sap.sailing.server.gateway.serialization.masterdata.impl.TopLevelMasterDataSerializer; import com.sap.sailing.server.operationaltransformation.ImportMasterDataOperation; public class MasterDataImporter { @@ -33,49 +22,35 @@ public class MasterDataImporter { this.racingEventService = racingEventService; } - public MasterDataImportObjectCreationCount importMasterData(String string, boolean override) { + public MasterDataImportObjectCreationCount importMasterData(TopLevelMasterData topLevelMasterData, boolean override) { MasterDataImportObjectCreationCountImpl creationCount = new MasterDataImportObjectCreationCountImpl(); - JsonDeserializer leaderboardGroupMasterDataDeserializer = LeaderboardGroupMasterDataJsonDeserializer.create(baseDomainFactory); - JSONParser parser = new JSONParser(); - try { - JSONObject masterDataOverall = (JSONObject) parser.parse(string); - JSONArray leaderboardGroupsMasterDataJsonArray = (JSONArray) masterDataOverall.get(TopLevelMasterDataSerializer.FIELD_PER_LG); - for (Object leaderBoardGroupMasterData : leaderboardGroupsMasterDataJsonArray) { - JSONObject leaderBoardGroupMasterDataJson = (JSONObject) leaderBoardGroupMasterData; - LeaderboardGroupMasterData masterData = leaderboardGroupMasterDataDeserializer - .deserialize(leaderBoardGroupMasterDataJson); - ImportMasterDataOperation op = new ImportMasterDataOperation(masterData, override, creationCount, baseDomainFactory); - creationCount = racingEventService.apply(op); - } - JsonDeserializer mediaTrackDeserializer = new MediaTrackJsonDeserializer(); - JSONArray mediaTracks = (JSONArray) masterDataOverall.get(TopLevelMasterDataSerializer.FIELD_MEDIA); - List tracks = new ArrayList(); - for (Object obj : mediaTracks) { - tracks.add(mediaTrackDeserializer.deserialize((JSONObject) obj)); - } - Collection existingMediaTracks = racingEventService.getAllMediaTracks(); - Map existingMap = new HashMap(); - - for (MediaTrack oneTrack : existingMediaTracks) { - existingMap.put(oneTrack.dbId, oneTrack); - } - - for (MediaTrack oneNewTrack : tracks) { - if (existingMap.containsKey(oneNewTrack.dbId)) { - if (override) { - racingEventService.mediaTrackDeleted(existingMap.get(oneNewTrack.dbId)); - } else { - continue; - } - } - racingEventService.mediaTrackAdded(oneNewTrack); - } - } catch (org.json.simple.parser.ParseException e) { - throw new RuntimeException(e); - } catch (JsonDeserializationException e) { - throw new RuntimeException(e); - } + ImportMasterDataOperation op = new ImportMasterDataOperation(topLevelMasterData, override, creationCount, + baseDomainFactory); + creationCount = racingEventService.apply(op); + createMediaTracks(topLevelMasterData, override); + return creationCount; } + private void createMediaTracks(TopLevelMasterData topLevelMasterData, boolean override) { + Collection tracks = topLevelMasterData.getAllMediaTracks(); + Collection existingMediaTracks = racingEventService.getAllMediaTracks(); + Map existingMap = new HashMap(); + + for (MediaTrack oneTrack : existingMediaTracks) { + existingMap.put(oneTrack.dbId, oneTrack); + } + + for (MediaTrack oneNewTrack : tracks) { + if (existingMap.containsKey(oneNewTrack.dbId)) { + if (override) { + racingEventService.mediaTrackDeleted(existingMap.get(oneNewTrack.dbId)); + } else { + continue; + } + } + racingEventService.mediaTrackAdded(oneNewTrack); + } + } + } diff --git a/java/com.sap.sailing.server/src/com/sap/sailing/server/operationaltransformation/AddSpecificRegatta.java b/java/com.sap.sailing.server/src/com/sap/sailing/server/operationaltransformation/AddSpecificRegatta.java index d1604f800cf..6180bc989c0 100755 --- a/java/com.sap.sailing.server/src/com/sap/sailing/server/operationaltransformation/AddSpecificRegatta.java +++ b/java/com.sap.sailing.server/src/com/sap/sailing/server/operationaltransformation/AddSpecificRegatta.java @@ -53,6 +53,7 @@ public class AddSpecificRegatta extends AbstractAddRegattaOperation { s.setResultDiscardingRule(new ThresholdBasedResultDiscardingRuleImpl(e.getValue().getDiscardingThresholds())); } s.setStartsWithZeroScore(e.getValue().isStartsWithZero()); + s.setSplitFleetContiguousScoring(e.getValue().hasSplitFleetContiguousScoring()); s.setFirstColumnIsNonDiscardableCarryForward(e.getValue().isFirstColumnIsNonDiscardableCarryForward()); result.add(s); } diff --git a/java/com.sap.sailing.server/src/com/sap/sailing/server/operationaltransformation/ImportMasterDataOperation.java b/java/com.sap.sailing.server/src/com/sap/sailing/server/operationaltransformation/ImportMasterDataOperation.java index e36cfbab8ee..46f996db9f6 100755 --- a/java/com.sap.sailing.server/src/com/sap/sailing/server/operationaltransformation/ImportMasterDataOperation.java +++ b/java/com.sap.sailing.server/src/com/sap/sailing/server/operationaltransformation/ImportMasterDataOperation.java @@ -3,10 +3,10 @@ package com.sap.sailing.server.operationaltransformation; import java.io.IOException; import java.io.Serializable; import java.util.ArrayList; +import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; -import java.util.Map.Entry; import java.util.Set; import java.util.UUID; import java.util.logging.Logger; @@ -16,36 +16,21 @@ import com.sap.sailing.domain.base.CourseArea; import com.sap.sailing.domain.base.DomainFactory; import com.sap.sailing.domain.base.Event; import com.sap.sailing.domain.base.Fleet; -import com.sap.sailing.domain.base.LeaderboardMasterData; import com.sap.sailing.domain.base.RaceColumn; -import com.sap.sailing.domain.base.RaceColumnInSeries; import com.sap.sailing.domain.base.RaceDefinition; import com.sap.sailing.domain.base.Regatta; import com.sap.sailing.domain.base.Series; -import com.sap.sailing.domain.base.impl.SeriesImpl; -import com.sap.sailing.domain.common.MaxPointsReason; -import com.sap.sailing.domain.common.RaceIdentifier; import com.sap.sailing.domain.common.RegattaAndRaceIdentifier; -import com.sap.sailing.domain.common.RegattaName; import com.sap.sailing.domain.common.ScoringSchemeType; import com.sap.sailing.domain.common.impl.MasterDataImportObjectCreationCountImpl; -import com.sap.sailing.domain.common.impl.MillisecondsTimePoint; import com.sap.sailing.domain.common.impl.Util.Pair; import com.sap.sailing.domain.leaderboard.FlexibleLeaderboard; import com.sap.sailing.domain.leaderboard.Leaderboard; import com.sap.sailing.domain.leaderboard.LeaderboardGroup; import com.sap.sailing.domain.leaderboard.RegattaLeaderboard; -import com.sap.sailing.domain.leaderboard.SettableScoreCorrection; -import com.sap.sailing.domain.leaderboard.impl.ThresholdBasedResultDiscardingRuleImpl; -import com.sap.sailing.domain.masterdataimport.EventMasterData; -import com.sap.sailing.domain.masterdataimport.FlexibleLeaderboardMasterData; -import com.sap.sailing.domain.masterdataimport.LeaderboardGroupMasterData; -import com.sap.sailing.domain.masterdataimport.RaceColumnMasterData; -import com.sap.sailing.domain.masterdataimport.RegattaLeaderboardMasterData; -import com.sap.sailing.domain.masterdataimport.RegattaMasterData; -import com.sap.sailing.domain.masterdataimport.ScoreCorrectionMasterData; -import com.sap.sailing.domain.masterdataimport.SeriesMasterData; -import com.sap.sailing.domain.masterdataimport.SingleScoreCorrectionMasterData; +import com.sap.sailing.domain.leaderboard.ThresholdBasedResultDiscardingRule; +import com.sap.sailing.domain.leaderboard.meta.LeaderboardGroupMetaLeaderboard; +import com.sap.sailing.domain.masterdataimport.TopLevelMasterData; import com.sap.sailing.domain.masterdataimport.WindTrackMasterData; import com.sap.sailing.domain.racelog.RaceLog; import com.sap.sailing.domain.racelog.RaceLogEvent; @@ -56,6 +41,7 @@ import com.sap.sailing.domain.tracking.Wind; import com.sap.sailing.domain.tracking.WindTrack; import com.sap.sailing.server.RacingEventService; import com.sap.sailing.server.RacingEventServiceOperation; +import com.sap.sailing.server.masterdata.DummyTrackedRace; public class ImportMasterDataOperation extends AbstractRacingEventServiceOperation { @@ -64,7 +50,7 @@ public class ImportMasterDataOperation extends private static final Logger logger = Logger.getLogger(ImportMasterDataOperation.class.getName()); - private final LeaderboardGroupMasterData masterData; + private final TopLevelMasterData masterData; private final MasterDataImportObjectCreationCountImpl creationCount; @@ -72,34 +58,39 @@ public class ImportMasterDataOperation extends private final boolean override; - public ImportMasterDataOperation(LeaderboardGroupMasterData masterData, boolean override, MasterDataImportObjectCreationCountImpl existingCreationCount, DomainFactory baseDomainFactory) { + public ImportMasterDataOperation(TopLevelMasterData topLevelMasterData, boolean override, + MasterDataImportObjectCreationCountImpl existingCreationCount, DomainFactory baseDomainFactory) { this.creationCount = new MasterDataImportObjectCreationCountImpl(); this.creationCount.add(existingCreationCount); this.baseDomainFactory = baseDomainFactory; - this.masterData = masterData; + this.masterData = topLevelMasterData; this.override = override; } @Override public MasterDataImportObjectCreationCountImpl internalApplyTo(RacingEventService toState) throws Exception { - createLeaderboardGroupWithAllRelatedObjects(masterData, toState); + for (LeaderboardGroup leaderboardGroup : masterData.getLeaderboardGroups()) { + createLeaderboardGroupWithAllRelatedObjects(toState, leaderboardGroup); + } + createWindTracks(toState); return creationCount; } - private void createLeaderboardGroupWithAllRelatedObjects(final LeaderboardGroupMasterData masterData, - final RacingEventService toState) { + private void createLeaderboardGroupWithAllRelatedObjects(final RacingEventService toState, + LeaderboardGroup leaderboardGroup) { + Map>> raceLogEvents = extractRaceLogEvents(leaderboardGroup); Map existingLeaderboards = toState.getLeaderboards(); List leaderboardNames = new ArrayList(); - createCourseAreasAndEvents(masterData, toState); - createRegattas(masterData, toState); - for (final LeaderboardMasterData board : masterData.getLeaderboards()) { - leaderboardNames.add(board.getName()); - if (existingLeaderboards.containsKey(board.getName())) { - if (creationCount.alreadyAddedLeaderboardWithName(board.getName())) { + createCourseAreasAndEvents(toState, leaderboardGroup); + createRegattas(toState, leaderboardGroup); + for (final Leaderboard leaderboard : leaderboardGroup.getLeaderboards()) { + leaderboardNames.add(leaderboard.getName()); + if (existingLeaderboards.containsKey(leaderboard.getName())) { + if (creationCount.alreadyAddedLeaderboardWithName(leaderboard.getName())) { //Has already been added by this operation continue; } else if (override) { - for (RaceColumn raceColumn : existingLeaderboards.get(board.getName()).getRaceColumns()) { + for (RaceColumn raceColumn : existingLeaderboards.get(leaderboard.getName()).getRaceColumns()) { for (Fleet fleet : raceColumn.getFleets()) { TrackedRace trackedRace = raceColumn.getTrackedRace(fleet); if (trackedRace != null) { @@ -107,91 +98,107 @@ public class ImportMasterDataOperation extends } } } - if (toState.getLeaderboardByName(board.getName()) != null) { - toState.removeLeaderboard(board.getName()); + if (toState.getLeaderboardByName(leaderboard.getName()) != null) { + toState.removeLeaderboard(leaderboard.getName()); } logger.info(String.format("Leaderboard with name %1$s already existed and has been overridden.", - board.getName())); + leaderboard.getName())); } else { logger.info(String.format("Leaderboard with name %1$s already exists and hasn't been overridden.", - board.getName())); + leaderboard.getName())); continue; } } - setCourseAreaIfNecessary(board, toState); - setRegattaIfNecessary(board, toState); - Leaderboard leaderboard = board.getLeaderboard(); if (leaderboard != null) { - leaderboard.setDisplayName(board.getDisplayName()); toState.addLeaderboard(leaderboard); + addRaceLogEvents(leaderboard, raceLogEvents); creationCount.addOneLeaderboard(leaderboard.getName()); - Leaderboard newLeaderboard = toState.getLeaderboardByName(board.getName()); - addRaceColumnsIfNecessary(board, newLeaderboard, toState); - // Set dummy tracked race, so that the leaderboard caches the competitors and - // will accept the score corrections - Pair dummyColumnAndFleet = addDummyTrackedRace(board.getCompetitorsById().values(), - leaderboard, getRegattaIfPossible(leaderboard)); - boolean addedScoreCorrections = false; - try { - if (dummyColumnAndFleet.getA() != null && dummyColumnAndFleet.getB() != null) { - addScoreCorrectionsIfPossible(board.getScoreCorrection(), newLeaderboard); - addedScoreCorrections = true; - } - addCarriedPoints(leaderboard, board.getCarriedPoints(), baseDomainFactory); - addSuppressedCompetitors(leaderboard, board.getSuppressedCompetitors(), baseDomainFactory); - addCompetitorDisplayNames(leaderboard, board.getDisplayNamesByCompetitorId(), - board.getCompetitorsById()); - addRaceLogEvents(leaderboard, board.getRaceLogEvents()); - toState.updateStoredLeaderboard(leaderboard); - - } finally { - if (addedScoreCorrections) { - unsetDummy(dummyColumnAndFleet, leaderboard); - } - } - relinkTrackedRacesIfPossible(toState, newLeaderboard); + relinkTrackedRacesIfPossible(toState, leaderboard); } } - int[] overallLeaderboardDiscardThresholds = masterData.getOverallLeaderboardDiscardingRule() != null ? masterData.getOverallLeaderboardDiscardingRule().getDiscardIndexResultsStartingWithHowManyRaces() : null; - ScoringSchemeType overallLeaderboardScoringSchemeType = masterData.getOverallLeaderboardScoringScheme() != null ? masterData.getOverallLeaderboardScoringScheme().getType() : null; - final LeaderboardGroup leaderboardGroup; - LeaderboardGroup existingLeaderboardGroup = toState.getLeaderboardGroupByName(masterData.getName()); + LeaderboardGroup existingLeaderboardGroup = toState.getLeaderboardGroupByName(leaderboardGroup.getName()); if (existingLeaderboardGroup != null && override) { logger.info(String.format("Leaderboard Group with name %1$s already existed and will be overridden.", - masterData.getName())); - toState.removeLeaderboardGroup(masterData.getName()); + leaderboardGroup.getName())); + toState.removeLeaderboardGroup(leaderboardGroup.getName()); existingLeaderboardGroup = null; } + Leaderboard overallLeaderboardData = null; if (existingLeaderboardGroup == null) { - leaderboardGroup = toState.addLeaderboardGroup(masterData.getName(), masterData.getDescription(), - masterData.isDisplayGroupsRevese(), leaderboardNames, overallLeaderboardDiscardThresholds, + overallLeaderboardData = leaderboardGroup.getOverallLeaderboard(); + int[] overallLeaderboardDiscardThresholds = null; + ScoringSchemeType overallLeaderboardScoringSchemeType = null; + if (overallLeaderboardData != null) { + LeaderboardGroupMetaLeaderboard metaLeaderboard = (LeaderboardGroupMetaLeaderboard) overallLeaderboardData; + ThresholdBasedResultDiscardingRule rule = (ThresholdBasedResultDiscardingRule) metaLeaderboard + .getResultDiscardingRule(); + overallLeaderboardDiscardThresholds = rule.getDiscardIndexResultsStartingWithHowManyRaces(); + overallLeaderboardScoringSchemeType = metaLeaderboard.getScoringScheme().getType(); + } + leaderboardGroup = toState.addLeaderboardGroup(leaderboardGroup.getName(), + leaderboardGroup.getDescription(), leaderboardGroup.isDisplayGroupsInReverseOrder(), + leaderboardNames, overallLeaderboardDiscardThresholds, overallLeaderboardScoringSchemeType); - creationCount.addOneLeaderboardGroup(masterData.getName()); + creationCount.addOneLeaderboardGroup(leaderboardGroup.getName()); } else { leaderboardGroup = existingLeaderboardGroup; logger.info(String.format("Leaderboard Group with name %1$s already exists and hasn't been overridden.", - masterData.getName())); + leaderboardGroup.getName())); } - if (masterData.hasOverallLeaderboard() && (override || existingLeaderboardGroup == null)) { + if (leaderboardGroup.getOverallLeaderboard() != null && (override || existingLeaderboardGroup == null)) { if (existingLeaderboardGroup != null && existingLeaderboardGroup.getOverallLeaderboard() != null) { // remove old overall leaderboard if it existed toState.removeLeaderboard(existingLeaderboardGroup.getOverallLeaderboard().getName()); } Leaderboard overallLeaderboard = leaderboardGroup.getOverallLeaderboard(); - addSuppressedCompetitors(overallLeaderboard, masterData.getOverallLeaderboardSuppressedCompetitorIds(), - baseDomainFactory); - Map factorsForMetaColumns = masterData.getMetaColumnsWithFactors(); - if (factorsForMetaColumns != null) { - for (RaceColumn column : overallLeaderboard.getRaceColumns()) { - Double explicitFactor = factorsForMetaColumns.get(column.getName()); - toState.updateLeaderboardColumnFactor(overallLeaderboard.getName(), column.getName(), explicitFactor); - } + for (Competitor suppressedCompetitor : overallLeaderboardData.getSuppressedCompetitors()) { + overallLeaderboard.setSuppressed(suppressedCompetitor, true); + } + for (RaceColumn column : overallLeaderboard.getRaceColumns()) { + Double explicitFactor = overallLeaderboardData.getRaceColumnByName(column.getName()) + .getExplicitFactor(); + toState.updateLeaderboardColumnFactor(overallLeaderboard.getName(), column.getName(), explicitFactor); } toState.getMongoObjectFactory().storeLeaderboardGroup(leaderboardGroup); // store changes to overall leaderboard } } + private void addRaceLogEvents(Leaderboard leaderboard, + Map>> raceLogEvents) { + for (RaceColumn raceColumn : leaderboard.getRaceColumns()) { + for (Fleet fleet : raceColumn.getFleets()) { + RaceLog log = raceColumn.getRaceLog(fleet); + Iterable raceLogsForColumnAndFleet = raceLogEvents.get(raceColumn).get(fleet); + for (RaceLogEvent event : raceLogsForColumnAndFleet) { + log.add(event); + } + } + } + + } + + private Map>> extractRaceLogEvents(LeaderboardGroup group) { + Map>> raceLogEvents = new HashMap>>(); + for (Leaderboard leaderboard : group.getLeaderboards()) { + for (RaceColumn raceColumn : leaderboard.getRaceColumns()) { + HashMap> raceLogEventsForRaceColumn = new HashMap>(); + raceLogEvents.put(raceColumn, raceLogEventsForRaceColumn); + for (Fleet fleet : raceColumn.getFleets()) { + RaceLog raceLog = raceColumn.getRaceLog(fleet); + raceLog.lockForRead(); + try { + Iterable fixes = raceLog.getRawFixes(); + raceLogEventsForRaceColumn.put(fleet, fixes); + } finally { + raceLog.unlockAfterRead(); + } + } + } + } + return raceLogEvents; + } + private void relinkTrackedRacesIfPossible(RacingEventService toState, Leaderboard newLeaderboard) { if (newLeaderboard instanceof FlexibleLeaderboard) { for (RaceColumn raceColumn : newLeaderboard.getRaceColumns()) { @@ -204,72 +211,13 @@ public class ImportMasterDataOperation extends } } - private void addRaceLogEvents(Leaderboard leaderboard, Map>> raceLogEvents) { - for (Entry>> entry : raceLogEvents.entrySet()) { - String raceColumnName = entry.getKey(); - RaceColumn raceColumn = leaderboard.getRaceColumnByName(raceColumnName); - for (Entry> fleetEntry : entry.getValue().entrySet()) { - String fleetName = fleetEntry.getKey(); - Fleet fleet = raceColumn.getFleetByName(fleetName); - List logEvents = fleetEntry.getValue(); - RaceLog raceLog = raceColumn.getRaceLog(fleet); - for (RaceLogEvent singleEvent : logEvents) { - raceLog.load(singleEvent); - } - } - } - } - - private void addCompetitorDisplayNames(Leaderboard leaderboard, Map map, - Map map2) { - for (Entry entry : map.entrySet()) { - leaderboard.setDisplayName(baseDomainFactory.getExistingCompetitorById(entry.getKey()), - entry.getValue()); - } - } - - interface CompetitorByIdGetter { - Competitor getCompetitorById(Serializable id); - } - - public static void addSuppressedCompetitors(Leaderboard leaderboard, List list, - DomainFactory domainFactory) { - for (Serializable id : list) { - Competitor competitorById = domainFactory.getExistingCompetitorById(id); - if (competitorById != null) { - leaderboard.setSuppressed(competitorById, true); - } - } - } - - private void addCarriedPoints(Leaderboard leaderboard, Map carriedPoints, - DomainFactory domainFactory) { - for (Entry entry : carriedPoints.entrySet()) { - leaderboard.setCarriedPoints(domainFactory.getExistingCompetitorById(entry.getKey()), entry.getValue()); - } - } - - private Regatta getRegattaIfPossible(Leaderboard leaderboard) { - if (leaderboard instanceof RegattaLeaderboard) { - return ((RegattaLeaderboard) leaderboard).getRegatta(); - } - return null; - } - - private void unsetDummy(Pair dummyColumnAndFleet, Leaderboard leaderboard) { - RaceColumn raceColumn = dummyColumnAndFleet.getA(); - Fleet fleet = dummyColumnAndFleet.getB(); - raceColumn.setTrackedRace(fleet, null); - } - /** * Hack adding a dummy tracked race, so that the competitors will be added to the leaderboards * - * @param competitors * @param leaderboard * @return the race column and fleet the dummy was attached to */ - public Pair addDummyTrackedRace(Iterable competitors, Leaderboard leaderboard, + public Pair addDummyTrackedRace(Leaderboard leaderboard, Regatta regatta) { RaceColumn raceColumn = null; Fleet fleet = null; @@ -281,61 +229,15 @@ public class ImportMasterDataOperation extends Iterator fleetIterator = fleets.iterator(); if (fleetIterator.hasNext()) { fleet = fleetIterator.next(); - DummyTrackedRace dummy = new DummyTrackedRace(competitors, regatta, null); + DummyTrackedRace dummy = new DummyTrackedRace(leaderboard.getAllCompetitors(), regatta, null); raceColumn.setTrackedRace(fleet, dummy); } } return new Pair(raceColumn, fleet); } - private void addScoreCorrectionsIfPossible(ScoreCorrectionMasterData scoreCorrectionMasterData, - final Leaderboard leaderboard) { - SettableScoreCorrection scoreCorrection = leaderboard.getScoreCorrection(); - scoreCorrection.setComment(scoreCorrectionMasterData.getComment()); - if (scoreCorrectionMasterData.getTimepointMillis() != null) { - scoreCorrection.setTimePointOfLastCorrectionsValidity(new MillisecondsTimePoint(scoreCorrectionMasterData - .getTimepointMillis())); - } - for (Entry> scoreCorrectionEntry : scoreCorrectionMasterData - .getCorrectionForRaceColumns().entrySet()) { - String columnName = scoreCorrectionEntry.getKey(); - RaceColumn raceColumn = leaderboard.getRaceColumnByName(columnName); - if (raceColumn != null) { - for (SingleScoreCorrectionMasterData singleCorrection : scoreCorrectionEntry.getValue()) { - Competitor competitor = leaderboard.getCompetitorByIdAsString(singleCorrection.getCompetitorId() - .toString()); - scoreCorrection.setMaxPointsReason(competitor, raceColumn, - MaxPointsReason.valueOf(singleCorrection.getMaxPointsReason())); - if (singleCorrection.getExplicitScoreCorrection() != null) { - scoreCorrection.correctScore(competitor, raceColumn, - singleCorrection.getExplicitScoreCorrection()); - } - } - } - } - - } - - private void addRaceColumnsIfNecessary(LeaderboardMasterData board, Leaderboard newLeaderboard, - RacingEventService toState) { - if (board instanceof FlexibleLeaderboardMasterData) { - for (RaceColumnMasterData raceColumnMasterData : ((FlexibleLeaderboardMasterData) board).getRaceColumns()) { - RaceColumn raceColumn = toState.addColumnToLeaderboard(raceColumnMasterData.getName(), board.getName(), - raceColumnMasterData.isMedal()); - Set windTrackMasterData = raceColumnMasterData.getWindTrackMasterData(); - if (windTrackMasterData != null) { - createWindTracks(windTrackMasterData, toState); - } - for (Map.Entry e : raceColumnMasterData.getRaceIdentifiersByFleetName() - .entrySet()) { - raceColumn.setRaceIdentifier(raceColumn.getFleetByName(e.getKey()), e.getValue()); - } - } - } - } - - private void createWindTracks(Set windTrackMasterData, RacingEventService toState) { - for (WindTrackMasterData windMasterData : windTrackMasterData) { + private void createWindTracks(RacingEventService toState) { + for (WindTrackMasterData windMasterData : masterData.getWindTrackMasterData()) { DummyTrackedRace trackedRaceWithNameAndId = new DummyTrackedRace(windMasterData.getRaceName(), windMasterData.getRaceId()); WindTrack windTrack = toState.getWindStore().getWindTrack(windMasterData.getRegattaName(), trackedRaceWithNameAndId, windMasterData.getWindSource(), 0, -1); for (Wind fix : windMasterData.getFixes()) { @@ -344,115 +246,86 @@ public class ImportMasterDataOperation extends } } - private void createRegattas(LeaderboardGroupMasterData masterData, RacingEventService toState) { - Iterable regattaData = masterData.getRegattas(); - for (RegattaMasterData singleRegattaData : regattaData) { - Regatta existingRegatta = toState.getRegatta(new RegattaName(singleRegattaData.getRegattaName())); - if (existingRegatta != null) { - if (creationCount.alreadyAddedRegattaWithId(existingRegatta.getId().toString())) { - // Already added earlier in this import process - continue; - } else if (override) { - logger.info(String - .format("Regatta with name %1$s already existed and has been overridden. All it's tracked races were stopped and removed.", - singleRegattaData.getRegattaName())); - try { - TrackedRegatta trackedRegatta = toState.getTrackedRegatta(existingRegatta); - List toRemove = new ArrayList(); - if (trackedRegatta != null) { - for (TrackedRace race : trackedRegatta.getTrackedRaces()) { - toRemove.add(race); - } - for (TrackedRace raceToRemove : toRemove) { - trackedRegatta.removeTrackedRace(raceToRemove); - RaceDefinition race = existingRegatta.getRaceByName(raceToRemove.getRaceIdentifier() - .getRaceName()); - if (race != null) { - try { - toState.removeRace(existingRegatta, race); - } catch (IOException | InterruptedException e) { - throw new RuntimeException(e); + private void createRegattas(RacingEventService toState, LeaderboardGroup leaderboardGroup) { + Iterable leaderboards = leaderboardGroup.getLeaderboards(); + for (Leaderboard leaderboard : leaderboards) { + if (leaderboard instanceof RegattaLeaderboard) { + RegattaLeaderboard regattaLeaderboard = (RegattaLeaderboard) leaderboard; + Regatta regatta = regattaLeaderboard.getRegatta(); + + Regatta existingRegatta = toState.getRegatta(regatta.getRegattaIdentifier()); + if (existingRegatta != null) { + if (creationCount.alreadyAddedRegattaWithId(existingRegatta.getId().toString())) { + // Already added earlier in this import process + continue; + } else if (override) { + logger.info(String + .format("Regatta with name %1$s already existed and has been overridden. All it's tracked races were stopped and removed.", + regatta.getRegattaIdentifier())); + try { + TrackedRegatta trackedRegatta = toState.getTrackedRegatta(existingRegatta); + List toRemove = new ArrayList(); + if (trackedRegatta != null) { + for (TrackedRace race : trackedRegatta.getTrackedRaces()) { + toRemove.add(race); + } + for (TrackedRace raceToRemove : toRemove) { + trackedRegatta.removeTrackedRace(raceToRemove); + RaceDefinition race = existingRegatta.getRaceByName(raceToRemove + .getRaceIdentifier().getRaceName()); + if (race != null) { + try { + toState.removeRace(existingRegatta, race); + } catch (IOException | InterruptedException e) { + throw new RuntimeException(e); + } } } } + toState.stopTrackingAndRemove(existingRegatta); + creationCount.addOverwrittenRegattaName(existingRegatta.getName()); + toState.removeRegatta(existingRegatta); + } catch (IOException | InterruptedException e) { + logger.warning(String.format( + "Regatta with name %1$s could not be deleted due to an error.", + regatta.getRegattaIdentifier())); + e.printStackTrace(); + continue; } - toState.stopTrackingAndRemove(existingRegatta); - creationCount.addOverwrittenRegattaName(existingRegatta.getName()); - toState.removeRegatta(existingRegatta); - } catch (IOException | InterruptedException e) { - logger.warning(String.format("Regatta with name %1$s could not be deleted due to an error.", - singleRegattaData.getRegattaName())); - e.printStackTrace(); + } else { + logger.info(String.format("Regatta with name %1$s already exists and hasn't been overridden.", + regatta.getRegattaIdentifier())); continue; } - } else { - logger.info(String.format("Regatta with name %1$s already exists and hasn't been overridden.", - singleRegattaData.getRegattaName())); - continue; } + Serializable id = regatta.getId(); + Iterable series = regatta.getSeries(); + String baseName = regatta.getBaseName(); + String boatClassName = regatta.getBoatClass().getName(); + CourseArea defaultCourseArea = regatta.getDefaultCourseArea(); + Serializable defaultCourseAreaId = (defaultCourseArea != null) ? defaultCourseArea.getId() : null; + ScoringSchemeType scoringSchemeType = regatta.getScoringScheme().getType(); + boolean isPersistent = regatta.isPersistent(); + Regatta createdRegatta = toState.getOrCreateRegattaWithoutReplication(baseName, boatClassName, id, + series, isPersistent, baseDomainFactory.createScoringScheme(scoringSchemeType), + defaultCourseAreaId).getA(); + createdRegatta.setRegattaConfiguration(regatta.getRegattaConfiguration()); + Set raceIdStrings = masterData.getRaceIdStringsForRegatta().get(regatta); + if (raceIdStrings != null) { + toState.setPersistentRegattaForRaceIDs(createdRegatta, raceIdStrings, override); + } + creationCount.addOneRegatta(createdRegatta.getId().toString()); } - Serializable id = singleRegattaData.getId(); - Iterable series = createSeries(singleRegattaData.getSeries(), toState); - String baseName = singleRegattaData.getBaseName(); - String boatClassName = singleRegattaData.getBoatClassName(); - String defaultCourseAreaId = singleRegattaData.getDefaultCourseAreaId(); - String scoringSchemeType = singleRegattaData.getScoringSchemeType(); - boolean isPersistent = singleRegattaData.isPersistent(); - UUID courseAreaUUID = defaultCourseAreaId != null ? UUID.fromString(defaultCourseAreaId) : null; - Regatta createdRegatta = toState.getOrCreateRegattaWithoutReplication(baseName, boatClassName, id, series, - isPersistent, baseDomainFactory.createScoringScheme(ScoringSchemeType.valueOf(scoringSchemeType)), - courseAreaUUID).getA(); - createdRegatta.setRegattaConfiguration(singleRegattaData.getRegattaConfiguration()); - toState.setPersistentRegattaForRaceIDs(createdRegatta, singleRegattaData.getRaceIdsAsStrings(), override); - creationCount.addOneRegatta(createdRegatta.getId().toString()); } } - private Iterable createSeries(Iterable series, RacingEventService toState) { - List result = new ArrayList(); - for (SeriesMasterData singleSeriesData : series) { - String name = singleSeriesData.getName(); - boolean isMedal = singleSeriesData.isMedal(); - Iterable fleets = singleSeriesData.getFleets(); - Iterable raceColumnMasterData = singleSeriesData.getRaceColumnNames(); - List raceColumnNames = new ArrayList(); - for (RaceColumnMasterData rcmd : raceColumnMasterData) { - raceColumnNames.add(rcmd.getName()); - } - SeriesImpl newSeries = new SeriesImpl(name, isMedal, fleets, raceColumnNames, toState); - Iterator raceColumnMasterDataIter = raceColumnMasterData.iterator(); - Iterator raceColumnIter = newSeries.getRaceColumns().iterator(); - while (raceColumnMasterDataIter.hasNext()) { - RaceColumnMasterData rcmd = raceColumnMasterDataIter.next(); - RaceColumnInSeries raceColumn = raceColumnIter.next(); - if (rcmd.getFactor() != null) { - raceColumn.setFactor(rcmd.getFactor()); - } - Set windTrackMasterData = rcmd.getWindTrackMasterData(); - if (windTrackMasterData != null) { - createWindTracks(windTrackMasterData, toState); - } - for (Map.Entry e : rcmd.getRaceIdentifiersByFleetName().entrySet()) { - raceColumn.setRaceIdentifier(raceColumn.getFleetByName(e.getKey()), e.getValue()); - } - } - int[] resultDiscardingRule = singleSeriesData.getDiscardingRule(); - if (resultDiscardingRule != null) { - newSeries.setResultDiscardingRule(new ThresholdBasedResultDiscardingRuleImpl(resultDiscardingRule)); - } - result.add(newSeries); - } - return result; - } - private void createCourseAreasAndEvents(LeaderboardGroupMasterData masterData, RacingEventService toState) { - Set events = masterData.getEvents(); - - for (EventMasterData event : events) { - String id = event.getId(); - Event existingEvent = toState.getEvent(UUID.fromString(id)); - if (existingEvent != null && override && !creationCount.alreadyAddedEventWithId(id)) { + private void createCourseAreasAndEvents(RacingEventService toState, LeaderboardGroup leaderboardGroup) { + for (Event event : masterData.getEventForLeaderboardGroup().get(leaderboardGroup)) { + UUID id = event.getId(); + Event existingEvent = toState.getEvent(id); + if (existingEvent != null && override && !creationCount.alreadyAddedEventWithId(id.toString())) { logger.info(String.format("Event with name %1$s already existed and will be overridden.", event.getName())); toState.removeEvent(existingEvent.getId()); @@ -460,29 +333,29 @@ public class ImportMasterDataOperation extends } if (existingEvent == null) { String name = event.getName(); - String pubString = event.getPubUrl(); - String venueName = event.getVenueName(); + String pubString = event.getPublicationUrl(); + String venueName = event.getVenue().getName(); boolean isPublic = event.isPublic(); - Event newEvent = toState.createEventWithoutReplication(name, venueName, pubString, isPublic, UUID.fromString(id)); + Event newEvent = toState.createEventWithoutReplication(name, venueName, pubString, isPublic, id); creationCount.addOneEvent(newEvent.getId().toString()); } else { logger.info(String.format("Event with name %1$s already exists and hasn't been overridden.", event.getName())); } - Iterable> courseAreas = event.getCourseAreas(); - for (Pair courseAreaEntry : courseAreas) { + Iterable courseAreas = event.getVenue().getCourseAreas(); + for (CourseArea courseArea : courseAreas) { boolean alreadyExists = false; - if (existingEvent != null - && existsInSet(existingEvent.getVenue().getCourseAreas(), courseAreaEntry.getA())) { + if (existingEvent != null && existsInSet(existingEvent.getVenue().getCourseAreas(), courseArea.getId())) { alreadyExists = true; } if (!alreadyExists) { - toState.addCourseAreaWithoutReplication(UUID.fromString(id), UUID.fromString(courseAreaEntry.getA()), courseAreaEntry.getB()); + toState.addCourseAreaWithoutReplication(id, courseArea.getId(), courseArea.getName()); } else { logger.info(String .format("Course area with id %1$s for event with id %2$s already exists and hasn't been overridden.", - courseAreaEntry.getA(), id)); + courseArea.getId(), id)); } + } } } @@ -490,37 +363,18 @@ public class ImportMasterDataOperation extends /** * * @param iterable - * @param key + * @param uuid * @return true if course with given id exists in iterable */ - private boolean existsInSet(Iterable iterable, String key) { + private boolean existsInSet(Iterable iterable, UUID uuid) { for (CourseArea area : iterable) { - if (area.getId().toString().matches(key)) { + if (area.getId() == uuid) { return true; } } return false; } - private void setRegattaIfNecessary(LeaderboardMasterData board, RacingEventService toState) { - if (board instanceof RegattaLeaderboardMasterData) { - RegattaLeaderboardMasterData regattaBoard = (RegattaLeaderboardMasterData) board; - Regatta regatta = toState.getRegatta(regattaBoard.getRegattaName()); - regattaBoard.setRegatta(regatta); - } - } - - private void setCourseAreaIfNecessary(LeaderboardMasterData board, RacingEventService toState) { - if (board instanceof FlexibleLeaderboardMasterData) { - FlexibleLeaderboardMasterData flexBoard = (FlexibleLeaderboardMasterData) board; - if (flexBoard.getCourseAreaId() == null) { - return; - } - CourseArea courseArea = toState.getCourseArea(UUID.fromString(flexBoard.getCourseAreaId())); - flexBoard.setCourseArea(courseArea); - } - } - @Override public RacingEventServiceOperation transformClientOp(RacingEventServiceOperation serverOp) { // TODO Auto-generated method stub diff --git a/java/com.sap.sailing.server/src/com/sap/sailing/server/operationaltransformation/UpdateSeries.java b/java/com.sap.sailing.server/src/com/sap/sailing/server/operationaltransformation/UpdateSeries.java index 88cc524008d..6a5e20add7b 100755 --- a/java/com.sap.sailing.server/src/com/sap/sailing/server/operationaltransformation/UpdateSeries.java +++ b/java/com.sap.sailing.server/src/com/sap/sailing/server/operationaltransformation/UpdateSeries.java @@ -13,13 +13,17 @@ public class UpdateSeries extends AbstractSeriesOperation { private final int[] resultDiscardingThresholds; private final boolean startsWithZeroScore; private final boolean firstColumnIsNonDiscardableCarryForward; + private final boolean hasSplitFleetContiguousScoring; - public UpdateSeries(RegattaIdentifier regattaIdentifier, String seriesName, boolean isMedal, int[] resultDiscardingThresholds, boolean startsWithZeroScore, boolean firstColumnIsNonDiscardableCarryForward) { + public UpdateSeries(RegattaIdentifier regattaIdentifier, String seriesName, boolean isMedal, + int[] resultDiscardingThresholds, boolean startsWithZeroScore, + boolean firstColumnIsNonDiscardableCarryForward, boolean hasSplitFleetContiguousScoring) { super(regattaIdentifier, seriesName); this.isMedal = isMedal; this.resultDiscardingThresholds = resultDiscardingThresholds; this.startsWithZeroScore = startsWithZeroScore; this.firstColumnIsNonDiscardableCarryForward = firstColumnIsNonDiscardableCarryForward; + this.hasSplitFleetContiguousScoring = hasSplitFleetContiguousScoring; } @Override @@ -30,6 +34,7 @@ public class UpdateSeries extends AbstractSeriesOperation { null : new ThresholdBasedResultDiscardingRuleImpl(resultDiscardingThresholds)); series.setStartsWithZeroScore(startsWithZeroScore); series.setFirstColumnIsNonDiscardableCarryForward(firstColumnIsNonDiscardableCarryForward); + series.setSplitFleetContiguousScoring(hasSplitFleetContiguousScoring); if (series.getRegatta().isPersistent()) { toState.updateStoredRegatta(series.getRegatta()); } diff --git a/java/com.sap.sailing.simulator/src/com/sap/sailing/simulator/impl/SimulatorUtils.java b/java/com.sap.sailing.simulator/src/com/sap/sailing/simulator/impl/SimulatorUtils.java index 0a2f1ab47e5..cb1bb66bde1 100644 --- a/java/com.sap.sailing.simulator/src/com/sap/sailing/simulator/impl/SimulatorUtils.java +++ b/java/com.sap.sailing.simulator/src/com/sap/sailing/simulator/impl/SimulatorUtils.java @@ -26,6 +26,7 @@ import com.sap.sailing.domain.common.impl.Util.Pair; import com.sap.sailing.domain.racelog.RaceLogStore; import com.sap.sailing.domain.tracking.RacesHandle; import com.sap.sailing.domain.tractracadapter.TracTracAdapterFactory; +import com.sap.sailing.domain.tractracadapter.TracTracConnectionConstants; import com.sap.sailing.server.impl.RacingEventServiceImpl; import com.sap.sailing.simulator.Path; import com.sap.sailing.simulator.SimulationParameters; @@ -81,7 +82,7 @@ public class SimulatorUtils { String tractracPassword = ""; RacesHandle raceHandle = tracTracAdapterFactory.getOrCreateTracTracAdapter(service.getBaseDomainFactory()) .addTracTracRace(service, paramURL, liveURI, storedURI, null, raceLogStore, - timeoutInMilliseconds, tractracUsername, tractracPassword); + timeoutInMilliseconds, tractracUsername, tractracPassword, TracTracConnectionConstants.ONLINE_STATUS); return raceHandle; } diff --git a/java/com.sap.sailing.www/index.html b/java/com.sap.sailing.www/index.html index a5552df3b8f..5f5326bbced 100644 --- a/java/com.sap.sailing.www/index.html +++ b/java/com.sap.sailing.www/index.html @@ -24,7 +24,7 @@
Sailer
- Release History + New Features

SAP Sailing Analytics

Understanding what happens out on the race course isn't always easy. To help solve this challenge and bring the excitement of sailing to the fans, we have developed the SAP sailing analytics.

diff --git a/java/com.sap.sailing.www/main.css b/java/com.sap.sailing.www/main.css index b170668e834..7b8f32e0f7a 100644 --- a/java/com.sap.sailing.www/main.css +++ b/java/com.sap.sailing.www/main.css @@ -105,7 +105,7 @@ a { /* line 47, site.css.sass */ #yield_content #pageHeadline { color: white; - margin: 0 0 10px 0; + margin: 10px 0 10px 0; font-size: 18px; } /* line 53, site.css.sass */ #yield_content #keyVisual { @@ -115,7 +115,7 @@ a { /* line 58, site.css.sass */ #yield_content #keyVisual #infoBox { width: 502px; - height: 80px; + height: 100px; background: #999999; position: absolute; right: 0; @@ -126,9 +126,13 @@ a { color: white; font-size: 12px; } #yield_content #keyVisual #infoBox a { - font-size: 12px; text-decoration: none; - float: right; } + float: right; + background: #fcb913; + color: white; + font-size: 18px; + font-family: OpenSansRegular, Arial, Verdana, sans-serif; + padding: 6px 12px 6px 12px; } /* line 72, site.css.sass */ #yield_content #mainContent { diff --git a/java/com.sap.sailing.www/release_notes.css b/java/com.sap.sailing.www/release_notes.css index f66130f21c8..130857a5cbc 100644 --- a/java/com.sap.sailing.www/release_notes.css +++ b/java/com.sap.sailing.www/release_notes.css @@ -9,6 +9,7 @@ body{ margin: 0 0 10px 0; border-bottom: 2px solid #222222; } + #yield_content #mainContent .articleHeadline { border-bottom: none; } diff --git a/java/com.sap.sailing.www/release_notes_RCApp.html b/java/com.sap.sailing.www/release_notes_RCApp.html index 0ec70f07c3e..928bbdfe284 100644 --- a/java/com.sap.sailing.www/release_notes_RCApp.html +++ b/java/com.sap.sailing.www/release_notes_RCApp.html @@ -15,7 +15,7 @@ SAP Website
diff --git a/java/com.sap.sailing.www/release_notes_admin.html b/java/com.sap.sailing.www/release_notes_admin.html index 0dc433a474b..14ab67eac2f 100644 --- a/java/com.sap.sailing.www/release_notes_admin.html +++ b/java/com.sap.sailing.www/release_notes_admin.html @@ -15,7 +15,7 @@ SAP Website
diff --git a/java/com.sap.sailing.www/release_notes_analyze.html b/java/com.sap.sailing.www/release_notes_analyze.html index 83229716860..512b98f06bb 100644 --- a/java/com.sap.sailing.www/release_notes_analyze.html +++ b/java/com.sap.sailing.www/release_notes_analyze.html @@ -15,7 +15,7 @@ SAP Website
diff --git a/java/com.sap.sailing.xmlexport/src/com/sap/sailing/xmlexport/LeaderboardData.java b/java/com.sap.sailing.xmlexport/src/com/sap/sailing/xmlexport/LeaderboardData.java index 37d32c4f506..617b52fa63e 100644 --- a/java/com.sap.sailing.xmlexport/src/com/sap/sailing/xmlexport/LeaderboardData.java +++ b/java/com.sap.sailing.xmlexport/src/com/sap/sailing/xmlexport/LeaderboardData.java @@ -430,6 +430,8 @@ public class LeaderboardData extends ExportAction { addNamedElementWithValue(legElement, "mark_from", leg.getFrom().getName()); addNamedElementWithValue(legElement, "mark_to", leg.getTo().getName()); addNamedElementWithValue(legElement, "leg_type", trackedLeg.getLegType(trackedLeg.getTrackedRace().getStartOfRace()).name()); + addNamedElementWithValue(legElement, "great_circle_distance_at_start_of_race_in_meters", trackedLeg.getGreatCircleDistance(trackedLeg.getTrackedRace().getStartOfRace()).getMeters()); + addNamedElementWithValue(legElement, "great_circle_distance_at_end_of_race_in_meters", trackedLeg.getGreatCircleDistance(trackedLeg.getTrackedRace().getEndOfRace()).getMeters()); for (Competitor competitor : trackedLeg.getTrackedRace().getCompetitorsFromBestToWorst(/*timePoint*/ trackedLeg.getTrackedRace().getEndOfRace())) { Element competitorElement = createCompetitorXML(competitor, leaderboard, /*shortVersion*/ true, null); @@ -665,9 +667,9 @@ public class LeaderboardData extends ExportAction { TrackedRace raceBefore = null; int sameDayGroupIndex = 0; int raceCounter = 0; for (RaceColumn raceColumn : leaderboard.getRaceColumns()) { for (Fleet fleet : raceColumn.getFleets()) { - sameDayGroupIndex += getSameDayGroupIndex(raceColumn.getTrackedRace(fleet), raceBefore); TrackedRace trackedRace = raceColumn.getTrackedRace(fleet); if (trackedRace != null && trackedRace.hasGPSData()) { + sameDayGroupIndex += getSameDayGroupIndex(raceColumn.getTrackedRace(fleet), raceBefore); TimePoint timeSpentForRace = MillisecondsTimePoint.now(); Pair> raceConfidenceAndErrorMessages = checkData(trackedRace); final List legs = new ArrayList(); diff --git a/java/com.tractrac.clientmodule/.classpath b/java/com.tractrac.clientmodule/.classpath index c4d932d2539..8bb6ac57c5b 100755 --- a/java/com.tractrac.clientmodule/.classpath +++ b/java/com.tractrac.clientmodule/.classpath @@ -6,7 +6,6 @@ - diff --git a/java/com.tractrac.clientmodule/META-INF/MANIFEST.MF b/java/com.tractrac.clientmodule/META-INF/MANIFEST.MF index 8151f6776e8..e0c85eed8f4 100755 --- a/java/com.tractrac.clientmodule/META-INF/MANIFEST.MF +++ b/java/com.tractrac.clientmodule/META-INF/MANIFEST.MF @@ -2,7 +2,7 @@ Manifest-Version: 1.0 Bundle-ManifestVersion: 2 Bundle-Name: TracTrac Client module Bundle-SymbolicName: com.tractrac.clientmodule -Bundle-Version: 2.0.11.qualifier +Bundle-Version: 2.0.12.qualifier Bundle-RequiredExecutionEnvironment: JavaSE-1.7 Bundle-ClassPath: lib/TracTracClientModule.jar, . @@ -39,7 +39,6 @@ Export-Package: com.maptrack.asio, com.maptrack.utils.seqtimedatatable.simple, com.maptrack.utils.sortedset, com.maptrack.utils.sortedset.btree, - com.sap.tractrac.clientmodule.util, com.tractrac.clientmodule, com.tractrac.clientmodule.data, com.tractrac.clientmodule.data.containers, diff --git a/java/com.tractrac.clientmodule/README.txt b/java/com.tractrac.clientmodule/README.txt index 43f9fe06e4a..93074dca5d8 100644 --- a/java/com.tractrac.clientmodule/README.txt +++ b/java/com.tractrac.clientmodule/README.txt @@ -1,5 +1,5 @@ ******************************************** -******* TracTracClientModule 2.0.11 ******** +******* TracTracClientModule 2.0.12 ******** ******************************************** This release only contains changes in its implementation (it keeps the previous API). @@ -20,6 +20,19 @@ It contains also some files: 2) New features +- Fixing a bug reading MTB files. In some scenarios when the positions of one boat arrive with a big delay, +they can be discarded by the library. The positions are in the MTB file and it is not necessary to +regenerate the files again. It is just a bug in the reading process. + + +******************************************** +******* TracTracClientModule 2.0.11 ******** +******************************************** + +This release only contains changes in its implementation (it keeps the previous API). + +1) New features + - Fixed a deadlock in the code. If the consummer aplication invokes a method in the datacontroller, a deadlock can happen because the stack of pending messages is locked. Now, it is always possible to add a new message to the queue of pending messages and the system will process it as soon as posible. diff --git a/java/com.tractrac.clientmodule/build.properties b/java/com.tractrac.clientmodule/build.properties index 40ec2905ec6..405d4909642 100755 --- a/java/com.tractrac.clientmodule/build.properties +++ b/java/com.tractrac.clientmodule/build.properties @@ -1,5 +1,3 @@ -source.. = src/ -output.. = bin/ bin.includes = META-INF/,\ .,\ lib/TracTracClientModule.jar diff --git a/java/com.tractrac.clientmodule/lib/TracTracClientModule.jar b/java/com.tractrac.clientmodule/lib/TracTracClientModule.jar index 86de2d1050b..3ecaaeec77f 100755 Binary files a/java/com.tractrac.clientmodule/lib/TracTracClientModule.jar and b/java/com.tractrac.clientmodule/lib/TracTracClientModule.jar differ diff --git a/java/com.tractrac.clientmodule/pom.xml b/java/com.tractrac.clientmodule/pom.xml index c27789f2009..b408fd22fd5 100644 --- a/java/com.tractrac.clientmodule/pom.xml +++ b/java/com.tractrac.clientmodule/pom.xml @@ -8,6 +8,6 @@ 1.0.0-SNAPSHOT com.tractrac.clientmodule - 2.0.11-SNAPSHOT + 2.0.12-SNAPSHOT eclipse-plugin diff --git a/java/com.tractrac.clientmodule/src/com/sap/tractrac/clientmodule/util/Base64.java b/java/com.tractrac.clientmodule/src/com/sap/tractrac/clientmodule/util/Base64.java deleted file mode 100755 index 97f3e1feb04..00000000000 --- a/java/com.tractrac.clientmodule/src/com/sap/tractrac/clientmodule/util/Base64.java +++ /dev/null @@ -1,210 +0,0 @@ -package com.sap.tractrac.clientmodule.util; - -/** - * Implements a BASE64 encoder and decoder. Class Base64 provides - * static encoding- and decoding-methods for describing binary data through - * printable characters. The implementation is compliant to RFC 1521. - * - * @copyright @version $Revision: #1 $. - * @author Stefan Kusterer, Last modified by $Author: d038253 $, Change list - * $Change: 156641 $. - */ -public class Base64 { - - protected static final char[] CHAR_LOOKUP_ARRAY = { - /* 0 */'A', /* 1 */'B', /* 2 */'C', /* 3 */'D', - /* 4 */'E', /* 5 */'F', /* 6 */'G', /* 7 */'H', - /* 8 */'I', /* 9 */'J', /* 10 */'K', /* 11 */'L', - /* 12 */'M', /* 13 */'N', /* 14 */'O', /* 15 */'P', - /* 16 */'Q', /* 17 */'R', /* 18 */'S', /* 19 */'T', - /* 20 */'U', /* 21 */'V', /* 22 */'W', /* 23 */'X', - /* 24 */'Y', /* 25 */'Z', - /* 26 */'a', /* 27 */'b', /* 28 */'c', /* 29 */'d', - /* 30 */'e', /* 31 */'f', /* 32 */'g', /* 33 */'h', - /* 34 */'i', /* 35 */'j', /* 36 */'k', /* 37 */'l', - /* 38 */'m', /* 39 */'n', /* 40 */'o', /* 41 */'p', - /* 42 */'q', /* 43 */'r', /* 44 */'s', /* 45 */'t', - /* 46 */'u', /* 47 */'v', /* 48 */'w', /* 49 */'x', - /* 50 */'y', /* 51 */'z', - /* 52 */'0', /* 53 */'1', /* 54 */'2', /* 55 */'3', - /* 56 */'4', /* 57 */'5', /* 58 */'6', /* 59 */'7', - /* 60 */'8', /* 61 */'9', - /* 62 */'+', /* 63 */'/', - /* pad */'=' }; - - protected static final int[] VALUE_LOOKUP_ARRAY = new int[128]; - - static // Initializer - { - for ( char i = 0; i < VALUE_LOOKUP_ARRAY.length; i++ ) { - if ( CHAR_LOOKUP_ARRAY[0] <= i && i <= CHAR_LOOKUP_ARRAY[25] ) { - VALUE_LOOKUP_ARRAY[i] = ( i - CHAR_LOOKUP_ARRAY[0] ); - } else if ( CHAR_LOOKUP_ARRAY[26] <= i && i <= CHAR_LOOKUP_ARRAY[51] ) { - VALUE_LOOKUP_ARRAY[i] = ( i - CHAR_LOOKUP_ARRAY[26] ) + 26; - } else if ( CHAR_LOOKUP_ARRAY[52] <= i && i <= CHAR_LOOKUP_ARRAY[61] ) { - VALUE_LOOKUP_ARRAY[i] = ( i - CHAR_LOOKUP_ARRAY[52] ) + 52; - } else if ( i == CHAR_LOOKUP_ARRAY[62] ) { - VALUE_LOOKUP_ARRAY[i] = 62; - } else if ( i == CHAR_LOOKUP_ARRAY[63] ) { - VALUE_LOOKUP_ARRAY[i] = 63; - } else if ( i == CHAR_LOOKUP_ARRAY[64] ) { - VALUE_LOOKUP_ARRAY[i] = -1; - } else { - VALUE_LOOKUP_ARRAY[i] = -2; - } - } - } - - // do not allow to instantiate this class - protected Base64( ) { - // only static methods - } - - public final static byte[] decode(String in) { - char[] c = new char[in.length()]; - in.getChars(0, in.length(), c, 0); - return decode(c); - } - - /** - * decode a given array of characters. - * - * @param in The input array of characters - * @return The array of bytes - */ - public final static byte[] decode( char[] in ) { - - if ( in == null || in.length == 0 ) { - return new byte[0]; - } - - int index_in; - int index_out; - int helper_1 = 0; - int helper_2 = 0; - int mod = 0; - int in_length = in.length; - int chr; - - // Determine number of used characters: Ignore linebreaks etc. and count - // trailing =-signes - for ( index_in = 0; index_in < in.length; index_in++ ) { - chr = in[index_in]; - if ( chr >= 128 ) { - in_length--; - } else if (VALUE_LOOKUP_ARRAY[chr] < 0) { - in_length--; - } - } - - // Allocate out-buffer - byte out[] = new byte[( in_length >>> 2 ) * 3 + ( ( in_length & 0x03 ) > 0 ? ( in_length & 0x03 ) - 1 : 0 )]; - - // Do the real decoding - for ( index_in = 0, index_out = 0; index_in < in.length && index_out < out.length; index_in++ ) { - chr = in[index_in]; - if ( chr > 127 || VALUE_LOOKUP_ARRAY[chr] == -2 ) { - continue; - } - - helper_1 = helper_2; - helper_2 = VALUE_LOOKUP_ARRAY[chr] > 0 ? VALUE_LOOKUP_ARRAY[chr] : 0; - - switch ( mod ) { - case 0: - // no operation - break; - case 1: - out[index_out++] = (byte) ( ( helper_1 << 2 ) & 0xFC | ( helper_2 >>> 4 ) & 0x03 ); - break; - case 2: - out[index_out++] = (byte) ( ( helper_1 << 4 ) & 0xF0 | ( helper_2 >>> 2 ) & 0x0F ); - break; - case 3: - out[index_out++] = (byte) ( ( helper_1 << 6 ) & 0xC0 | helper_2 & 0x3F ); - break; - } - - mod = ( mod < 3 ? mod + 1 : 0 ); - } - - return out; - } - - /** - * Add a charcter to an array of chars and insert linebreas if necessary - */ - private final static int writeToCharArray( char[] out, int idx, char chr ) { - out[idx++] = chr; - return idx; - } - - /** - * encode a given array. - * - * @param in the input array of binary data - * @return The array of characters - */ - public final static String encode( byte[] in ) { - - if ( in == null ) { - return null; - } - - int index_in; - int index_out; - char chr; - - // Allocate buffer for result: Consider chars for trailing =-signs - // and linebreaks. - char out[] = new char[( ( ( in.length + 2 ) / 3 ) << 2 )]; - - for ( index_in = 0, index_out = 0; index_in < in.length - 2; index_in += 3 ) { - // compute first byte: highest six bits of first byte - chr = CHAR_LOOKUP_ARRAY[( in[index_in] >>> 2 ) & 0x3F]; - index_out = writeToCharArray( out, index_out, chr ); - - // compute second byte: lowest two bits of first byte - chr = CHAR_LOOKUP_ARRAY[( in[index_in] << 4 ) & 0x30 | - // and highest four bits of second byte - ( in[index_in + 1] >>> 4 ) & 0x0F]; - index_out = writeToCharArray( out, index_out, chr ); - - // compute third byte: lowest four bits of second byte - chr = CHAR_LOOKUP_ARRAY[( in[index_in + 1] << 2 ) & 0x3C | - // and higest two bits of third byte - ( in[index_in + 2] >>> 6 ) & 0x03]; - index_out = writeToCharArray( out, index_out, chr ); - - // compute fourth byte: lowest six bits of third byte - chr = CHAR_LOOKUP_ARRAY[in[index_in + 2] & 0x3F]; - index_out = writeToCharArray( out, index_out, chr ); - } - - // take care of the last bytes (one or two) - if ( index_in < in.length ) { - chr = CHAR_LOOKUP_ARRAY[( in[index_in] >>> 2 ) & 0x3F]; - index_out = writeToCharArray( out, index_out, chr ); - - if ( index_in < in.length - 1 ) { - // there are two remaining bytes - chr = CHAR_LOOKUP_ARRAY[( in[index_in] << 4 ) & 0x30 | ( in[index_in + 1] >>> 4 ) & 0x0F]; - index_out = writeToCharArray( out, index_out, chr ); - - chr = CHAR_LOOKUP_ARRAY[( in[index_in + 1] << 2 ) & 0x3F]; - index_out = writeToCharArray( out, index_out, chr ); - } else { - // there is only one remaining byte - chr = CHAR_LOOKUP_ARRAY[( in[index_in] << 4 ) & 0x30]; - index_out = writeToCharArray( out, index_out, chr ); - } - } - - // add padding =-signs if required - while ( index_out < out.length ) { - index_out = writeToCharArray( out, index_out, CHAR_LOOKUP_ARRAY[64] ); - } - - return new String(out); - } -} diff --git a/wiki/planning/analysisscenarios.md b/wiki/planning/analysisscenarios.md index 684f968db8f..5dd99ff01df 100644 --- a/wiki/planning/analysisscenarios.md +++ b/wiki/planning/analysisscenarios.md @@ -4,4 +4,18 @@ We find that users would like certain analysis scenarios be supported in easier More advanced users also like to perform historic analyses and would like to see a more systematic approach regarding filtering and aggregation of various metrics accumulated by the core sailing analytics. To what degree should we strengthen an extraction to HANA with Business Objects (BOBJ) tools on top, and to what degree should we aim for an integrated approach where the sailing analytics offer the desired filtering and aggregation features in their Java environment? -We need to understand what the ideal UI approach supporting this would be. Is this a portal with portlets and widgets, or is it a set of pre-configured existing components? We will need UID consultancy for this. \ No newline at end of file +We need to understand what the ideal UI approach supporting this would be. Is this a portal with portlets and widgets, or is it a set of preconfigured existing components? We will need UID consultancy for this. + +## Candidates for analytical scenarios: +* Start analysis +* Maneuver performance analysis +* Speed analysis +* Track analysis +* Upwind/Downwind performance comparison +* Center of gravity of the competitor field +* Wind change/trend +* Results +* Course and course geometry analysis +* Race simulation (based on Christopher's simulator) +* Sailor profile +* Sailor comparison \ No newline at end of file diff --git a/wiki/planning/finding-a-design-agency.md b/wiki/planning/finding-a-design-agency.md index 4c06898f019..a2388e35180 100644 --- a/wiki/planning/finding-a-design-agency.md +++ b/wiki/planning/finding-a-design-agency.md @@ -1,4 +1,148 @@ -# Finding a design agency +# Finding a Design Agency + +[[_TOC_]] + +# Meeting preparations + +## Questions + +1. Wie sieht der Gesamtprozess vom "Verstehen der Anforderungen" bis zur +"Implementierung" aus? +2. Wie läuft das Projektmanagement? +3. Wie werden Designentscheidungen dokumentiert? +4. Wie werden alternative Entwürfe behandelt? +5. Wie wird die Usability getestet? (gibt es Usertests? wie oft?) +6. Wie wird die Kompatibilität der Lösung für den Device-Zoo sichergestellt? +Euch fallen sicher auch ein paar gute Fragen ein. Dazu kommen Axel's +Fragen, die eher allgemeine Rahmenbedingungen betreffen: +7. Frühester Starttermin +8. Anzahl verfügbarer Leute +9. Technlogie-Kompetenzen +10. Anzahl möglicher paralleler Projekte + +## Possible Process per Project + +1. We define the basic page flow and describe a minimal feature set in a document. +2. A ramp-up workshop with the analytics team and the agency makes sure that everyone at the agency is on the same level +3. Agency creates a design that shows all relevant pages (mockup). This step is delivered by using images. +4. The agency creates a clickable prototype based on the mockups. This prototype must work on all target devices and be implemented in HTML or native UI. +5. Sailing team starts integration with the server. +6. Agency provides long-term support for changes. Lifecycle is communicated with agency. + +## Decision Matrix + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
ObjectiveCreative WorklineUbilabsGMRDigitalsunrayMedienfabrik
Android Knowledge, References and Developers?
Mobile HTML Knowledge, References and Developers?
Professional Meeting in terms of preparation and participants?
GWT Knowledge?
Technical Knowledge (GIT, SVN, ...)?
Knowledge of Sailing Domain?
Team size of developers and designers (10+)?
+ +# Meeting Notes (20.01.2014) + +Participants: Axel, Frank, Simon + +- We have four projects that we would like to work on with an external agency + +1. Race Committee App +2. Analytics Homepage +3. Race Board +4. TV Overlays + +- Important to make a decision about what we really want first before going into the process of deciding which agencies to go for. Agreed on the following workflow for each project: + +1. We define the basic page flow and describe a minimal feature set in a document. +2. A ramp-up workshop with the analytics team and the agency makes sure that everyone at the agency is on the same level +3. Agency creates a design that shows all relevant pages (mockup). This design is delivered by using images. +4. The agency creates a clickable prototype based on the mockups. This prototype must work on all target devices. +5. Sailing team starts integration with the server. +6. Agency provides long-term support for changes. Lifecycle is communicated with agency. + +- The following criteria (order=priority) has been defined and guide the process on deciding for an agency: + +1. Design skills show professional work and a deep understanding of mobile devices and user interaction +2. References show that the agency tries hard to understand the domain the project is built for +3. Android skills at least for views +4. Based in proximity of WDF or at least in Germany + +- Applying these criteria to the list of agencies, we agreed on the following three agencies: + +1. Ubilabs +2. Creative Workline +3. Sysvision + +- RaceBoard is a very complex topic. We agreed that we can't decide on the concrete design or the feature set now. But we have a basic understanding how we want to improve it and what we expect from a redesign. We can't decide now if it will be native or HTML5. We include into the projects we need help from the agency but we don't expect a solution right now. Agreed that we will try to get feedback from the agency and then define the project. We tell an agency that they should leave placeholders in the Analytics Homepage project for analytics that we might define later (start analysis, data mining). + +- In order to speed up the time to market we discussed the possibility of continuing the work on the Analytics Homepage with App House and later order Pier2Port to implement the prototype in HTML5. We agreed that this could be a way to go as we can't actually give any estimation for the time and effort an agency needs to implement this project. Stefan needs to agree as this would mean to put some more money aside. + +- Agreed on the following action items: + +1. Creating an email describing who we are and what we want (Simon) +2. Sending out that email and calling each agency in order to schedule a meeting (Simon) +3. Create a document that describes the features for the Analytics Homepage (Frank) +4. Check with Stefan that parallel work is ok (internal=external budget) (Axel) + +# Agencies @@ -91,7 +235,7 @@ Telefon: 040 / 22 81 72 62 0
-Priority list +# Priority list @@ -118,48 +262,4 @@ Priority list -
? ?
- -## Meeting Notes (20.01.2014) - -Participants: Axel, Frank, Simon - -- We have four projects that we would like to work on with an external agency - -1. Race Committee App -2. Analytics Homepage -3. Race Board -4. TV Overlays - -- Important to make a decision about what we really want first before going into the process of deciding which agencies to go for. Agreed on the following workflow for each project: - -1. We define the basic page flow and describe a minimal feature set in a document. -2. A ramp-up workshop with the analytics team and the agency makes sure that everyone at the agency is on the same level -3. Agency creates a design that shows all relevant pages (mockup). This design is delivered by using images. -4. The agency creates a clickable prototype based on the mockups. This prototype must work on all target devices. -5. Sailing team starts integration with the server. -6. Agency provides long-term support for changes. Lifecycle is communicated with agency. - -- The following criteria (order=priority) has been defined and guide the process on deciding for an agency: - -1. Design skills show professional work and a deep understanding of mobile devices and user interaction -2. References show that the agency tries hard to understand the domain the project is built for -3. Android skills at least for views -4. Based in proximity of WDF or at least in Germany - -- Applying these criteria to the list of agencies, we agreed on the following three agencies: - -1. Ubilabs -2. Creative Workline -3. Sysvision - -- RaceBoard is a very complex topic. We agreed that we can't decide on the concrete design or the feature set now. But we have a basic understanding how we want to improve it and what we expect from a redesign. We can't decide now if it will be native or HTML5. We include into the projects we need help from the agency but we don't expect a solution right now. Agreed that we will try to get feedback from the agency and then define the project. We tell an agency that they should leave placeholders in the Analytics Homepage project for analytics that we might define later (start analysis, data mining). - -- In order to speed up the time to market we discussed the possibility of continuing the work on the Analytics Homepage with App House and later order Pier2Port to implement the prototype in HTML5. We agreed that this could be a way to go as we can't actually give any estimation for the time and effort an agency needs to implement this project. Stefan needs to agree as this would mean to put some more money aside. - -- Agreed on the following action items: - -1. Creating an email describing who we are and what we want (Simon) -2. Sending out that email and calling each agency in order to schedule a meeting (Simon) -3. Create a document that describes the features for the Analytics Homepage (Frank) -4. Check with Stefan that parallel work is ok (internal=external budget) (Axel) \ No newline at end of file + \ No newline at end of file