Merge branch 'master' into mak-change-timepanel-controls

This commit is contained in:
Marcus Kammer committed 2012-05-29 11:58:08 +02:00
commit 552d10027a
61 files changed
+799 -350

No files matched your search

@@ -57,7 +57,10 @@ public class DeclinationServiceImpl implements DeclinationService {
int year = cal.get(Calendar.YEAR);
QuadTree<Declination> set;
while ((set = getYearStore(year)) != null) {
Declination resultForYear = set.get(position);
Declination resultForYear;
synchronized (set) {
resultForYear = set.get(position);
}
Distance spatialDistance = resultForYear.getPosition().getDistance(position);
// consider result only if it's closer than maxDistance
if (spatialDistance.compareTo(maxDistance) <= 0) {
@@ -73,7 +76,9 @@ public class DeclinationServiceImpl implements DeclinationService {
if (result == null) {
QuadTree<Declination> importerCacheForYear = importerCache.get(year);
if (importerCacheForYear != null) {
result = importerCacheForYear.get(position);
synchronized (importerCacheForYear) {
result = importerCacheForYear.get(position);
}
if (result.getPosition().getDistance(position).compareTo(maxDistance) <= 0) {
return result;
// else it's further away from the requested position as demanded by maxDistance
@@ -85,7 +90,9 @@ public class DeclinationServiceImpl implements DeclinationService {
importerCacheForYear = new QuadTree<Declination>();
importerCache.put(year, importerCacheForYear);
}
importerCacheForYear.put(result.getPosition(), result);
synchronized (importerCacheForYear) {
importerCacheForYear.put(result.getPosition(), result);
}
}
}
return result;
@@ -49,7 +49,9 @@ public class DeclinationStore {
result = new QuadTree<Declination>();
BufferedReader in = new BufferedReader(new InputStreamReader(is));
while ((record = readExternal(in)) != null) {
result.put(record.getPosition(), record);
synchronized (result) {
result.put(record.getPosition(), record);
}
}
}
return result;
@@ -150,7 +152,10 @@ public class DeclinationStore {
System.out.println("Date: " + year + "/" + (month + 1) + ", Latitude: " + lat);
for (double lng = 0; lng < 180; lng += grid) {
Position point = new DegreePosition(lat, lng);
Declination existingDeclinationRecord = storedDeclinations.get(point);
Declination existingDeclinationRecord;
synchronized (storedDeclinations) {
existingDeclinationRecord = storedDeclinations.get(point);
}
if (existingDeclinationRecord == null
|| DeclinationServiceImpl.timeAndSpaceDistance(existingDeclinationRecord
.getPosition().getDistance(point), timePoint, existingDeclinationRecord
@@ -161,7 +166,10 @@ public class DeclinationStore {
}
for (double lng = -grid; lng > -180; lng -= grid) {
Position point = new DegreePosition(lat, lng);
Declination existingDeclinationRecord = storedDeclinations.get(point);
Declination existingDeclinationRecord;
synchronized (storedDeclinations) {
existingDeclinationRecord = storedDeclinations.get(point);
}
if (existingDeclinationRecord == null
|| DeclinationServiceImpl.timeAndSpaceDistance(existingDeclinationRecord
.getPosition().getDistance(point), timePoint, existingDeclinationRecord
@@ -175,7 +183,10 @@ public class DeclinationStore {
System.out.println("Date: " + year + "/" + (month + 1) + ", Latitude: " + lat);
for (double lng = 0; lng < 180; lng += grid) {
Position point = new DegreePosition(lat, lng);
Declination existingDeclinationRecord = storedDeclinations.get(point);
Declination existingDeclinationRecord;
synchronized (storedDeclinations) {
existingDeclinationRecord = storedDeclinations.get(point);
}
if (DeclinationServiceImpl.timeAndSpaceDistance(existingDeclinationRecord.getPosition().getDistance(point),
timePoint, existingDeclinationRecord.getTimePoint()) > 0.1) {
// less than ~6 nautical miles and/or ~.6 months off
@@ -184,7 +195,10 @@ public class DeclinationStore {
}
for (double lng = -grid; lng > -180; lng -= grid) {
Position point = new DegreePosition(lat, lng);
Declination existingDeclinationRecord = storedDeclinations.get(point);
Declination existingDeclinationRecord;
synchronized (storedDeclinations) {
existingDeclinationRecord = storedDeclinations.get(point);
}
if (DeclinationServiceImpl.timeAndSpaceDistance(existingDeclinationRecord.getPosition().getDistance(point),
timePoint, existingDeclinationRecord.getTimePoint()) > 0.1) {
// less than ~6 nautical miles and/or ~.6 months off
@@ -7,4 +7,5 @@ Bundle-Vendor: SAP
Bundle-RequiredExecutionEnvironment: JavaSE-1.6
Export-Package: com.sap.sailing.domain.common,
com.sap.sailing.domain.common.impl,
com.sap.sailing.domain.common.quadtree
com.sap.sailing.domain.common.quadtree,
com.sap.sailing.domain.common.quadtree.impl;x-friends:="com.sap.sailing.domain.test"
@@ -12,9 +12,12 @@ public class AbstractPosition implements Position {
}
public boolean equals(Object o) {
return o instanceof Position &&
getLatRad() == ((Position) o).getLatRad() &&
getLngRad() == ((Position) o).getLngRad();
if (o == null) {
return false;
} else {
return o instanceof Position && getLatRad() == ((Position) o).getLatRad()
&& getLngRad() == ((Position) o).getLngRad();
}
}
@Override
@@ -32,11 +32,16 @@ import com.sap.sailing.domain.common.quadtree.impl.Bounds;
import com.sap.sailing.domain.common.quadtree.impl.QuadTreeNode;
/**
* The QuadTree lets you organize objects in a grid, that redefines
* itself and focuses more gridding when more objects appear in a
* certain area.
* The QuadTree lets you organize objects in a grid, that redefines itself and focuses more gridding when more objects
* appear in a certain area.
* <p>
*
* @param <T> type of object stored by coordinates
* Note that this class is not thread safe. If multiple threads can access the same instance concurrently, callers have
* to ensure proper synchronization. Concurrent reads are permissible while any write should block all other operations.
*
* @param <T>
* type of object stored by coordinates
* @author Axel Uhl (D043530)
*/
public class QuadTree<T> implements Serializable {
@@ -110,7 +110,7 @@ public class QuadTreeNode<T> implements Serializable {
* into the children.
*/
@SuppressWarnings("unchecked")
protected void split() {
protected void split() {
// Make sure we're bigger than the minimum, if we care,
if (minSize != NO_MIN_SIZE) {
if (Math.abs(bounds.getNorthEast().getLatDeg() - bounds.getSouthWest().getLatDeg()) < minSize
@@ -121,7 +121,6 @@ public class QuadTreeNode<T> implements Serializable {
double nsHalf = (bounds.getNorthEast().getLatDeg() + bounds.getSouthWest().getLatDeg()) / 2.0;
double ewHalf = (bounds.getNorthEast().getLngDeg() + bounds.getSouthWest().getLngDeg()) / 2.0;
children = new QuadTreeNode[4];
children[NORTHWEST] = new QuadTreeNode<T>(new Bounds(new DegreePosition(nsHalf, bounds.getSouthWest().getLngDeg()), new DegreePosition(bounds.getNorthEast().getLatDeg(), ewHalf)), maxItems);
children[NORTHEAST] = new QuadTreeNode<T>(new Bounds(new DegreePosition(nsHalf, ewHalf), bounds.getNorthEast()), maxItems);
children[SOUTHEAST] = new QuadTreeNode<T>(new Bounds(new DegreePosition(bounds.getSouthWest().getLatDeg(), ewHalf), new DegreePosition(nsHalf, bounds.getNorthEast().getLngDeg())), maxItems);
@@ -131,7 +130,6 @@ public class QuadTreeNode<T> implements Serializable {
for (Iterator<QuadTreeLeaf<T>> i=temp.iterator(); i.hasNext(); ) {
put(i.next());
}
//items.removeAllElements();
}
/**
@@ -208,9 +206,9 @@ public class QuadTreeNode<T> implements Serializable {
this.allTheSamePoint = false;
}
}
if (this.items.size() > maxItems && !this.allTheSamePoint)
if (this.items.size() > maxItems && !this.allTheSamePoint) {
split();
}
} else {
QuadTreeNode<T> node = getChild(leaf.getPoint());
if (node != null) {
@@ -51,6 +51,7 @@ import com.sap.sailing.domain.leaderboard.LeaderboardGroup;
import com.sap.sailing.domain.leaderboard.SettableScoreCorrection;
import com.sap.sailing.domain.leaderboard.ThresholdBasedResultDiscardingRule;
import com.sap.sailing.domain.leaderboard.impl.LeaderboardGroupImpl;
import com.sap.sailing.domain.leaderboard.impl.LowerScoreIsBetter;
import com.sap.sailing.domain.leaderboard.impl.ResultDiscardingRuleImpl;
import com.sap.sailing.domain.leaderboard.impl.ScoreCorrectionImpl;
import com.sap.sailing.domain.persistence.DomainObjectFactory;
@@ -170,7 +171,7 @@ public class DomainObjectFactoryImpl implements DomainObjectFactory {
}
ThresholdBasedResultDiscardingRule resultDiscardingRule = new ResultDiscardingRuleImpl(discardIndexResultsStartingWithHowManyRaces);
FlexibleLeaderboardImplWithDelayedCarriedPoints result = new FlexibleLeaderboardImplWithDelayedCarriedPoints(
(String) o.get(FieldNames.LEADERBOARD_NAME.name()), scoreCorrection, resultDiscardingRule);
(String) o.get(FieldNames.LEADERBOARD_NAME.name()), scoreCorrection, resultDiscardingRule, new LowerScoreIsBetter());
BasicDBList dbRaceColumns = (BasicDBList) o.get(FieldNames.LEADERBOARD_COLUMNS.name());
// For a FlexibleLeaderboard, fleets are owned by the leaderboard's RaceColumn objects. We need to manage them here:
Map<String, Fleet> fleetsByName = new HashMap<String, Fleet>();
@@ -1,5 +1,6 @@
package com.sap.sailing.domain.persistence.impl;
import java.util.Comparator;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
@@ -60,8 +61,8 @@ public class FlexibleLeaderboardImplWithDelayedCarriedPoints extends FlexibleLea
}
public FlexibleLeaderboardImplWithDelayedCarriedPoints(String name, SettableScoreCorrection scoreCorrection,
ThresholdBasedResultDiscardingRule resultDiscardingRule) {
super(name, scoreCorrection, resultDiscardingRule);
ThresholdBasedResultDiscardingRule resultDiscardingRule, Comparator<Integer> scoreComparator) {
super(name, scoreCorrection, resultDiscardingRule, scoreComparator);
carriedPointsByCompetitorName = new HashMap<String, Integer>();
maxPointsReasonsByCompetitorName = new HashMap<String, Map<RaceColumn,MaxPointsReason>>();
correctedScoresByCompetitorName = new HashMap<String, Map<RaceColumn,Integer>>();
@@ -1,8 +1,10 @@
package com.sap.sailing.domain.test;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
@@ -80,4 +82,46 @@ public class CourseTest {
assertEquals(0, Util.size(course.getWaypoints()));
assertEquals(0, Util.size(course.getLegs()));
}
@Test
public void testInsertWaypointToCourseWithTwoWaypoints() {
List<Waypoint> waypoints = new ArrayList<Waypoint>();
final WaypointImpl wp1 = new WaypointImpl(new BuoyImpl("Test Buoy 1"));
waypoints.add(wp1);
final WaypointImpl wp2 = new WaypointImpl(new BuoyImpl("Test Buoy 2"));
waypoints.add(wp2);
Course course = new CourseImpl("Test Course", waypoints);
assertEquals(2, Util.size(course.getWaypoints()));
assertEquals(1, Util.size(course.getLegs()));
final WaypointImpl wp1_5 = new WaypointImpl(new BuoyImpl("Test Buoy 1.5"));
course.addWaypoint(1, wp1_5);
assertEquals(3, Util.size(course.getWaypoints()));
assertEquals(2, Util.size(course.getLegs()));
assertTrue(Util.equals(Arrays.asList(new Waypoint[] { wp1, wp1_5, wp2 }), course.getWaypoints()));
assertEquals(0, course.getIndexOfWaypoint(wp1));
assertEquals(1, course.getIndexOfWaypoint(wp1_5));
assertEquals(2, course.getIndexOfWaypoint(wp2));
}
@Test
public void testRemovetWaypointFromCourseWithThreeWaypoints() {
List<Waypoint> waypoints = new ArrayList<Waypoint>();
final WaypointImpl wp1 = new WaypointImpl(new BuoyImpl("Test Buoy 1"));
waypoints.add(wp1);
final WaypointImpl wp2 = new WaypointImpl(new BuoyImpl("Test Buoy 2"));
waypoints.add(wp2);
final WaypointImpl wp3 = new WaypointImpl(new BuoyImpl("Test Buoy 3"));
waypoints.add(wp3);
Course course = new CourseImpl("Test Course", waypoints);
assertEquals(3, Util.size(course.getWaypoints()));
assertEquals(2, Util.size(course.getLegs()));
course.removeWaypoint(1);
assertEquals(2, Util.size(course.getWaypoints()));
assertEquals(1, Util.size(course.getLegs()));
assertTrue(Util.equals(Arrays.asList(new Waypoint[] { wp1, wp3 }), course.getWaypoints()));
assertEquals(0, course.getIndexOfWaypoint(wp1));
assertEquals(-1, course.getIndexOfWaypoint(wp2));
assertEquals(1, course.getIndexOfWaypoint(wp3));
}
}
@@ -20,6 +20,7 @@ import com.sap.sailing.domain.common.impl.DegreeBearingImpl;
import com.sap.sailing.domain.common.impl.Util.Pair;
import com.sap.sailing.domain.common.impl.WindSourceImpl;
import com.sap.sailing.domain.leaderboard.impl.FlexibleLeaderboardImpl;
import com.sap.sailing.domain.leaderboard.impl.LowerScoreIsBetter;
import com.sap.sailing.domain.leaderboard.impl.ResultDiscardingRuleImpl;
import com.sap.sailing.domain.leaderboard.impl.ScoreCorrectionImpl;
import com.sap.sailing.domain.tracking.impl.WindImpl;
@@ -35,7 +36,8 @@ public class LeaderboardForKielWeekTest extends OnlineTracTracBasedTest {
@Test
public void leaderboardWithOneRaceTest() throws URISyntaxException, NoWindException, IOException, InterruptedException {
leaderboard = new FlexibleLeaderboardImpl("Kiel Week 2011 505s", new ScoreCorrectionImpl(), new ResultDiscardingRuleImpl(new int[] { 3, 6 }));
leaderboard = new FlexibleLeaderboardImpl("Kiel Week 2011 505s", new ScoreCorrectionImpl(),
new ResultDiscardingRuleImpl(new int[] { 3, 6 }), new LowerScoreIsBetter());
Fleet defaultFleet = leaderboard.getFleet(null);
MillisecondsTimePoint now = MillisecondsTimePoint.now();
loadRace("357c700a-9d9a-11e0-85be-406186cbf87c"); // 505 Race 2
@@ -25,6 +25,7 @@ import com.sap.sailing.domain.common.impl.Util;
import com.sap.sailing.domain.common.impl.Util.Pair;
import com.sap.sailing.domain.leaderboard.FlexibleLeaderboard;
import com.sap.sailing.domain.leaderboard.impl.FlexibleLeaderboardImpl;
import com.sap.sailing.domain.leaderboard.impl.LowerScoreIsBetter;
import com.sap.sailing.domain.leaderboard.impl.ResultDiscardingRuleImpl;
import com.sap.sailing.domain.leaderboard.impl.ScoreCorrectionImpl;
import com.sap.sailing.domain.tracking.TrackedRace;
@@ -85,7 +86,7 @@ public class LeaderboardOfflineTest extends AbstractLeaderboardTest {
@Test
public void ensureMedalRaceParamIsIgnoredIfRaceColumnAlreadyExists() {
FlexibleLeaderboard leaderboard = new FlexibleLeaderboardImpl("Test Leaderboard", new ScoreCorrectionImpl(), new ResultDiscardingRuleImpl(
new int[] { 5, 8 }));
new int[] { 5, 8 }), new LowerScoreIsBetter());
Fleet defaultFleet = leaderboard.getFleet(null);
final String columnName = "abc";
setupRaces(1, 0);
@@ -108,7 +109,7 @@ public class LeaderboardOfflineTest extends AbstractLeaderboardTest {
}
ScoreCorrectionImpl scoreCorrection = new ScoreCorrectionImpl();
FlexibleLeaderboard leaderboard = new FlexibleLeaderboardImpl("Test Leaderboard", scoreCorrection, new ResultDiscardingRuleImpl(
new int[] { 1 }));
new int[] { 1 }), new LowerScoreIsBetter());
Fleet defaultFleet = leaderboard.getFleet(null);
int i=0;
int bestScore = Integer.MAX_VALUE;
@@ -144,7 +145,7 @@ public class LeaderboardOfflineTest extends AbstractLeaderboardTest {
}
ScoreCorrectionImpl scoreCorrection = new ScoreCorrectionImpl();
FlexibleLeaderboard leaderboard = new FlexibleLeaderboardImpl("Test Leaderboard", scoreCorrection, new ResultDiscardingRuleImpl(
new int[] { 1 }));
new int[] { 1 }), new LowerScoreIsBetter());
Fleet defaultFleet = leaderboard.getFleet(null);
int i=0;
int bestScore = Integer.MAX_VALUE;
@@ -171,7 +172,7 @@ public class LeaderboardOfflineTest extends AbstractLeaderboardTest {
int secondDiscardingThreshold, Integer carry, boolean addOneMedalRace, int numberOfUntrackedRaces) throws NoWindException {
setupRaces(numberOfStartedRaces, numberOfNotStartedRaces);
FlexibleLeaderboard leaderboard = new FlexibleLeaderboardImpl("Test Leaderboard", new ScoreCorrectionImpl(), new ResultDiscardingRuleImpl(
new int[] { firstDiscardingThreshold, secondDiscardingThreshold }));
new int[] { firstDiscardingThreshold, secondDiscardingThreshold }), new LowerScoreIsBetter());
Fleet defaultFleet = leaderboard.getFleet(null);
int i=0;
for (TrackedRace race : testRaces) {
@@ -22,9 +22,11 @@ import com.sap.sailing.domain.base.impl.FleetImpl;
import com.sap.sailing.domain.base.impl.MillisecondsTimePoint;
import com.sap.sailing.domain.base.impl.RegattaImpl;
import com.sap.sailing.domain.base.impl.SeriesImpl;
import com.sap.sailing.domain.common.MaxPointsReason;
import com.sap.sailing.domain.common.NoWindException;
import com.sap.sailing.domain.common.TimePoint;
import com.sap.sailing.domain.leaderboard.Leaderboard;
import com.sap.sailing.domain.leaderboard.impl.LowerScoreIsBetter;
import com.sap.sailing.domain.leaderboard.impl.RegattaLeaderboardImpl;
import com.sap.sailing.domain.leaderboard.impl.ResultDiscardingRuleImpl;
import com.sap.sailing.domain.leaderboard.impl.ScoreCorrectionImpl;
@@ -36,7 +38,7 @@ public class LeaderboardScoringAndRankingTest extends AbstractLeaderboardTest {
private Leaderboard createLeaderboard(Regatta regatta, int[] discardingThresholds) {
ScoreCorrectionImpl scoreCorrections = new ScoreCorrectionImpl();
ResultDiscardingRuleImpl discardingRules = new ResultDiscardingRuleImpl(discardingThresholds);
return new RegattaLeaderboardImpl(regatta, scoreCorrections, discardingRules);
return new RegattaLeaderboardImpl(regatta, scoreCorrections, discardingRules, new LowerScoreIsBetter());
}
@Test
@@ -56,6 +58,33 @@ public class LeaderboardScoringAndRankingTest extends AbstractLeaderboardTest {
assertEquals(competitors, rankedCompetitors);
}
/**
* Asserts that the competitors ranking worse than the disqualified competitor advance by one
*/
@Test
public void testOneStartedRaceWithDifferentScoresAndDisqualification() {
List<Competitor> competitors = createCompetitors(10);
Regatta regatta = createRegatta(/* qualifying */0, new String[] { "Default" }, /* final */1,
new String[] { "Default" },
/* medal */false, "testOneStartedRaceWithDifferentScores",
DomainFactory.INSTANCE.getOrCreateBoatClass("49er", /* typicallyStartsUpwind */true));
Leaderboard leaderboard = createLeaderboard(regatta, /* discarding thresholds */ new int[0]);
Series finalSeries;
Iterator<? extends Series> seriesIter = regatta.getSeries().iterator();
seriesIter.next();
finalSeries = seriesIter.next();
leaderboard.getScoreCorrection().setMaxPointsReason(competitors.get(5), finalSeries.getRaceColumnByName("F1"), MaxPointsReason.DSQ);
TimePoint now = MillisecondsTimePoint.now();
TimePoint later = new MillisecondsTimePoint(now.asMillis()+1000);
TrackedRace f1 = new MockedTrackedRaceWithStartTimeAndRanks(now, competitors);
RaceColumn f1Column = series.get(1).getRaceColumnByName("F1");
f1Column.setTrackedRace(f1Column.getFleets().iterator().next(), f1);
List<Competitor> rankedCompetitors = leaderboard.getCompetitorsFromBestToWorst(later);
assertEquals(competitors.subList(0, 5), rankedCompetitors.subList(0, 5));
assertEquals(competitors.subList(6, 10), rankedCompetitors.subList(5, 9));
assertEquals(competitors.get(5), rankedCompetitors.get(9));
}
@Test
public void testDistributionAcrossQualifyingFleetsWithDifferentScores() {
List<Competitor> competitors = createCompetitors(10);
@@ -1,6 +1,7 @@
package com.sap.sailing.domain.test;
import java.util.Collections;
import java.util.List;
import com.sap.sailing.domain.base.BoatClass;
import com.sap.sailing.domain.base.Competitor;
@@ -43,6 +44,11 @@ public class MockedTrackedRaceWithFixedRank extends MockedTrackedRace {
}
@Override
public List<Competitor> getCompetitorsFromBestToWorst(TimePoint timePoint) {
return Collections.singletonList(competitor);
}
@Override
public boolean hasStarted(TimePoint at) {
return started;
@@ -412,4 +412,9 @@ public class MockedTrackedRaceWithStartTimeAndRanks implements TrackedRace {
return null;
}
@Override
public List<Competitor> getCompetitorsFromBestToWorst(TimePoint timePoint) {
return competitorsFromBestToWorst;
}
}
@@ -1,12 +1,14 @@
package com.sap.sailing.domain.test;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import org.junit.Test;
import com.sap.sailing.domain.common.Position;
import com.sap.sailing.domain.common.impl.DegreePosition;
import com.sap.sailing.domain.common.quadtree.QuadTree;
import com.sap.sailing.domain.common.quadtree.impl.QuadTreeNode;
public class QuadTreeTest {
private class GLatLngQuadTree extends QuadTree<Position> {
@@ -21,6 +23,53 @@ public class QuadTreeTest {
}
}
private static class QuadTreeWithPublicGetTop<T> extends QuadTree<T> {
private static final long serialVersionUID = -783622065160380333L;
@Override
public QuadTreeNode<T> getTop() {
return super.getTop();
}
}
@Test
public void testNoNPEDuringSecondPutInSameLeaf() {
final QuadTreeWithPublicGetTop<Object> qt = new QuadTreeWithPublicGetTop<Object>();
final Position p = new DegreePosition(0, 0);
final NullPointerException[] npe = new NullPointerException[1];
final boolean[] stop = new boolean[1];
Runnable r = new Runnable() {
@Override
public void run() {
while (!stop[0]) {
synchronized (qt) {
try {
qt.wait();
// if the following try/catch is moved outside the synchronized block, occasional NPEs result
try {
qt.put(p, p);
} catch (NullPointerException e) {
npe[0] = e;
}
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}
}
};
new Thread(r, "1").start();
new Thread(r, "2").start();
new Thread(r, "3").start();
new Thread(r, "4").start();
for (int i=0; i<10000000; i++) {
synchronized(qt) {
qt.notifyAll();
}
assertNull("NullPointerException "+(npe[0]==null?"":npe[0].getMessage())+" during iteration "+i, npe[0]);
}
stop[0] = true;
}
@Test
public void testDistance() {
GLatLngQuadTree quadtree = new GLatLngQuadTree(new DegreePosition(49.29,
@@ -620,4 +620,10 @@ public class MockedTrackedRace implements DynamicTrackedRace {
// TODO Auto-generated method stub
}
@Override
public List<Competitor> getCompetitorsFromBestToWorst(TimePoint timePoint) {
// TODO Auto-generated method stub
return null;
}
}
@@ -23,7 +23,8 @@ import com.sap.sailing.domain.tracking.TrackedRace;
*/
public interface RaceColumn extends Named {
/**
* @return the fleets for each of which this column has a single race and therefore optionally a {@link TrackedRace}
* @return the fleets for each of which this column has a single race and therefore optionally a {@link TrackedRace}, in
* ascending order; best fleets first
*/
Iterable<? extends Fleet> getFleets();
@@ -15,6 +15,9 @@ import com.sap.sailing.domain.common.Named;
*
*/
public interface Series extends Named {
/**
* Returns the fleets of this series, on ascending order, better fleets first.
*/
Iterable<? extends Fleet> getFleets();
/**
@@ -87,6 +87,14 @@ public class CourseImpl extends NamedImpl implements Course {
@Override
public synchronized void addWaypoint(int zeroBasedPosition, Waypoint waypointToAdd) {
waypoints.add(zeroBasedPosition, waypointToAdd);
Map<Waypoint, Integer> updatesToWaypointIndexes = new HashMap<Waypoint, Integer>();
updatesToWaypointIndexes.put(waypointToAdd, zeroBasedPosition);
for (Map.Entry<Waypoint, Integer> e : waypointIndexes.entrySet()) {
if (e.getValue() >= zeroBasedPosition) {
updatesToWaypointIndexes.put(e.getKey(), e.getValue()+1);
}
}
waypointIndexes.putAll(updatesToWaypointIndexes);
int legStartWaypointIndex;
if (zeroBasedPosition == waypoints.size()-1) { // added to end
legStartWaypointIndex = zeroBasedPosition-1;
@@ -104,6 +112,14 @@ public class CourseImpl extends NamedImpl implements Course {
if (zeroBasedPosition >= 0) {
boolean isLast = zeroBasedPosition == waypoints.size()-1;
Waypoint removedWaypoint = waypoints.remove(zeroBasedPosition);
waypointIndexes.remove(removedWaypoint);
Map<Waypoint, Integer> updatesToWaypointIndexes = new HashMap<Waypoint, Integer>();
for (Map.Entry<Waypoint, Integer> e : waypointIndexes.entrySet()) {
if (e.getValue() > zeroBasedPosition) { // only > because the entry with == was just removed
updatesToWaypointIndexes.put(e.getKey(), e.getValue()-1);
}
}
waypointIndexes.putAll(updatesToWaypointIndexes);
if (isLast) {
if (waypoints.size() > 0) { // if we had only one waypoint, we didn't have any legs
// last waypoint was removed; remove last leg
@@ -167,7 +183,7 @@ public class CourseImpl extends NamedImpl implements Course {
}
@Override
public int getIndexOfWaypoint(Waypoint waypoint) {
public synchronized int getIndexOfWaypoint(Waypoint waypoint) {
int result = -1;
Integer indexEntry = waypointIndexes.get(waypoint);
if (indexEntry != null) {
@@ -1,6 +1,7 @@
package com.sap.sailing.domain.base.impl;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@@ -13,6 +14,7 @@ import com.sap.sailing.domain.common.impl.NamedImpl;
public class SeriesImpl extends NamedImpl implements Series {
private static final long serialVersionUID = -1640404303144907381L;
private final Map<String, Fleet> fleetsByName;
private final List<Fleet> fleetsInAscendingOrder;
private final Iterable<RaceColumnInSeriesImpl> raceColumns;
private boolean isMedal;
@@ -22,6 +24,8 @@ public class SeriesImpl extends NamedImpl implements Series {
for (Fleet fleet : fleets) {
this.fleetsByName.put(fleet.getName(), fleet);
}
fleetsInAscendingOrder = new ArrayList<Fleet>(fleetsByName.values());
Collections.sort(fleetsInAscendingOrder);
List<RaceColumnInSeriesImpl> myRaceColumns = new ArrayList<RaceColumnInSeriesImpl>();
for (String raceColumnName : raceColumnNames) {
RaceColumnInSeriesImpl raceColumn = new RaceColumnInSeriesImpl(raceColumnName, this);
@@ -32,7 +36,7 @@ public class SeriesImpl extends NamedImpl implements Series {
}
public Iterable<? extends Fleet> getFleets() {
return fleetsByName.values();
return fleetsInAscendingOrder;
}
@Override
@@ -5,6 +5,7 @@ import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
@@ -18,6 +19,7 @@ import com.sap.sailing.domain.common.TimePoint;
import com.sap.sailing.domain.common.impl.Util;
import com.sap.sailing.domain.common.impl.Util.Pair;
import com.sap.sailing.domain.leaderboard.Leaderboard;
import com.sap.sailing.domain.leaderboard.ScoreCorrection;
import com.sap.sailing.domain.leaderboard.ScoreCorrection.Result;
import com.sap.sailing.domain.leaderboard.SettableScoreCorrection;
import com.sap.sailing.domain.leaderboard.ThresholdBasedResultDiscardingRule;
@@ -46,6 +48,8 @@ public abstract class AbstractLeaderboardImpl implements Leaderboard {
* provided by this map are considered by {@link #getTotalPoints(Competitor, TimePoint)}.
*/
private final Map<Competitor, Integer> carriedPoints;
private final Comparator<Integer> scoreComparator;
/**
* A leaderboard entry representing a snapshot of a cell at a given time point for a single race/competitor.
@@ -96,13 +100,16 @@ public abstract class AbstractLeaderboardImpl implements Leaderboard {
}
/**
* @param scoreComparator the comparator to use to compare basic scores, such as net points
* @param name must not be <code>null</code>
*/
public AbstractLeaderboardImpl(SettableScoreCorrection scoreCorrection, ThresholdBasedResultDiscardingRule resultDiscardingRule) {
public AbstractLeaderboardImpl(SettableScoreCorrection scoreCorrection,
ThresholdBasedResultDiscardingRule resultDiscardingRule, Comparator<Integer> scoreComparator) {
this.carriedPoints = new HashMap<Competitor, Integer>();
this.scoreCorrection = scoreCorrection;
this.displayNames = new HashMap<Competitor, String>();
this.resultDiscardingRule = resultDiscardingRule;
this.scoreComparator = scoreComparator;
}
@Override
@@ -186,7 +193,38 @@ public abstract class AbstractLeaderboardImpl implements Leaderboard {
@Override
public int getTrackedRank(Competitor competitor, RaceColumn race, TimePoint timePoint) throws NoWindException {
final TrackedRace trackedRace = race.getTrackedRace(competitor);
return trackedRace == null ? 0 : trackedRace.hasStarted(timePoint) ? trackedRace.getRank(competitor, timePoint) : 0;
return trackedRace == null ? 0
: trackedRace.hasStarted(timePoint) ? improveByDisqualificationsOfBetterRankedCompetitors(race, trackedRace, timePoint, trackedRace
.getRank(competitor, timePoint)) : 0;
}
/**
* Per competitor disqualified ({@link ScoreCorrection} has a {@link MaxPointsReason} for the competitor), all
* competitors ranked worse by the tracking system need to have their rank corrected by one.
* @param trackedRace the race to which the rank refers; look for disqualifications / max points reasons in this column
* @param timePoint
* time point at which to consider disqualifications (not used yet because currently we don't remember
* <em>when</em> a competitor was disqualified)
* @param rank a competitors rank according to the tracking system
*
* @return the unmodified <code>rank</code> if no disqualifications for better-ranked competitors exist for <code>race</code>,
* or otherwise a rank improved (lowered) by the number of disqualifications of competitors whose tracked rank is better (lower)
* than <code>rank</code>.
*/
private int improveByDisqualificationsOfBetterRankedCompetitors(RaceColumn raceColumn, TrackedRace trackedRace, TimePoint timePoint, int rank) {
int correctedRank = rank;
List<Competitor> competitorsFromBestToWorst = trackedRace.getCompetitorsFromBestToWorst(timePoint);
int betterCompetitorRank=1;
Iterator<Competitor> ci = competitorsFromBestToWorst.iterator();
while (betterCompetitorRank < rank && ci.hasNext()) {
Competitor betterTrackedCompetitor = ci.next();
MaxPointsReason maxPointsReasonForBetterCompetitor = getScoreCorrection().getMaxPointsReason(betterTrackedCompetitor, raceColumn);
if (maxPointsReasonForBetterCompetitor != null && maxPointsReasonForBetterCompetitor != MaxPointsReason.NONE) {
correctedRank--;
}
betterCompetitorRank++;
}
return correctedRank;
}
@Override
@@ -233,7 +271,8 @@ public abstract class AbstractLeaderboardImpl implements Leaderboard {
boolean discarded = isDiscarded(competitor, race, timePoint);
return new EntryImpl(trackedPoints, correctedResults.getCorrectedScore(), correctedResults.isCorrected(),
discarded ? 0
: correctedResults.getCorrectedScore() * (race.isMedalRace() ? 2 : 1), correctedResults.getMaxPointsReason(), discarded);
: correctedResults.getCorrectedScore() * (race.isMedalRace() ? MEDAL_RACE_FACTOR : 1),
correctedResults.getMaxPointsReason(), discarded);
}
@Override
@@ -345,7 +384,7 @@ public abstract class AbstractLeaderboardImpl implements Leaderboard {
} else {
comparisonResult = netPointsAndFleet.get(o1).getB().compareTo(netPointsAndFleet.get(o2).getB());
if (comparisonResult == 0) {
comparisonResult = netPointsAndFleet.get(o1).getA() - netPointsAndFleet.get(o2).getA();
comparisonResult = scoreComparator.compare(netPointsAndFleet.get(o1).getA(), netPointsAndFleet.get(o2).getA());
}
}
return comparisonResult;
@@ -365,6 +404,6 @@ public abstract class AbstractLeaderboardImpl implements Leaderboard {
}
protected Comparator<? super Competitor> getTotalRankComparator(TimePoint timePoint) {
return new LeaderboardTotalRankComparator(this, timePoint);
return new LeaderboardTotalRankComparator(this, timePoint, scoreComparator);
}
}
@@ -3,6 +3,7 @@ package com.sap.sailing.domain.leaderboard.impl;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.logging.Logger;
@@ -31,8 +32,8 @@ public class FlexibleLeaderboardImpl extends AbstractLeaderboardImpl implements
private String name;
public FlexibleLeaderboardImpl(String name, SettableScoreCorrection scoreCorrection,
ThresholdBasedResultDiscardingRule resultDiscardingRule) {
super(scoreCorrection, resultDiscardingRule);
ThresholdBasedResultDiscardingRule resultDiscardingRule, Comparator<Integer> scoreComparator) {
super(scoreCorrection, resultDiscardingRule, scoreComparator);
if (name == null) {
throw new IllegalArgumentException("A leaderboard's name must not be null");
}
@@ -46,11 +46,13 @@ import com.sap.sailing.domain.leaderboard.Leaderboard;
public class LeaderboardTotalRankComparator implements Comparator<Competitor> {
private final Leaderboard leaderboard;
private final TimePoint timePoint;
private final Comparator<Integer> scoreComparator;
public LeaderboardTotalRankComparator(Leaderboard leaderboard, TimePoint timePoint) {
public LeaderboardTotalRankComparator(Leaderboard leaderboard, TimePoint timePoint, Comparator<Integer> scoreComparator) {
super();
this.leaderboard = leaderboard;
this.timePoint = timePoint;
this.scoreComparator = scoreComparator;
}
protected Leaderboard getLeaderboard() {
@@ -202,19 +204,14 @@ public class LeaderboardTotalRankComparator implements Comparator<Competitor> {
* the integer numbers by their natural ordering.
*/
protected Comparator<Integer> getScoreComparator() {
return new Comparator<Integer>() {
@Override
public int compare(Integer o1, Integer o2) {
return o1-o2;
}
};
return scoreComparator;
}
/**
* This implementation ranks a competitor better (lesser) if it has the lower score sum
*/
protected int compareByScoreSum(int o1ScoreSum, int o2ScoreSum) {
return o1ScoreSum - o2ScoreSum;
return getScoreComparator().compare(o1ScoreSum, o2ScoreSum);
}
/**
@@ -0,0 +1,20 @@
package com.sap.sailing.domain.leaderboard.impl;
import java.io.Serializable;
import java.util.Comparator;
/**
* The score comparator as used by the ISAF standard scoring scheme. Lower scores are better.
*
* @author Axel Uhl (D043530)
*
*/
public class LowerScoreIsBetter implements Comparator<Integer>, Serializable {
private static final long serialVersionUID = -2767385186133743330L;
@Override
public int compare(Integer o1, Integer o2) {
return o1-o2;
}
}
@@ -1,5 +1,9 @@
package com.sap.sailing.domain.leaderboard.impl;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import com.sap.sailing.domain.base.Fleet;
import com.sap.sailing.domain.base.impl.AbstractRaceColumn;
import com.sap.sailing.domain.leaderboard.FlexibleRaceColumn;
@@ -17,7 +21,12 @@ public class RaceColumnImpl extends AbstractRaceColumn implements FlexibleRaceCo
public RaceColumnImpl(String name, boolean medalRace, Iterable<Fleet> fleets) {
super(name);
this.medalRace = medalRace;
this.fleets = fleets;
List<Fleet> myFleets = new ArrayList<Fleet>();
for (Fleet fleet : fleets) {
myFleets.add(fleet);
}
Collections.sort(myFleets);
this.fleets = myFleets;
}
@Override
@@ -1,6 +1,7 @@
package com.sap.sailing.domain.leaderboard.impl;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import com.sap.sailing.domain.base.Fleet;
@@ -22,8 +23,9 @@ public class RegattaLeaderboardImpl extends AbstractLeaderboardImpl {
private static final long serialVersionUID = 2370461218294770084L;
private final Regatta regatta;
public RegattaLeaderboardImpl(Regatta regatta, SettableScoreCorrection scoreCorrection, ThresholdBasedResultDiscardingRule resultDiscardingRule) {
super(scoreCorrection, resultDiscardingRule);
public RegattaLeaderboardImpl(Regatta regatta, SettableScoreCorrection scoreCorrection,
ThresholdBasedResultDiscardingRule resultDiscardingRule, Comparator<Integer> scoreComparator) {
super(scoreCorrection, resultDiscardingRule, scoreComparator);
this.regatta = regatta;
}
@@ -391,4 +391,10 @@ public interface TrackedRace extends Serializable {
WindStore getWindStore();
Competitor getOverallLeader(TimePoint timePoint) throws NoWindException;
/**
* Returns the competitors of this tracked race, according to their ranking. Competitors whose {@link #getRank(Competitor)} is 0 will
* be sorted "worst".
*/
List<Competitor> getCompetitorsFromBestToWorst(TimePoint timePoint);
}
@@ -104,6 +104,7 @@ public class TrackedLegImpl implements TrackedLeg, RaceChangeListener {
}
// ensure that race isn't updated by events as we're tying to sort the competitors
synchronized (getTrackedRace()) {
// TODO See bug 469; competitors already disqualified may need to be ranked worst
Collections.sort(rankedCompetitorList, new WindwardToGoComparator(this, timePoint));
rankedCompetitorList = Collections.unmodifiableList(rankedCompetitorList);
synchronized (competitorTracksOrderedByRank) {
@@ -610,7 +610,7 @@ public abstract class TrackedRaceImpl implements TrackedRace, CourseListener {
public synchronized Competitor getOverallLeader(TimePoint timePoint) throws NoWindException {
try {
Competitor result = null;
List<Competitor> ranks = getRanks(timePoint);
List<Competitor> ranks = getCompetitorsFromBestToWorst(timePoint);
if (ranks != null && !ranks.isEmpty()) {
result = ranks.iterator().next();
}
@@ -623,13 +623,20 @@ public abstract class TrackedRaceImpl implements TrackedRace, CourseListener {
@Override
public synchronized int getRank(Competitor competitor, TimePoint timePoint) throws NoWindException {
try {
return getRanks(timePoint).indexOf(competitor) + 1;
int result;
if (getMarkPassings(competitor).isEmpty()) {
result = 0;
} else {
result = getCompetitorsFromBestToWorst(timePoint).indexOf(competitor) + 1;
}
return result;
} catch (NoWindError e) {
throw e.getCause();
}
}
private List<Competitor> getRanks(TimePoint timePoint) {
@Override
public List<Competitor> getCompetitorsFromBestToWorst(TimePoint timePoint) {
synchronized (competitorRankings) {
List<Competitor> rankedCompetitors = competitorRankings.get(timePoint);
if (rankedCompetitors == null) {
@@ -44,7 +44,7 @@
<property name="expedition.udp.port" value="2010" />
<property name="mongo.port" value="10200" />
<property name="osgi.noShutdown" value="true" />
<property name="replication.brokerURL" value="tcp://localhost:61616" />
<property name="replication.brokerURL" value="tcp://0.0.0.0:61616" />
<property name="replication.persistenceDir" value="." />
<property name="replication.useJMX" value="false" />
</configurations>
@@ -194,7 +194,9 @@ public class ReverseGeocoderImpl implements ReverseGeocoder {
private void cachePlacemarks(Position position, Double radius, List<Placemark> placemarks) {
Collections.sort(placemarks, new Placemark.ByDistance(position));
if (position != null) {
cache.put(position, new Triple<Position, Double, List<Placemark>>(position, radius, placemarks));
synchronized (cache) {
cache.put(position, new Triple<Position, Double, List<Placemark>>(position, radius, placemarks));
}
}
}
@@ -211,7 +213,9 @@ public class ReverseGeocoderImpl implements ReverseGeocoder {
*/
private void updateCachedPlacemarks(Position cachedPoint, Double newRadius, List<Placemark> newPlacemarks) {
if (cachedPoint != null) {
cache.replace(cachedPoint, new Triple<Position, Double, List<Placemark>>(cachedPoint, newRadius, newPlacemarks));
synchronized (cache) {
cache.replace(cachedPoint, new Triple<Position, Double, List<Placemark>>(cachedPoint, newRadius, newPlacemarks));
}
}
}
@@ -223,7 +227,9 @@ public class ReverseGeocoderImpl implements ReverseGeocoder {
* {@link ReverseGeocoderImpl#POSITION_CACHE_DISTANCE_LIMIT the distance limit}
*/
private Triple<Position, Double, List<Placemark>> checkCache(Position position) {
return cache.get(position, POSITION_CACHE_DISTANCE_LIMIT);
synchronized (cache) {
return cache.get(position, POSITION_CACHE_DISTANCE_LIMIT);
}
}
private JSONArray callNearestService(Position position) throws MalformedURLException, IOException, ParseException {
+19 -11
View File
@@ -143,15 +143,23 @@
color: #fff;
}
.titleLabel {
.titleLabelWrapper {
position: absolute;
width: 400px;
text-align: right;
font-family: 'UbuntuMedium', Arial, Verdana, sans-serif;
font-size: 16px;
color: #fff;
right: 5px;
top: 41px;
min-width: 400px;
text-align: right;
height: 68px;
right: 0;
top: 0;
font-family: 'UbuntuMedium', Arial, Verdana, sans-serif;
font-size: 16px;
color: #fff;
//background: url(images/titleLabelWrapper.png) right center no-repeat;
}
.titleLabel {
background: url(images/titleLabelInner.png) left center no-repeat;
height: 26px;
padding: 41px 7px 0 130px;
}
@@ -297,9 +305,9 @@
position: fixed;
width: 100%;
top: 0;
background-image: url(images/header_bg_modern_eventname.png), url(images/white_gradient_header.png), url(images/header_bg_modern.png);
background-position: right top, center top, 0 0;
background-repeat: no-repeat, no-repeat, repeat-x;
background-image: url(images/white_gradient_header.png), url(images/header_bg_modern.png);
background-position: center top, 0 0;
background-repeat: no-repeat, repeat-x;
box-shadow: 0 0 20px #858585;
-moz-box-shadow: 0 0 20px #858585;
-webkit-box-shadow: 0 0 20px #858585;
+78 -25
View File
@@ -111,7 +111,45 @@ input.opencoloumn {
right:0;
}
.globalNavigation-home {
.globalNavigation-home {
border-radius: 0px 0px 4px 4px;
-moz-border-radius: 0px 0px 4px 4px;
-webkit-border-radius: 0px 0px 4px 4px;
margin: 0 10px 0 0;
float: left;
}
.globalNavigation-home a{
color: #fff;
text-decoration: none;
display: block;
background: url(images/globalNavigation-home_bg.png) 5px center no-repeat #7c7b7c;
padding: 5px 6px 5px 25px;
border-radius: 0px 0px 4px 4px;
-moz-border-radius: 0px 0px 4px 4px;
-webkit-border-radius: 0px 0px 4px 4px;
}
.globalNavigation-leaderBoard {
border-radius: 0px 0px 4px 4px;
-moz-border-radius: 0px 0px 4px 4px;
-webkit-border-radius: 0px 0px 4px 4px;
margin: 0 5px 0 0;
float: left;
}
.globalNavigation-leaderBoard a {
color: #fff;
text-decoration: none;
display: block;
background: url(images/globalNavigation-leaderBoard_bg.png) 5px center no-repeat #7c7b7c;
border-radius: 0px 0px 4px 4px;
-moz-border-radius: 0px 0px 4px 4px;
-webkit-border-radius: 0px 0px 4px 4px;
padding: 5px 6px 5px 25px;
}
.globalNavigation-leaderBoardGroup {
background: url(images/globalNavigation-home_bg.png) 5px center no-repeat #7c7b7c;
border-radius: 0px 0px 4px 4px;
-moz-border-radius: 0px 0px 4px 4px;
@@ -121,33 +159,14 @@ input.opencoloumn {
float: left;
}
.globalNavigation-home a{
color: #fff;
text-decoration: none;
}
.globalNavigation-leaderBoard {
background: url(images/globalNavigation-leaderBoard_bg.png) 5px center no-repeat #7c7b7c;
border-radius: 0px 0px 4px 4px;
-moz-border-radius: 0px 0px 4px 4px;
-webkit-border-radius: 0px 0px 4px 4px;
padding: 5px 6px 5px 25px;
margin: 0 10px 0 0;
float: left;
}
.globalNavigation-leaderBoard a {
color: #fff;
text-decoration: none;
}
.globalNavigation-leaderBoardGroup {
background-color: gray;
.globalNavigation-leaderBoardGroup a {
color: #fff;
text-decoration: none;
}
.raceBoardNavigation {
float: left;
margin: 3px;;
margin: 9px 0 0 7px;
font-family: 'UbuntuLight', Arial, Verdana, sans-serif;
}
@@ -196,6 +215,40 @@ input.opencoloumn {
.raceBoardNavigation-settingsButtonPanel {
float: right;
margin: 3px;;
margin: 9px 12px 0 0;
}
.raceBoardNavigation-settingsButton {
background: url(images/settings_white.png), url(images/btn-cta-orangeleft.png);
background-position: center, center 0;
background-repeat: no-repeat, repeat-x;
width: 27px;
height: 23px;
margin: 0 5px 0 1px;
-webkit-border-radius: 0px 3px 3px 0px;
border-radius: 0px 3px 3px 0px;
}
.raceBoardNavigation-settingsButton:hover {
background-image: url(images/settings_white.png), url(images/btn-cta-orangeleft.png);
background-position: center, center -30px;
background-repeat: no-repeat, repeat-x;
cursor: pointer;
}
.raceBoardNavigation-innerElement {
background: url("images/btn-cta-orangeleft.png") repeat-x scroll center 0 transparent;
border-bottom-left-radius: 3px;
border-top-left-radius: 3px;
color: #FFFFFF;
cursor: pointer;
font-family: UbuntuBold,Verdana,Arial,sans-serif;
font-size: 14px;
margin: 0 0 0 0;
padding: 2px 7px 2px 3px;
height: 19px;
}
.raceBoardNavigation-innerElement:hover {
background: url("images/btn-cta-orangeleft.png") repeat-x scroll center -30px transparent;
cursor: pointer;
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 743 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.0 KiB

@@ -22,9 +22,13 @@ public class LogoAndTitlePanel extends FlowPanel {
sailingAnalyticsLabel.addStyleName("sailingAnalyticsLabel boldLabel");
this.add(labelPanel);
FlowPanel titleLabelWrapper = new FlowPanel();
titleLabelWrapper.addStyleName("titleLabelWrapper");
titleLabel = new Label(title);
titleLabel.addStyleName("titleLabel");
this.add(titleLabel);
titleLabelWrapper.add(titleLabel);
this.add(titleLabelWrapper);
}
}
@@ -45,9 +45,9 @@ import com.google.gwt.view.client.SelectionChangeEvent;
import com.google.gwt.view.client.SelectionChangeEvent.Handler;
import com.google.gwt.view.client.SelectionModel;
import com.sap.sailing.domain.common.DetailType;
import com.sap.sailing.domain.common.RegattaAndRaceIdentifier;
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.gwt.ui.actions.AsyncActionsExecutor;
import com.sap.sailing.gwt.ui.actions.GetLeaderboardByNameAction;
import com.sap.sailing.gwt.ui.client.Collator;
@@ -63,7 +63,6 @@ import com.sap.sailing.gwt.ui.client.Timer.PlayModes;
import com.sap.sailing.gwt.ui.client.Timer.PlayStates;
import com.sap.sailing.gwt.ui.client.UserAgentChecker.UserAgentTypes;
import com.sap.sailing.gwt.ui.leaderboard.LegDetailColumn.LegDetailField;
import com.sap.sailing.gwt.ui.leaderboard.NetPointsComparator.SortOrderCalculator;
import com.sap.sailing.gwt.ui.shared.CompetitorDTO;
import com.sap.sailing.gwt.ui.shared.LeaderboardDTO;
import com.sap.sailing.gwt.ui.shared.LeaderboardEntryDTO;
@@ -478,17 +477,18 @@ public class LeaderboardPanel extends FormPanel implements TimeListener, PlaySta
@Override
public Comparator<LeaderboardRowDTO> getComparator() {
if (race.isMedalRace()) {
return getLeaderboard().getMedalRaceComparator(race.getRaceColumnName());
} else {
SortOrderCalculator sortOrderCalculator = new SortOrderCalculator() {
@Override
public boolean isAscending() {
return isSortedAscendingForThisColumn(getLeaderboardPanel().getLeaderboardTable());
}
};
return new NetPointsComparator(sortOrderCalculator, race.getRaceColumnName());
}
return new Comparator<LeaderboardRowDTO>() {
@Override
public int compare(LeaderboardRowDTO o1, LeaderboardRowDTO o2) {
List<CompetitorDTO> competitorsFromBestToWorst = getLeaderboard().getCompetitorsFromBestToWorst(race);
boolean ascending = isSortedAscendingForThisColumn(getLeaderboardPanel().getLeaderboardTable());
int o1Rank = competitorsFromBestToWorst.indexOf(o1.competitor) + 1;
int o2Rank = competitorsFromBestToWorst.indexOf(o2.competitor) + 1;
return o1Rank == 0 ? o2Rank == 0 ? 0
: ascending ? 1 : -1 : o2Rank == 0 ? ascending ? -1 : 1
: o1Rank - o2Rank;
}
};
}
@Override
@@ -326,7 +326,7 @@ public class LegColumn extends ExpandableSortableColumn<String> {
@Override
public String getValue(LeaderboardRowDTO row) {
LegEntryDTO legEntry = getLegEntry(row);
if (legEntry != null) {
if (legEntry != null && legEntry.rank != 0) {
return ""+legEntry.rank;
} else {
return "";
@@ -1,35 +0,0 @@
package com.sap.sailing.gwt.ui.leaderboard;
import java.util.Comparator;
import com.sap.sailing.gwt.ui.shared.LeaderboardEntryDTO;
import com.sap.sailing.gwt.ui.shared.LeaderboardRowDTO;
public class NetPointsComparator implements Comparator<LeaderboardRowDTO> {
private final SortOrderCalculator sortOrderCalculator;
private final String raceName;
public interface SortOrderCalculator {
boolean isAscending();
}
public NetPointsComparator(SortOrderCalculator sortOrderCalculator, String raceName) {
super();
this.sortOrderCalculator = sortOrderCalculator;
this.raceName = raceName;
}
/**
* sorts a meaningless <code>0</code> value to the bottom always, regardless whether ascending/descending sorting is
* requested
*/
@Override
public int compare(LeaderboardRowDTO o1, LeaderboardRowDTO o2) {
boolean ascending = sortOrderCalculator.isAscending();
LeaderboardEntryDTO o1Entry = o1.fieldsByRaceName.get(raceName);
LeaderboardEntryDTO o2Entry = o2.fieldsByRaceName.get(raceName);
return (o1Entry == null || o1Entry.netPoints == 0) ? (o2Entry == null || o2Entry.netPoints == 0) ? 0
: ascending ? 1 : -1 : (o2Entry == null || o2Entry.netPoints == 0) ? ascending ? -1 : 1
: o1Entry.netPoints - o2Entry.netPoints;
}
}
@@ -34,12 +34,12 @@ public class GlobalNavigationPanel extends FlowPanel {
String homeLink = spectatorViewLink;
if(showHomeNavigation) {
addNavigationLink(stringMessages.home(), homeLink, "home");
}
if (leaderboardGroupName != null && !leaderboardGroupName.isEmpty()) {
String leaderBoardGroupLink = spectatorViewLink + "?leaderboardGroupName=" + leaderboardGroupName;
addNavigationLink(leaderboardGroupName, leaderBoardGroupLink, "leaderBoardGroup");
if (leaderboardGroupName != null && !leaderboardGroupName.isEmpty()) {
String leaderBoardGroupLink = spectatorViewLink + "?leaderboardGroupName=" + leaderboardGroupName;
addNavigationLink(leaderboardGroupName, leaderBoardGroupLink, "leaderBoardGroup", "Go to the Event overview.");
} else {
addNavigationLink(stringMessages.home(), homeLink, "home", "Go to the Event overview.");
}
}
if (leaderboardName != null && !leaderboardName.isEmpty()) {
@@ -47,11 +47,12 @@ public class GlobalNavigationPanel extends FlowPanel {
if (leaderboardGroupName != null && !leaderboardGroupName.isEmpty()) {
leaderBoardLink += "&leaderboardGroupName=" + leaderboardGroupName;
}
addNavigationLink(leaderboardName, leaderBoardLink, "leaderBoard");
addNavigationLink(leaderboardName, leaderBoardLink, "leaderBoard", "Go to the overview and see all Races in one Leaderboard");
}
}
private void addNavigationLink(String linkName, String linkUrl, String styleNameExtension) {
private void addNavigationLink(String linkName, String linkUrl, String styleNameExtension, String htmlTitle) {
String setHtmlTitle = htmlTitle;
String url = linkUrl;
if(debugParam != null && !debugParam.isEmpty()) {
url += url.contains("?") ? "&" : "?";
@@ -60,6 +61,7 @@ public class GlobalNavigationPanel extends FlowPanel {
HTML linkHtml = new HTML(ANCHORTEMPLATE.anchor(URLFactory.INSTANCE.encode(url), linkName));
linkHtml.addStyleName(STYLE_NAME_PREFIX + styleNameExtension);
linkHtml.setTitle(setHtmlTitle);
add(linkHtml);
}
}
@@ -183,9 +183,7 @@ public class RaceBoardEntryPoint extends AbstractEntryPoint {
FlowPanel toolbarPanel = new FlowPanel();
//TODO Quickfix for touch devices
toolbarPanel.add(raceBoardPanel.getNavigationWidget());
toolbarPanel.add(raceBoardPanel.getSettingsWidget());
FlowPanel logoAndTitlePanel = createLogoAndTitlePanel(raceBoardPanel);
FlowPanel timePanel = createTimePanel(raceBoardPanel);
@@ -17,7 +17,6 @@ import com.google.gwt.user.client.ui.Button;
import com.google.gwt.user.client.ui.CheckBox;
import com.google.gwt.user.client.ui.FlowPanel;
import com.google.gwt.user.client.ui.FormPanel;
import com.google.gwt.user.client.ui.Label;
import com.google.gwt.user.client.ui.MenuBar;
import com.google.gwt.user.client.ui.ToggleButton;
import com.google.gwt.user.client.ui.Widget;
@@ -175,23 +174,10 @@ public class RaceBoardPanel extends FormPanel implements RegattaDisplayer, RaceS
mainPanel.add(componentViewer.getViewerWidget());
}
settingsPanel = new FlowPanel();
settingsPanel.addStyleName("raceBoardNavigation-settingsButtonPanel");
Label settingsLabel = new Label("Settings: ");
settingsLabel.addStyleName("raceBoardNavigation-settingsLabel");
settingsLabel.getElement().getStyle().setFloat(Style.Float.LEFT);
settingsLabel.getElement().getStyle().setPadding(3, Style.Unit.PX);
settingsPanel.add(settingsLabel);
addSettingsMenuButton(settingsPanel, leaderboardPanel);
addSettingsMenuButton(settingsPanel, raceMap);
addSettingsMenuButton(settingsPanel, windChart);
addSettingsMenuButton(settingsPanel, competitorChart);
addComponentAsCheckboxToNavigationMenu(leaderboardAndMapViewer, leaderboardPanel);
addComponentAsCheckboxToNavigationMenu(leaderboardAndMapViewer, windChart);
addComponentAsCheckboxToNavigationMenu(leaderboardAndMapViewer, competitorChart);
addComponentToNavigationMenu(leaderboardAndMapViewer, leaderboardPanel, true);
addComponentToNavigationMenu(leaderboardAndMapViewer, windChart, true);
addComponentToNavigationMenu(leaderboardAndMapViewer, competitorChart, true);
addComponentToNavigationMenu(leaderboardAndMapViewer, raceMap, false);
}
@SuppressWarnings("unused")
@@ -205,23 +191,6 @@ public class RaceBoardPanel extends FormPanel implements RegattaDisplayer, RaceS
}
}
private <SettingsType> void addSettingsMenuButton(FlowPanel settingsPanel, final Component<SettingsType> component) {
if(component.hasSettings()) {
Button settingsButton = new Button(component.getLocalizedShortName());
settingsButton.addClickHandler(new ClickHandler() {
@Override
public void onClick(ClickEvent event) {
new SettingsDialog<SettingsType>(component, stringMessages).show();
}
});
settingsButton.addStyleName("raceBoardNavigation-settingsButton");
settingsButton.getElement().getStyle().setFloat(Style.Float.LEFT);
settingsButton.getElement().getStyle().setPadding(3, Style.Unit.PX);
settingsPanel.add(settingsButton);
}
}
private LeaderboardPanel createLeaderboardPanel(String leaderboardName, String leaderboardGroupName) {
LeaderboardSettings leaderBoardSettings = LeaderboardSettingsFactory.getInstance()
.createNewSettingsForPlayMode(timer.getPlayMode(), /* nameOfRaceToSort */
@@ -232,13 +201,15 @@ public class RaceBoardPanel extends FormPanel implements RegattaDisplayer, RaceS
userAgentType);
}
private void addComponentAsCheckboxToNavigationMenu(final ComponentViewer componentViewer,
final Component<?> component) {
private <SettingsType> void addComponentToNavigationMenu(final ComponentViewer componentViewer,
final Component<SettingsType> component, boolean withCheckbox) {
final CheckBox checkBox= new CheckBox(component.getLocalizedShortName());
checkBox.getElement().getStyle().setFloat(Style.Float.LEFT);
checkBox.setEnabled(withCheckbox);
checkBox.setValue(component.isVisible());
checkBox.setTitle(stringMessages.showHideComponent(component.getLocalizedShortName()));
checkBox.addStyleName("raceBoardNavigation-innerElement");
checkBox.addValueChangeHandler(new ValueChangeHandler<Boolean>() {
@Override
@@ -259,6 +230,22 @@ public class RaceBoardPanel extends FormPanel implements RegattaDisplayer, RaceS
});
componentsNavigationPanel.add(checkBox);
if(component.hasSettings()) {
Button settingsButton = new Button("");
settingsButton.addClickHandler(new ClickHandler() {
@Override
public void onClick(ClickEvent event) {
new SettingsDialog<SettingsType>(component, stringMessages).show();
}
});
settingsButton.addStyleName("raceBoardNavigation-settingsButton");
settingsButton.getElement().getStyle().setFloat(Style.Float.LEFT);
settingsButton.setTitle(stringMessages.settingsForComponent(component.getLocalizedShortName()));
componentsNavigationPanel.add(settingsButton);
}
}
public void addComponentAsToogleButtonToNavigationMenu(final ComponentViewer componentViewer,
@@ -19,6 +19,7 @@ import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.WeakHashMap;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Executor;
@@ -214,8 +215,11 @@ public class SailingServiceImpl extends RemoteServiceServlet implements SailingS
private final Executor executor;
private final WeakHashMap<Competitor, CompetitorDTO> weakCompetitorDTOCache;
public SailingServiceImpl() {
BundleContext context = Activator.getDefault();
weakCompetitorDTOCache = new WeakHashMap<Competitor, CompetitorDTO>();
racingEventServiceTracker = createAndOpenRacingEventServiceTracker(context);
replicationServiceTracker = createAndOpenReplicationServiceTracker(context);
mongoObjectFactory = MongoFactory.INSTANCE.getDefaultMongoObjectFactory();
@@ -258,7 +262,7 @@ public class SailingServiceImpl extends RemoteServiceServlet implements SailingS
result.name = leaderboard.getName();
result.competitorDisplayNames = new HashMap<CompetitorDTO, String>();
for (RaceColumn raceColumn : leaderboard.getRaceColumns()) {
result.createEmptyRaceColumn(raceColumn.getName(), raceColumn.isMedalRace());
RaceColumnDTO raceColumnDTO = result.createEmptyRaceColumn(raceColumn.getName(), raceColumn.isMedalRace());
for (Fleet fleet : raceColumn.getFleets()) {
RegattaAndRaceIdentifier raceIdentifier = null;
TrackedRace trackedRace = raceColumn.getTrackedRace(fleet);
@@ -269,6 +273,7 @@ public class SailingServiceImpl extends RemoteServiceServlet implements SailingS
result.addRace(raceColumn.getName(), fleet.getName(), raceColumn.isMedalRace(),
raceIdentifier, /* StrippedRaceDTO */ null);
}
result.setCompetitorsFromBestToWorst(raceColumnDTO, getCompetitorDTOList(leaderboard.getCompetitorsFromBestToWorst(raceColumn, timePoint)));
}
result.rows = new HashMap<CompetitorDTO, LeaderboardRowDTO>();
result.hasCarriedPoints = leaderboard.hasCarriedPoints();
@@ -285,15 +290,15 @@ public class SailingServiceImpl extends RemoteServiceServlet implements SailingS
final Entry entry = leaderboard.getEntry(competitor, raceColumn, timePoint);
RunnableFuture<LeaderboardEntryDTO> future = new FutureTask<LeaderboardEntryDTO>(new Callable<LeaderboardEntryDTO>() {
@Override
public LeaderboardEntryDTO call() {
try {
return getLeaderboardEntryDTO(entry, raceColumn.getTrackedRace(competitor), competitor, timePoint,
namesOfRaceColumnsForWhichToLoadLegDetails != null
&& namesOfRaceColumnsForWhichToLoadLegDetails.contains(raceColumn.getName()));
} catch (NoWindException e) {
throw new NoWindError(e);
}
}
public LeaderboardEntryDTO call() {
try {
return getLeaderboardEntryDTO(entry, raceColumn.getTrackedRace(competitor), competitor, timePoint,
namesOfRaceColumnsForWhichToLoadLegDetails != null
&& namesOfRaceColumnsForWhichToLoadLegDetails.contains(raceColumn.getName()));
} catch (NoWindException e) {
throw new NoWindError(e);
}
}
});
executor.execute(future);
futuresForColumnName.put(raceColumn.getName(), future);
@@ -319,6 +324,14 @@ public class SailingServiceImpl extends RemoteServiceServlet implements SailingS
return result;
}
private List<CompetitorDTO> getCompetitorDTOList(List<Competitor> competitorsFromBestToWorst) {
List<CompetitorDTO> result = new ArrayList<CompetitorDTO>();
for (Competitor competitor : competitorsFromBestToWorst) {
result.add(getCompetitorDTO(competitor));
}
return result;
}
@Override
public void stressTestLeaderboardByName(String leaderboardName, int times) throws Exception {
Leaderboard leaderboard = getService().getLeaderboardByName(leaderboardName);
@@ -474,12 +487,17 @@ public class SailingServiceImpl extends RemoteServiceServlet implements SailingS
}
private CompetitorDTO getCompetitorDTO(Competitor c) {
CountryCode countryCode = c.getTeam().getNationality().getCountryCode();
CompetitorDTO competitorDTO = new CompetitorDTO(c.getName(), countryCode == null ? ""
: countryCode.getTwoLetterISOCode(), countryCode == null ? "" : countryCode.getThreeLetterIOCCode(),
countryCode == null ? "" : countryCode.getName(), c.getBoat().getSailID(), c.getId().toString(),
new BoatClassDTO(c.getBoat().getBoatClass().getName(), c.getBoat().getBoatClass().getHullLength()
.getMeters()));
CompetitorDTO competitorDTO = weakCompetitorDTOCache.get(c);
if (competitorDTO == null) {
CountryCode countryCode = c.getTeam().getNationality().getCountryCode();
competitorDTO = new CompetitorDTO(c.getName(), countryCode == null ? ""
: countryCode.getTwoLetterISOCode(),
countryCode == null ? "" : countryCode.getThreeLetterIOCCode(), countryCode == null ? ""
: countryCode.getName(), c.getBoat().getSailID(), c.getId().toString(),
new BoatClassDTO(c.getBoat().getBoatClass().getName(), c.getBoat().getBoatClass().getHullLength()
.getMeters()));
weakCompetitorDTOCache.put(c, competitorDTO);
}
return competitorDTO;
}
@@ -2,7 +2,6 @@ package com.sap.sailing.gwt.ui.shared;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
import java.util.Date;
import java.util.List;
import java.util.Map;
@@ -32,10 +31,6 @@ public abstract class AbstractLeaderboardDTO implements IsSerializable {
}
}
public Comparator<LeaderboardRowDTO> getMedalRaceComparator(String medalRaceName) {
return new MedalRaceComparator(medalRaceName);
}
/**
* If the race whose name is specified in <code>raceName</code> has any competitor who has valid
* {@link LeaderboardEntryDTO#legDetails} for that race, the number of entries in the leg details is returned,
@@ -72,39 +67,6 @@ public abstract class AbstractLeaderboardDTO implements IsSerializable {
return totalPoints;
}
private class MedalRaceComparator implements Comparator<LeaderboardRowDTO> {
private final String medalRaceName;
public MedalRaceComparator(String medalRaceName) {
this.medalRaceName = medalRaceName;
}
@Override
public int compare(LeaderboardRowDTO o1, LeaderboardRowDTO o2) {
int result;
if (scoredInMedalRace(o1.competitor)) {
if (scoredInMedalRace(o2.competitor)) {
// both scored in medal race
result = o1.fieldsByRaceName.get(medalRaceName).netPoints
- o2.fieldsByRaceName.get(medalRaceName).netPoints;
} else {
// only o1 scored in medal race, so o1 scores better = "less"
result = -1;
}
} else {
if (scoredInMedalRace(o2.competitor)) {
// only o2 scored in medal race, so o2 scores better, o1 scores worse = "greater"
result = 1;
} else {
// neither one scored in any medal race; to be considered equal for medal race comparison
result = 0;
}
}
return result;
}
}
public int getNetPoints(CompetitorDTO competitor, String nameOfLastRaceSoFar) {
int result = 0;
LeaderboardRowDTO row = rows.get(competitor);
@@ -186,11 +148,12 @@ public abstract class AbstractLeaderboardDTO implements IsSerializable {
races.add(index, raceInLeaderboardDTO);
}
public void createEmptyRaceColumn(String raceColumnName, boolean medalRace) {
RaceColumnDTO raceInLeaderboardDTO = new RaceColumnDTO();
raceInLeaderboardDTO.setRaceColumnName(raceColumnName);
raceInLeaderboardDTO.setMedalRace(medalRace);
races.add(raceInLeaderboardDTO);
public RaceColumnDTO createEmptyRaceColumn(String raceColumnName, boolean medalRace) {
RaceColumnDTO raceColumn = new RaceColumnDTO();
raceColumn.setRaceColumnName(raceColumnName);
raceColumn.setMedalRace(medalRace);
races.add(raceColumn);
return raceColumn;
}
protected RaceColumnDTO getRaceInLeaderboardByName(String raceColumnName) {
@@ -1,6 +1,8 @@
package com.sap.sailing.gwt.ui.shared;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import com.google.gwt.user.client.rpc.IsSerializable;
@@ -17,8 +19,20 @@ public class LeaderboardDTO extends AbstractLeaderboardDTO implements IsSerializ
* The competitor list, ordered ascending by total rank
*/
public List<CompetitorDTO> competitors;
private Map<RaceColumnDTO, List<CompetitorDTO>> competitorOrderingPerRace;
public LeaderboardDTO() {}
public LeaderboardDTO() {
competitorOrderingPerRace = new HashMap<RaceColumnDTO, List<CompetitorDTO>>();
}
public void setCompetitorsFromBestToWorst(RaceColumnDTO raceColumn, List<CompetitorDTO> orderedCompetitors) {
competitorOrderingPerRace.put(raceColumn, orderedCompetitors);
}
public List<CompetitorDTO> getCompetitorsFromBestToWorst(RaceColumnDTO raceColumn) {
return competitorOrderingPerRace.get(raceColumn);
}
public int getRank(CompetitorDTO competitor) {
return competitors.indexOf(competitor) + 1;
@@ -13,7 +13,7 @@ import com.google.gwt.user.client.rpc.IsSerializable;
public class LegEntryDTO implements IsSerializable {
public Double distanceTraveledInMeters;
public Double averageSpeedOverGroundInKnots;
public Integer rank;
public int rank;
public Double gapToLeaderInSeconds;
public Double estimatedTimeToNextWaypointInSeconds;
@@ -57,7 +57,7 @@ public class LegEntryDTO implements IsSerializable {
result = prime * result + ((numberOfJibes == null) ? 0 : numberOfJibes.hashCode());
result = prime * result + ((numberOfPenaltyCircles == null) ? 0 : numberOfPenaltyCircles.hashCode());
result = prime * result + ((numberOfTacks == null) ? 0 : numberOfTacks.hashCode());
result = prime * result + ((rank == null) ? 0 : rank.hashCode());
result = prime * result + rank;
result = prime * result + (started ? 1231 : 1237);
result = prime * result + (int) (timeInMilliseconds ^ (timeInMilliseconds >>> 32));
result = prime * result + ((velocityMadeGoodInKnots == null) ? 0 : velocityMadeGoodInKnots.hashCode());
@@ -116,10 +116,7 @@ public class LegEntryDTO implements IsSerializable {
return false;
} else if (!numberOfTacks.equals(other.numberOfTacks))
return false;
if (rank == null) {
if (other.rank != null)
return false;
} else if (!rank.equals(other.rank))
if (rank != other.rank)
return false;
if (started != other.started)
return false;
@@ -79,6 +79,12 @@ implements CompetitorSelectionChangeListener, RequiresResize {
private long stepSize = 5000;
private DetailType dataToShow;
private final CompetitorSelectionProvider competitorSelectionProvider;
/**
* When the chart is not visible and the competitor selection changes, no loading is performed. However, in this case
* we need to remember that loading will be necessary as soon as the chart becomes visible.
*/
private boolean needToLoadWhenMadeVisible;
public AbstractChartPanel(SailingServiceAsync sailingService, AsyncActionsExecutor asyncActionsExecutor,
CompetitorSelectionProvider competitorSelectionProvider, RaceSelectionProvider raceSelectionProvider,
@@ -104,6 +110,14 @@ implements CompetitorSelectionChangeListener, RequiresResize {
timer.addTimeListener(this);
timeZoomProvider.addTimeZoomChangeListener(this);
}
@Override
public void setVisible(boolean visible) {
super.setVisible(visible);
if (needToLoadWhenMadeVisible) {
loadData(/* showBusyIndicator */ true);
}
}
/**
* Creates a new chart for the given {@link DetailType} <code>dataToShow</code> and also
@@ -120,7 +134,6 @@ implements CompetitorSelectionChangeListener, RequiresResize {
.setMarginRight(65)
.setBorderColor(new Color("#A6A6A6"))
.setBorderWidth(1)
// .setBackgroundColor(new Color("#C6C6C6"))
.setChartSubtitle(new ChartSubtitle().setText(stringMessages.clickAndDragToZoomIn()))
.setLinePlotOptions(new LinePlotOptions().setLineWidth(LINE_WIDTH).setMarker(new Marker().setEnabled(false).setHoverState(
new Marker().setEnabled(true).setRadius(4))).setShadow(false)
@@ -211,60 +224,70 @@ implements CompetitorSelectionChangeListener, RequiresResize {
* @param showBusyIndicator If <code>true</code> is the busy indicator shown while loading the data from the server.
*/
protected void loadData(boolean showBusyIndicator) {
if (needsDataLoading()) {
if (showBusyIndicator) {
setWidget(chart);
showLoading("Loading competitor data...");
}
if (chartData == null || chartData.getDetailType() != getDataToShow()) {
chartData = new MultiCompetitorRaceDataDTO(getDataToShow());
}
// Date toDate = new Date(System.currentTimeMillis() - timer.getLivePlayDelayInMillis());
final ArrayList<Pair<Date, CompetitorDTO>> dataQuery = new ArrayList<Pair<Date, CompetitorDTO>>();
for (CompetitorDTO competitor : getVisibleCompetitors()) {
Date chartDataDateOfNewestData = chartData.getDateOfNewestData();
Date competitorDateOfNewestData = chartData.contains(competitor) ? chartData.getCompetitorData(competitor).getDateOfNewestData() : null;
if (!chartData.contains(competitor)) {
dataQuery.add(new Pair<Date, CompetitorDTO>(new Date(0), competitor));
} else if (competitorDateOfNewestData.before(chartDataDateOfNewestData) || competitorDateOfNewestData.before(maxTimepoint)) {
dataQuery.add(new Pair<Date, CompetitorDTO>(new Date(competitorDateOfNewestData.getTime() + getStepSize()), competitor));
if (isVisible()) {
if (hasVisibleCompetitors()) {
needToLoadWhenMadeVisible = false; // we're loading it now
if (showBusyIndicator) {
setWidget(chart);
showLoading("Loading competitor data...");
}
if (chartData == null || chartData.getDetailType() != getDataToShow()) {
chartData = new MultiCompetitorRaceDataDTO(getDataToShow());
}
}
GetCompetitorsRaceDataAction getCompetitorsRaceDataAction = new GetCompetitorsRaceDataAction(sailingService,
selectedRaceIdentifier, dataQuery, maxTimepoint, getStepSize(), getDataToShow(),
new AsyncCallback<MultiCompetitorRaceDataDTO>() {
@Override
public void onFailure(Throwable caught) {
errorReporter.reportError(getStringMessages().failedToLoadRaceData() + ": " + caught.toString(),
// Date toDate = new Date(System.currentTimeMillis() - timer.getLivePlayDelayInMillis());
final ArrayList<Pair<Date, CompetitorDTO>> dataQuery = new ArrayList<Pair<Date, CompetitorDTO>>();
for (CompetitorDTO competitor : getVisibleCompetitors()) {
Date chartDataDateOfNewestData = chartData.getDateOfNewestData();
Date competitorDateOfNewestData = chartData.contains(competitor) ? chartData.getCompetitorData(
competitor).getDateOfNewestData() : null;
if (!chartData.contains(competitor)) {
dataQuery.add(new Pair<Date, CompetitorDTO>(new Date(0), competitor));
} else if (competitorDateOfNewestData.before(chartDataDateOfNewestData)
|| competitorDateOfNewestData.before(maxTimepoint)) {
dataQuery.add(new Pair<Date, CompetitorDTO>(new Date(competitorDateOfNewestData.getTime()
+ getStepSize()), competitor));
}
}
GetCompetitorsRaceDataAction getCompetitorsRaceDataAction = new GetCompetitorsRaceDataAction(
sailingService, selectedRaceIdentifier, dataQuery, maxTimepoint, getStepSize(),
getDataToShow(), new AsyncCallback<MultiCompetitorRaceDataDTO>() {
@Override
public void onFailure(Throwable caught) {
errorReporter.reportError(
getStringMessages().failedToLoadRaceData() + ": " + caught.toString(),
timer.getPlayMode() == PlayModes.Live);
hideLoading();
}
}
@Override
public void onSuccess(MultiCompetitorRaceDataDTO result) {
if (result != null) {
for (CompetitorRaceDataDTO competitorData : result.getAllRaceData()) {
if (chartData.contains(competitorData.getCompetitor())) {
chartData.addCompetitorRaceData(competitorData);
chartData.setCompetitorMarkPassingsData(competitorData);
} else {
chartData.setCompetitorData(competitorData.getCompetitor(), competitorData);
@Override
public void onSuccess(MultiCompetitorRaceDataDTO result) {
if (result != null) {
for (CompetitorRaceDataDTO competitorData : result.getAllRaceData()) {
if (chartData.contains(competitorData.getCompetitor())) {
chartData.addCompetitorRaceData(competitorData);
chartData.setCompetitorMarkPassingsData(competitorData);
} else {
chartData.setCompetitorData(competitorData.getCompetitor(), competitorData);
}
}
}
}
chart.getXAxis().setMin(minTimepoint.getTime());
chart.getXAxis().setMax(maxTimepoint.getTime());
chart.getXAxis().setMin(minTimepoint.getTime());
chart.getXAxis().setMax(maxTimepoint.getTime());
drawChartData();
chart.hideLoading();
}
});
asyncActionsExecutor.execute(getCompetitorsRaceDataAction);
drawChartData();
hideLoading();
}
});
asyncActionsExecutor.execute(getCompetitorsRaceDataAction);
} else {
setWidget(noCompetitorsSelectedLabel);
}
} else {
setWidget(noCompetitorsSelectedLabel);
// not visible; don't load data but remember that data needs to be loaded as soon as the chart becomes visible
needToLoadWhenMadeVisible = true;
}
}
@@ -570,10 +593,6 @@ implements CompetitorSelectionChangeListener, RequiresResize {
}
}
private boolean needsDataLoading() {
return hasVisibleCompetitors() && isVisible();
}
@Override
public void onResize() {
if(getChartData() != null) {
@@ -107,7 +107,7 @@ public abstract class RaceChart extends SimplePanel implements RaceTimesInfoProv
}
protected void hideLoading() {
if(timer.getPlayMode() != PlayModes.Live) {
if (timer.getPlayMode() != PlayModes.Live) {
chart.hideLoading();
}
isLoading = false;
@@ -134,14 +134,9 @@ public abstract class RaceChart extends SimplePanel implements RaceTimesInfoProv
}
protected boolean onClick(ChartClickEvent chartClickEvent) {
if(!isLoading && !isZoomed) {
// when the user zooms into the chart first a AxisSetExtremesEvent is sent and a ChartClickEvent afterwards
// if (ignoreClickOnce) {
// ignoreClickOnce = false;
// } else {
timer.setPlayMode(PlayModes.Replay);
timer.setTime(chartClickEvent.getXAxisValueAsLong());
// }
if (!isLoading && !isZoomed) {
timer.setPlayMode(PlayModes.Replay);
timer.setTime(chartClickEvent.getXAxisValueAsLong());
}
return true;
}
@@ -168,7 +163,7 @@ public abstract class RaceChart extends SimplePanel implements RaceTimesInfoProv
* visibility state.
*/
protected void useCheckboxesToShowAndHide(final Chart chart) {
chart.setLegend(new Legend().setEnabled(true).setBorderWidth(0).setSymbolPadding(20)); // make room for checkbox
chart.setLegend(new Legend().setEnabled(true).setBorderWidth(0).setSymbolPadding(25)); // make room for checkbox
chart.setSeriesPlotOptions(new SeriesPlotOptions().setSeriesCheckboxClickEventHandler(new SeriesCheckboxClickEventHandler() {
@Override
public boolean onClick(SeriesCheckboxClickEvent seriesCheckboxClickEvent) {
@@ -103,7 +103,7 @@ public class SliderBar extends FocusPanel implements RequiresResize, HasValue<Do
*
* @return a prototype of this image
*/
@Source("slider.png")
@Source("slider_blue.png")
ImageResource slider();
/**
@@ -111,7 +111,7 @@ public class SliderBar extends FocusPanel implements RequiresResize, HasValue<Do
*
* @return a prototype of this image
*/
@Source("slider.png")
@Source("slider_blue.png")
ImageResource sliderDisabled();
/**
@@ -119,7 +119,7 @@ public class SliderBar extends FocusPanel implements RequiresResize, HasValue<Do
*
* @return a prototype of this image
*/
@Source("slider.png")
@Source("slider_blue.png")
ImageResource sliderSliding();
@NotStrict
Binary file not shown.

Before

Width:  |  Height:  |  Size: 596 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 422 B

@@ -15,6 +15,7 @@ import com.sap.sailing.domain.leaderboard.Leaderboard;
import com.sap.sailing.domain.leaderboard.LeaderboardGroup;
import com.sap.sailing.domain.leaderboard.impl.FlexibleLeaderboardImpl;
import com.sap.sailing.domain.leaderboard.impl.LeaderboardGroupImpl;
import com.sap.sailing.domain.leaderboard.impl.LowerScoreIsBetter;
import com.sap.sailing.domain.leaderboard.impl.ResultDiscardingRuleImpl;
import com.sap.sailing.domain.leaderboard.impl.ScoreCorrectionImpl;
import com.sap.sailing.domain.persistence.DomainObjectFactory;
@@ -43,16 +44,16 @@ public class TestStoringAndRetrievingLeaderboardGroups extends AbstractMongoDBTe
final ArrayList<Leaderboard> leaderboards = new ArrayList<>();
Leaderboard leaderboard = new FlexibleLeaderboardImpl(leaderboardNames[0], new ScoreCorrectionImpl(),
new ResultDiscardingRuleImpl(discardIndexResultsStartingWithHowManyRaces));
new ResultDiscardingRuleImpl(discardIndexResultsStartingWithHowManyRaces), new LowerScoreIsBetter());
leaderboards.add(leaderboard);
leaderboard = new FlexibleLeaderboardImpl(leaderboardNames[1], new ScoreCorrectionImpl(),
new ResultDiscardingRuleImpl(discardIndexResultsStartingWithHowManyRaces));
new ResultDiscardingRuleImpl(discardIndexResultsStartingWithHowManyRaces), new LowerScoreIsBetter());
leaderboards.add(leaderboard);
leaderboard = new FlexibleLeaderboardImpl(leaderboardNames[2], new ScoreCorrectionImpl(),
new ResultDiscardingRuleImpl(discardIndexResultsStartingWithHowManyRaces));
new ResultDiscardingRuleImpl(discardIndexResultsStartingWithHowManyRaces), new LowerScoreIsBetter());
leaderboards.add(leaderboard);
leaderboard = new FlexibleLeaderboardImpl(leaderboardNames[3], new ScoreCorrectionImpl(),
new ResultDiscardingRuleImpl(discardIndexResultsStartingWithHowManyRaces));
new ResultDiscardingRuleImpl(discardIndexResultsStartingWithHowManyRaces), new LowerScoreIsBetter());
leaderboards.add(leaderboard);
final LeaderboardGroup leaderboardGroup = new LeaderboardGroupImpl(groupName, groupDescription, leaderboards);
@@ -80,10 +81,10 @@ public class TestStoringAndRetrievingLeaderboardGroups extends AbstractMongoDBTe
final ArrayList<Leaderboard> leaderboards = new ArrayList<>();
Leaderboard leaderboard = new FlexibleLeaderboardImpl(leaderboardNames[0], new ScoreCorrectionImpl(),
new ResultDiscardingRuleImpl(discardIndexResultsStartingWithHowManyRaces));
new ResultDiscardingRuleImpl(discardIndexResultsStartingWithHowManyRaces), new LowerScoreIsBetter());
leaderboards.add(leaderboard);
leaderboard = new FlexibleLeaderboardImpl(leaderboardNames[1], new ScoreCorrectionImpl(),
new ResultDiscardingRuleImpl(discardIndexResultsStartingWithHowManyRaces));
new ResultDiscardingRuleImpl(discardIndexResultsStartingWithHowManyRaces), new LowerScoreIsBetter());
leaderboards.add(leaderboard);
final LeaderboardGroup leaderboardGroup = new LeaderboardGroupImpl(groupName, groupDescription, leaderboards);
@@ -93,11 +94,11 @@ public class TestStoringAndRetrievingLeaderboardGroups extends AbstractMongoDBTe
final Leaderboard[] ungroupedLeaderboards = {
new FlexibleLeaderboardImpl(ungroupedLeaderboardNames[0], new ScoreCorrectionImpl(),
new ResultDiscardingRuleImpl(discardIndexResultsStartingWithHowManyRaces)),
new ResultDiscardingRuleImpl(discardIndexResultsStartingWithHowManyRaces), new LowerScoreIsBetter()),
new FlexibleLeaderboardImpl(ungroupedLeaderboardNames[1], new ScoreCorrectionImpl(),
new ResultDiscardingRuleImpl(discardIndexResultsStartingWithHowManyRaces)),
new ResultDiscardingRuleImpl(discardIndexResultsStartingWithHowManyRaces), new LowerScoreIsBetter()),
new FlexibleLeaderboardImpl(ungroupedLeaderboardNames[2], new ScoreCorrectionImpl(),
new ResultDiscardingRuleImpl(discardIndexResultsStartingWithHowManyRaces)) };
new ResultDiscardingRuleImpl(discardIndexResultsStartingWithHowManyRaces), new LowerScoreIsBetter()) };
mongoObjectFactory.storeLeaderboard(ungroupedLeaderboards[0]);
mongoObjectFactory.storeLeaderboard(ungroupedLeaderboards[1]);
mongoObjectFactory.storeLeaderboard(ungroupedLeaderboards[2]);
@@ -133,7 +134,7 @@ public class TestStoringAndRetrievingLeaderboardGroups extends AbstractMongoDBTe
final String groupDescription = "A leaderboard group";
final ArrayList<Leaderboard> leaderboards = new ArrayList<>();
final FlexibleLeaderboard leaderboard = new FlexibleLeaderboardImpl(leaderboardName, new ScoreCorrectionImpl(), new ResultDiscardingRuleImpl(discardIndexResultsStartingWithHowManyRaces));
final FlexibleLeaderboard leaderboard = new FlexibleLeaderboardImpl(leaderboardName, new ScoreCorrectionImpl(), new ResultDiscardingRuleImpl(discardIndexResultsStartingWithHowManyRaces), new LowerScoreIsBetter());
final Fleet fleet = leaderboard.getFleet(null);
final RaceColumn race = leaderboard.addRaceColumn(columnName, false, fleet);
leaderboards.add(leaderboard);
@@ -22,6 +22,7 @@ import com.sap.sailing.domain.common.impl.Util;
import com.sap.sailing.domain.leaderboard.FlexibleLeaderboard;
import com.sap.sailing.domain.leaderboard.Leaderboard;
import com.sap.sailing.domain.leaderboard.impl.FlexibleLeaderboardImpl;
import com.sap.sailing.domain.leaderboard.impl.LowerScoreIsBetter;
import com.sap.sailing.domain.leaderboard.impl.ResultDiscardingRuleImpl;
import com.sap.sailing.domain.leaderboard.impl.ScoreCorrectionImpl;
import com.sap.sailing.domain.persistence.impl.DomainObjectFactoryImpl;
@@ -35,7 +36,7 @@ public class TestStoringAndRetrievingLeaderboards extends AbstractMongoDBTest {
final String leaderboardName = "TestLeaderboard";
final int[] discardIndexResultsStartingWithHowManyRaces = new int[] { 5, 8 };
FlexibleLeaderboardImpl leaderboard = new FlexibleLeaderboardImpl(leaderboardName, new ScoreCorrectionImpl(),
new ResultDiscardingRuleImpl(discardIndexResultsStartingWithHowManyRaces));
new ResultDiscardingRuleImpl(discardIndexResultsStartingWithHowManyRaces), new LowerScoreIsBetter());
new MongoObjectFactoryImpl(db).storeLeaderboard(leaderboard);
Leaderboard loadedLeaderboard = new DomainObjectFactoryImpl(db).loadLeaderboard(leaderboardName);
assertEquals(leaderboardName, loadedLeaderboard.getName());
@@ -50,7 +51,7 @@ public class TestStoringAndRetrievingLeaderboards extends AbstractMongoDBTest {
final int carriedPointsForWolfgangHunger = 3;
final int[] discardIndexResultsStartingWithHowManyRaces = new int[] { 5, 8 };
FlexibleLeaderboardImpl leaderboard = new FlexibleLeaderboardImpl(leaderboardName, new ScoreCorrectionImpl(),
new ResultDiscardingRuleImpl(discardIndexResultsStartingWithHowManyRaces));
new ResultDiscardingRuleImpl(discardIndexResultsStartingWithHowManyRaces), new LowerScoreIsBetter());
Competitor competitor = createCompetitor();
TrackedRace raceWithOneCompetitor = new MockedTrackedRaceWithFixedRank(competitor, /* rank */ 1, /* started */ true);
leaderboard.addRace(raceWithOneCompetitor, raceColumnName, /* medalRace */ false, leaderboard.getFleet(null));
@@ -75,7 +76,7 @@ public class TestStoringAndRetrievingLeaderboards extends AbstractMongoDBTest {
final int correctedPoints = 2;
final int[] discardIndexResultsStartingWithHowManyRaces = new int[] { 5, 8 };
FlexibleLeaderboardImpl leaderboard = new FlexibleLeaderboardImpl(leaderboardName, new ScoreCorrectionImpl(),
new ResultDiscardingRuleImpl(discardIndexResultsStartingWithHowManyRaces));
new ResultDiscardingRuleImpl(discardIndexResultsStartingWithHowManyRaces), new LowerScoreIsBetter());
Competitor competitor = createCompetitor();
TrackedRace raceWithOneCompetitor1 = new MockedTrackedRaceWithFixedRank(competitor, /* rank */ 1, /* started */ true);
TrackedRace raceWithOneCompetitor2 = new MockedTrackedRaceWithFixedRank(competitor, /* rank */ 2, /* started */ true);
@@ -101,7 +102,7 @@ public class TestStoringAndRetrievingLeaderboards extends AbstractMongoDBTest {
final MaxPointsReason maxPointsReason = MaxPointsReason.DNF;
final int[] discardIndexResultsStartingWithHowManyRaces = new int[] { 5, 8 };
FlexibleLeaderboardImpl leaderboard = new FlexibleLeaderboardImpl(leaderboardName, new ScoreCorrectionImpl(),
new ResultDiscardingRuleImpl(discardIndexResultsStartingWithHowManyRaces));
new ResultDiscardingRuleImpl(discardIndexResultsStartingWithHowManyRaces), new LowerScoreIsBetter());
Competitor competitor = createCompetitor();
TrackedRace raceWithOneCompetitor1 = new MockedTrackedRaceWithFixedRank(competitor, /* rank */ 1, /* started */ true);
TrackedRace raceWithOneCompetitor2 = new MockedTrackedRaceWithFixedRank(competitor, /* rank */ 2, /* started */ true);
@@ -128,7 +129,7 @@ public class TestStoringAndRetrievingLeaderboards extends AbstractMongoDBTest {
final MaxPointsReason maxPointsReason = MaxPointsReason.DNF;
final int[] discardIndexResultsStartingWithHowManyRaces = new int[] { 5, 8 };
FlexibleLeaderboardImpl leaderboard = new FlexibleLeaderboardImpl(leaderboardName, new ScoreCorrectionImpl(),
new ResultDiscardingRuleImpl(discardIndexResultsStartingWithHowManyRaces));
new ResultDiscardingRuleImpl(discardIndexResultsStartingWithHowManyRaces), new LowerScoreIsBetter());
Competitor competitor = createCompetitor();
TrackedRace raceWithOneCompetitor1 = new MockedTrackedRaceWithFixedRank(competitor, /* rank */ 1, /* started */ true);
TrackedRace raceWithOneCompetitor2 = new MockedTrackedRaceWithFixedRank(competitor, /* rank */ 2, /* started */ true);
@@ -24,5 +24,5 @@
<booleanAttribute key="tracing" value="false"/>
<booleanAttribute key="useCustomFeatures" value="false"/>
<booleanAttribute key="useDefaultConfigArea" value="false"/>
<stringAttribute key="workspace_bundles" value="com.google.gwt.osgi@default:default,com.googlecode.java-diff-utils@default:default,com.mongodb.driver@default:default,com.sap.sailing.declination@default:default,com.sap.sailing.domain.common@default:default,com.sap.sailing.domain.persistence@default:default,com.sap.sailing.domain.swisstimingadapter.persistence@default:default,com.sap.sailing.domain.swisstimingadapter@default:default,com.sap.sailing.domain.tractracadapter.persistence@default:default,com.sap.sailing.domain.tractracadapter@default:default,com.sap.sailing.domain@default:default,com.sap.sailing.expeditionconnector@default:default,com.sap.sailing.geocoding@default:default,com.sap.sailing.gwt.ui@default:default,com.sap.sailing.mongodb@default:default,com.sap.sailing.operationaltransformation@default:default,com.sap.sailing.server.replication@default:default,com.sap.sailing.server@default:default,com.sap.sailing.udpconnector@default:default,com.sap.sailing.www.events@default:default,com.sap.sailing.www@default:default,com.sap.sailing.xcelsiusadapter@default:default,com.tractrac.clientmodule@default:default,com.tractrac.resultapi@default:default,org.json.simple@default:default,org.moxieapps.gwt.highcharts@default:default"/>
<stringAttribute key="workspace_bundles" value="com.google.gwt.osgi@default:default,com.googlecode.java-diff-utils@default:default,com.mongodb.driver@default:default,com.sap.sailing.declination@default:default,com.sap.sailing.domain.common@default:default,com.sap.sailing.domain.persistence@default:default,com.sap.sailing.domain.swisstimingadapter.persistence@default:default,com.sap.sailing.domain.swisstimingadapter@default:default,com.sap.sailing.domain.tractracadapter.persistence@default:default,com.sap.sailing.domain.tractracadapter@default:default,com.sap.sailing.domain@default:default,com.sap.sailing.expeditionconnector@default:default,com.sap.sailing.geocoding@default:default,com.sap.sailing.gwt.ui@default:default,com.sap.sailing.mongodb@default:default,com.sap.sailing.operationaltransformation@default:default,com.sap.sailing.server.replication@default:default,com.sap.sailing.server@default:default,com.sap.sailing.udpconnector@default:default,com.sap.sailing.www.events@default:default,com.sap.sailing.www@default:default,com.sap.sailing.xcelsiusadapter@default:default,com.tractrac.clientmodule@default:default,org.json.simple@default:default,org.moxieapps.gwt.highcharts@default:default"/>
</launchConfiguration>
@@ -31,4 +31,22 @@
<servlet-name>ExpeditionThroughHttpPostServlet</servlet-name>
<url-pattern>/expedition</url-pattern>
</servlet-mapping>
<servlet>
<servlet-name>ListLeaderboards</servlet-name>
<servlet-class>com.sap.sailing.server.impl.ListLeaderboards</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>ListLeaderboards</servlet-name>
<url-pattern>/listleaderboards</url-pattern>
</servlet-mapping>
<servlet>
<servlet-name>LeaderboardJsonExport</servlet-name>
<servlet-class>com.sap.sailing.server.impl.LeaderboardJsonExport</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>LeaderboardJsonExport</servlet-name>
<url-pattern>/leaderboard</url-pattern>
</servlet-mapping>
</web-app>
@@ -0,0 +1,92 @@
package com.sap.sailing.server.impl;
import java.io.IOException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.json.simple.JSONArray;
import org.json.simple.JSONObject;
import com.sap.sailing.domain.base.Competitor;
import com.sap.sailing.domain.base.Fleet;
import com.sap.sailing.domain.base.RaceColumn;
import com.sap.sailing.domain.base.impl.MillisecondsTimePoint;
import com.sap.sailing.domain.common.NoWindException;
import com.sap.sailing.domain.common.TimePoint;
import com.sap.sailing.domain.leaderboard.Leaderboard;
import com.sap.sailing.server.Servlet;
public class LeaderboardJsonExport extends Servlet {
private static final long serialVersionUID = -2460691283231361152L;
private static final String PARAM_NAME_LEADERBOARDNAME = "leaderboardName";
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
TimePoint timePoint = MillisecondsTimePoint.now();
String leaderboardName = req.getParameter(PARAM_NAME_LEADERBOARDNAME);
if (leaderboardName == null) {
resp.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, "Need to specify a leaderboard name using the "+
PARAM_NAME_LEADERBOARDNAME+" parameter");
} else {
Leaderboard leaderboard = getService().getLeaderboardByName(leaderboardName);
if (leaderboard == null) {
resp.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, "Leaderboard "+leaderboardName+" not found");
} else {
try {
List<Competitor> competitorsFromBestToWorstAccordingToTotalRank = leaderboard
.getCompetitorsFromBestToWorst(timePoint);
Map<RaceColumn, List<Competitor>> rankedCompetitorsPerColumn = new HashMap<RaceColumn, List<Competitor>>();
JSONObject jsonLeaderboard = new JSONObject();
jsonLeaderboard.put("name", leaderboard.getName());
JSONArray jsonColumnNames = new JSONArray();
jsonLeaderboard.put("columnNames", jsonColumnNames);
for (RaceColumn raceColumn : leaderboard.getRaceColumns()) {
jsonColumnNames.add(raceColumn.getName());
}
JSONArray jsonCompetitorEntries = new JSONArray();
jsonLeaderboard.put("competitors", jsonCompetitorEntries);
for (Competitor competitor : competitorsFromBestToWorstAccordingToTotalRank) {
JSONObject jsonCompetitor = new JSONObject();
jsonCompetitor.put("name", competitor.getName());
final String displayName = leaderboard.getDisplayName(competitor);
jsonCompetitor.put("displayName", displayName==null?competitor.getName():displayName);
jsonCompetitor.put("id", competitor.getId().toString());
jsonCompetitor.put("sailID", competitor.getBoat().getSailID());
jsonCompetitor.put("nationality", competitor.getTeam().getNationality()
.getThreeLetterIOCAcronym());
jsonCompetitor.put("rank",
competitorsFromBestToWorstAccordingToTotalRank.indexOf(competitor) + 1);
jsonCompetitor.put("totalPoints", leaderboard.getTotalPoints(competitor, timePoint));
jsonCompetitorEntries.add(jsonCompetitor);
JSONObject jsonRaceColumns = new JSONObject();
jsonCompetitor.put("raceScores", jsonRaceColumns);
for (RaceColumn raceColumn : leaderboard.getRaceColumns()) {
List<Competitor> rankedCompetitorsForColumn = rankedCompetitorsPerColumn.get(raceColumn);
if (rankedCompetitorsForColumn == null) {
rankedCompetitorsForColumn = leaderboard.getCompetitorsFromBestToWorst(raceColumn, timePoint);
rankedCompetitorsPerColumn.put(raceColumn, rankedCompetitorsForColumn);
}
JSONObject jsonEntry = new JSONObject();
jsonRaceColumns.put(raceColumn.getName(), jsonEntry);
final Fleet fleetOfCompetitor = raceColumn.getFleetOfCompetitor(competitor);
jsonEntry.put("fleet", fleetOfCompetitor==null?"":fleetOfCompetitor.getName());
jsonEntry.put("netPoints", leaderboard.getNetPoints(competitor, raceColumn, timePoint));
jsonEntry.put("totalPoints", leaderboard.getTotalPoints(competitor, raceColumn, timePoint));
jsonEntry.put("maxPointsReason", leaderboard.getMaxPointsReason(competitor, raceColumn, timePoint));
jsonEntry.put("rank", rankedCompetitorsForColumn.indexOf(competitor)+1);
jsonEntry.put("isDiscarded", leaderboard.isDiscarded(competitor, raceColumn, timePoint));
}
}
jsonLeaderboard.writeJSONString(resp.getWriter());
} catch (NoWindException e) {
resp.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, e.getMessage());
}
}
}
}
}
@@ -0,0 +1,28 @@
package com.sap.sailing.server.impl;
import java.io.IOException;
import java.util.Map;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.json.simple.JSONArray;
import com.sap.sailing.domain.leaderboard.Leaderboard;
import com.sap.sailing.server.Servlet;
public class ListLeaderboards extends Servlet {
private static final long serialVersionUID = -2193421590275280102L;
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
JSONArray jsonLeaderboards = new JSONArray();
Map<String, Leaderboard> leaderboards = getService().getLeaderboards();
for (String leaderboardName : leaderboards.keySet()) {
jsonLeaderboards.add(leaderboardName);
}
jsonLeaderboards.writeJSONString(resp.getWriter());
}
}
@@ -51,6 +51,7 @@ import com.sap.sailing.domain.leaderboard.Leaderboard;
import com.sap.sailing.domain.leaderboard.LeaderboardGroup;
import com.sap.sailing.domain.leaderboard.impl.FlexibleLeaderboardImpl;
import com.sap.sailing.domain.leaderboard.impl.LeaderboardGroupImpl;
import com.sap.sailing.domain.leaderboard.impl.LowerScoreIsBetter;
import com.sap.sailing.domain.leaderboard.impl.ResultDiscardingRuleImpl;
import com.sap.sailing.domain.leaderboard.impl.ScoreCorrectionImpl;
import com.sap.sailing.domain.persistence.DomainObjectFactory;
@@ -207,7 +208,7 @@ public class RacingEventServiceImpl implements RacingEventService, RegattaListen
@Override
public Leaderboard addFlexibleLeaderboard(String name, int[] discardThresholds) {
Leaderboard result = new FlexibleLeaderboardImpl(name, new ScoreCorrectionImpl(), new ResultDiscardingRuleImpl(
discardThresholds));
discardThresholds), new LowerScoreIsBetter());
synchronized (leaderboardsByName) {
if (leaderboardsByName.containsKey(name)) {
throw new IllegalArgumentException("Leaderboard with name "+name+" already exists");
@@ -1495,7 +1495,6 @@ public abstract class BaseChart<T> extends Widget {
// Once we're rendered, we're maintaining the point state in the DOM, so we can dump our internal list to save memory
series.clearInternalPointsList();
nativeAdjustCheckboxPosition(get(series.getId()));
}
return returnThis();
@@ -1818,6 +1817,7 @@ public abstract class BaseChart<T> extends Widget {
public T redraw() {
if (isRendered()) {
nativeRedraw(chart);
nativeAdjustCheckboxPosition(chart);
}
return returnThis();
}
@@ -1969,7 +1969,6 @@ public abstract class BaseChart<T> extends Widget {
for (Series series : seriesList) {
series.clearInternalPointsList();
series.setRendered(true);
nativeAdjustCheckboxPosition(get(series.getId()));
}
}
@@ -2489,20 +2488,22 @@ public abstract class BaseChart<T> extends Widget {
/**
* Fixing a bug currently in the base Highcharts implementation regarding the placement of the checkbox in the legend.
* Requires the symbol padding (see {@link Legend#setSymbolPadding(Number)}) to be set to <code>20</code>. Invoked
* whenever a series is added / displayed in a rendered chart.<p>
* Requires the symbol padding (see {@link Legend#setSymbolPadding(Number)}) to be set to <code>25</code>. Invoked
* whenever the chart is rendered.<p>
*
* The implementation moves the legend item text 15px to the left, using the space made by setting the symbol
* padding to 20px; the checkbox is moved 18px to the left with the top margin set to 0px.
* The implementation moves the checkbox between the legend symbol and the legend item, using the space made by setting the symbol
* padding to 25px.
*/
private static native JavaScriptObject nativeAdjustCheckboxPosition(JavaScriptObject series) /*-{
if (series.legendItem && series.checkbox) {
series.legendItem.translate(-15, 0);
series.checkbox.style.marginLeft = '-18px'
series.checkbox.style.marginTop = '0px'
private static native JavaScriptObject nativeAdjustCheckboxPosition(JavaScriptObject chart) /*-{
var series = chart.series;
for(var i= 0; i<series.length; i++) {
if(series[i].legendItem && series[i].checkbox) {
series[i].checkbox.style.marginLeft = - series[i].legendItemWidth + 20 + "px";
series[i].checkbox.style.marginTop = '0px';
}
}
}-*/;
private static native void nativeRedraw(JavaScriptObject chart) /*-{
chart.redraw();
}-*/;