Merge remote-tracking branch 'origin/master' into mark-rounding-inference

Conflicts:
	java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/impl/DynamicTrackedRaceImpl.java
This commit is contained in:
Nicolas committed 2014-06-25 10:39:28 +02:00
commit abcc0d2f8c
80 files changed
+992 -269

No files matched your search

+1
View File
@@ -46,6 +46,7 @@ Like businesses, sailors need the latest information to make strategic decisions
* [[Project Planning (bigger development)|wiki/planning]]
* [[General Event Planning|wiki/general-event-planning]]
* [[Information about Extreme Sailing Series|wiki/extreme-sailing-series]]
* [[Kieler Woche 2014 event page|wiki/kielerwoche2014]]
### Internal services (not related to wiki but useful)
@@ -9,7 +9,9 @@ import org.json.simple.JSONObject;
import org.json.simple.parser.JSONParser;
import org.json.simple.parser.ParseException;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.Timeout;
import com.sap.sailing.domain.common.impl.MillisecondsTimePoint;
import com.sap.sailing.domain.igtimiadapter.datatypes.AntHrm;
@@ -19,6 +21,8 @@ import com.sap.sailing.domain.igtimiadapter.datatypes.GpsQualitySatCount;
import com.sap.sse.common.Util;
public class FixFactoryTest {
@Rule public Timeout AbstractTracTracLiveTestTimeout = new Timeout(2 * 60 * 1000);
private static final String demoJson = "{\n"+
"\"EA-AK-AAAG\": {\n"+
"\"1\": {\n"+
@@ -8,7 +8,9 @@ import java.net.URISyntaxException;
import org.apache.http.client.ClientProtocolException;
import org.json.simple.parser.ParseException;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.Timeout;
import com.sap.sailing.domain.igtimiadapter.persistence.PersistenceFactory;
import com.sap.sailing.mongodb.MongoDBConfiguration;
@@ -16,6 +18,8 @@ import com.sap.sailing.mongodb.MongoDBService;
import com.sap.sse.common.Util;
public class WebSocketServerListTest {
@Rule public Timeout AbstractTracTracLiveTestTimeout = new Timeout(2 * 60 * 1000);
@Test
public void testWebSocketServerList() throws IllegalStateException, ClientProtocolException, IOException, ParseException, URISyntaxException {
final ClientImpl testAppClient = new ClientImpl("7fcdd217e0aa16090edb4ad55b09ec43b2021090e209541fc9b7003c2a2b70c6",
@@ -10,7 +10,9 @@ import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.Timeout;
import com.sap.sailing.declination.DeclinationService;
import com.sap.sailing.domain.common.SpeedWithBearing;
@@ -29,6 +31,8 @@ import com.sap.sailing.domain.igtimiadapter.shared.IgtimiWindReceiver;
import com.sap.sailing.domain.tracking.Wind;
public class WindReceiverTest {
@Rule public Timeout AbstractTracTracLiveTestTimeout = new Timeout(2 * 60 * 1000);
@Test
public void simpleWindReceiverTest() {
final List<Wind> windReceived = new ArrayList<>();
@@ -11,7 +11,9 @@ import javax.xml.parsers.ParserConfigurationException;
import org.apache.http.client.ClientProtocolException;
import org.json.simple.parser.ParseException;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.Timeout;
import org.xml.sax.SAXException;
import com.sap.sailing.domain.igtimiadapter.Account;
@@ -27,6 +29,8 @@ import com.sap.sailing.mongodb.MongoDBService;
public class SignInTest {
private static final Logger logger = Logger.getLogger(SignInTest.class.getName());
@Rule public Timeout AbstractTracTracLiveTestTimeout = new Timeout(2 * 60 * 1000);
@Test
public void testSimpleSignIn() throws ClientProtocolException, IOException, IllegalStateException,
ParserConfigurationException, SAXException, ClassNotFoundException, InstantiationException,
@@ -4,6 +4,8 @@ import java.io.IOException;
import org.apache.http.client.ClientProtocolException;
import org.junit.Before;
import org.junit.Rule;
import org.junit.rules.Timeout;
import com.sap.sailing.domain.igtimiadapter.Account;
import com.sap.sailing.domain.igtimiadapter.IgtimiConnection;
@@ -13,6 +15,8 @@ import com.sap.sailing.domain.igtimiadapter.impl.Activator;
public class AbstractTestWithIgtimiConnection {
protected IgtimiConnection connection;
@Rule public Timeout AbstractTracTracLiveTestTimeout = new Timeout(2 * 60 * 1000);
@Before
public void setUp() throws ClientProtocolException, IOException, org.json.simple.parser.ParseException {
final IgtimiConnectionFactory connectionFactory = Activator.getInstance().getConnectionFactory();
@@ -378,8 +378,14 @@ public class IgtimiWindReceiver implements BulkFixReceiver {
if (declinationService == null) {
trueHeading = hdgm;
} else {
Declination declination = declinationService.getDeclination(timePoint, position, /* timeoutForOnlineFetchInMilliseconds 5s */ 5000);
trueHeading = hdgm.add(declination.getBearingCorrectedTo(timePoint));
try {
Declination declination = declinationService.getDeclination(timePoint, position, /* timeoutForOnlineFetchInMilliseconds 5s */ 5000);
trueHeading = hdgm.add(declination.getBearingCorrectedTo(timePoint));
} catch (Exception e) {
logger.log(Level.SEVERE, "Correction of declination was requested but unsuccessful. Can't correct heading "+
hdgm+"@"+timePoint+" by declination. Forwarding exception.");
throw e;
}
}
} else {
trueHeading = null;
@@ -154,7 +154,11 @@ public class WebSocketConnectionManager extends WebSocketAdapter implements Live
private void notifyListeners(List<Fix> fixes) {
for (BulkFixReceiver listener : listeners.keySet()) {
listener.received(fixes);
try {
listener.received(fixes);
} catch (Exception e) {
logger.log(Level.SEVERE, "Error notifying listener "+listener+" of Igtimi fixes "+fixes, e);
}
}
}
@@ -1,8 +1,10 @@
package com.sap.sailing.domain.persistence;
import java.net.URL;
import java.util.Collection;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import com.mongodb.DBObject;
import com.sap.sailing.domain.base.Competitor;
@@ -123,4 +125,6 @@ public interface DomainObjectFactory {
DomainFactory getBaseDomainFactory();
Iterable<Entry<DeviceConfigurationMatcher, DeviceConfiguration>> loadAllDeviceConfigurations();
Map<String, Set<URL>> loadResultUrls();
}
@@ -1,6 +1,7 @@
package com.sap.sailing.domain.persistence;
import java.io.Serializable;
import java.net.URL;
import com.mongodb.DB;
import com.mongodb.DBObject;
@@ -131,4 +132,8 @@ public interface MongoObjectFactory {
void removeDeviceConfiguration(DeviceConfigurationMatcher matcher);
void removeRaceLog(RaceLogIdentifier identifier);
void storeResultUrl(String resultProviderName, URL url);
void removeResultUrl(String resultProviderName, URL url);
}
@@ -87,4 +87,9 @@ public enum CollectionNames {
* Metadata for the GPSFixes, grouped by Device Identifier.
*/
GPS_FIXES_METADATA,
/**
* URLs providing race results
*/
RESULT_URLS,
}
@@ -1779,4 +1779,27 @@ public class DomainObjectFactoryImpl implements DomainObjectFactory {
stringRepresentation, deviceType, stringRepresentation);
}
}
@Override
public Map<String, Set<URL>> loadResultUrls() {
Map<String, Set<URL>> resultUrls = new HashMap<>();
DBCollection resultUrlCollection = database.getCollection(CollectionNames.RESULT_URLS.name());
for (DBObject dbObject : resultUrlCollection.find()) {
String providerName = (String) dbObject.get(FieldNames.RESULT_PROVIDERNAME.name());
String urlString = (String) dbObject.get(FieldNames.RESULT_URL.name());
URL url;
try {
url = new URL(urlString);
} catch (MalformedURLException e) {
logger.log(Level.SEVERE, "Failed to parse result Url String: " + urlString + ". Did not load url!");
continue;
}
if (!resultUrls.containsKey(providerName)) {
resultUrls.put(providerName, new HashSet<URL>());
}
Set<URL> set = resultUrls.get(providerName);
set.add(url);
}
return resultUrls;
}
}
@@ -108,4 +108,7 @@ public enum FieldNames {
// Timespan
FROM_MILLIS, TO_MILLIS,
// Result Import url fields
RESULT_PROVIDERNAME, RESULT_URL
}
@@ -1257,4 +1257,21 @@ public class MongoObjectFactoryImpl implements MongoObjectFactory {
storeRaceLogIdentifier(identifier, query);
getRaceLogCollection().remove(query);
}
@Override
public void storeResultUrl(String resultProviderName, URL url) {
DBCollection resultUrlsCollection = database.getCollection(CollectionNames.RESULT_URLS.name());
DBObject query = new BasicDBObject(FieldNames.RESULT_PROVIDERNAME.name(), resultProviderName);
DBObject entry = new BasicDBObject(FieldNames.RESULT_PROVIDERNAME.name(), resultProviderName);
entry.put(FieldNames.RESULT_URL.name(), url.toString());
resultUrlsCollection.update(query, entry, /* upsrt */true, /* multi */false, WriteConcern.SAFE);
}
@Override
public void removeResultUrl(String resultProviderName, URL url) {
DBCollection resultUrlsCollection = database.getCollection(CollectionNames.RESULT_URLS.name());
DBObject query = new BasicDBObjectBuilder().add(FieldNames.RESULT_PROVIDERNAME.name(), resultProviderName)
.add(FieldNames.RESULT_URL.name(), url.toString()).get();
resultUrlsCollection.remove(query);
}
}
@@ -1,7 +1,6 @@
package com.sap.sailing.domain.racelogtracking.test.impl;
import static junit.framework.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import java.util.Arrays;
import java.util.Collections;
@@ -31,7 +30,7 @@ import com.sap.sailing.domain.racelog.tracking.test.mock.SmartphoneImeiIdentifie
import com.sap.sailing.domain.racelogtracking.test.AbstractGPSFixStoreTest;
import com.sap.sailing.domain.tracking.GPSFixMoving;
import com.sap.sailing.domain.tracking.TrackedRegatta;
import com.sap.sailing.domain.tracking.impl.BaseRaceChangeListener;
import com.sap.sailing.domain.tracking.impl.AbstractRaceChangeListener;
import com.sap.sailing.domain.tracking.impl.DynamicTrackedRaceImpl;
import com.sap.sailing.domain.tracking.impl.EmptyWindStore;
import com.sap.sailing.domain.tracking.impl.TrackedRegattaImpl;
@@ -39,7 +38,8 @@ import com.sap.sailing.domain.tracking.impl.TrackedRegattaImpl;
public class TrackedRaceLoadsFixesTest extends AbstractGPSFixStoreTest {
private final BoatClass boatClass = DomainFactory.INSTANCE.getOrCreateBoatClass("49er");
private boolean finishedLoadingFirstBeforeSecond = true;
private int numberOfSwitchesBetweenLoadingRaceLogs = 0;
private Integer previouslyLoading = null;
private int numFixesReceived = 0;
@Test
@@ -114,19 +114,16 @@ public class TrackedRaceLoadsFixesTest extends AbstractGPSFixStoreTest {
DynamicTrackedRaceImpl trackedRace = new DynamicTrackedRaceImpl(regatta, race, Collections.<Sideline>emptyList(),
EmptyWindStore.INSTANCE, store, 0, 0, 0);
trackedRace.addListener(new BaseRaceChangeListener() {
boolean currentlyLoadingFirst = true;
trackedRace.addListener(new AbstractRaceChangeListener() {
@Override
public void competitorPositionChanged(GPSFixMoving fix, Competitor competitor) {
numFixesReceived++;
if (currentlyLoadingFirst) {
if (fix.getTimePoint().asMillis() > numFixes/2) {
currentlyLoadingFirst = false;
}
} else {
if (fix.getTimePoint().asMillis() <= numFixes/2) {
finishedLoadingFirstBeforeSecond = false;
}
int currentlyLoading = fix.getTimePoint().asMillis() <= numFixes/2 ? 1 : 2;
if (previouslyLoading == null) {
previouslyLoading = currentlyLoading;
} else if (previouslyLoading != currentlyLoading) {
previouslyLoading = currentlyLoading;
numberOfSwitchesBetweenLoadingRaceLogs++;
}
}
});
@@ -137,7 +134,7 @@ public class TrackedRaceLoadsFixesTest extends AbstractGPSFixStoreTest {
trackedRace.waitForLoadingFromGPSFixStoreToFinishRunning(raceLog);
trackedRace.waitForLoadingFromGPSFixStoreToFinishRunning(raceLog2);
assertTrue(finishedLoadingFirstBeforeSecond);
assertEquals(1, numberOfSwitchesBetweenLoadingRaceLogs);
assertEquals(numFixes, numFixesReceived);
}
}
@@ -124,6 +124,9 @@ public class SharedDomainFactoryImpl implements SharedDomainFactory {
@Override
public Nationality getOrCreateNationality(String threeLetterIOCCode) {
if (threeLetterIOCCode == null) {
threeLetterIOCCode = " ";
}
synchronized (nationalityCache) {
Nationality result = nationalityCache.get(threeLetterIOCCode);
if (result == null) {
@@ -177,15 +177,18 @@ public abstract class BaseRacingProcedure extends BaseRaceStateChangedListener i
protected void update() {
boolean isRecallDisplayed = isRecallDisplayedAnalyzer.analyze();
// always call listeners for changed flag, as this does not only affect recal, but also
// changes start procedure, for which some text elements need to be updated
// ({@link BaseRaceInfoFragmen#renderFlagChangesCountdown}
changedListeners.onActiveFlagsChanged(this);
if (cachedIsIndividualRecallDisplayed != isRecallDisplayed) {
cachedIsIndividualRecallDisplayed = isRecallDisplayed;
if (cachedIsIndividualRecallDisplayed) {
changedListeners.onIndividualRecallDisplayed(this);
changedListeners.onActiveFlagsChanged(this);
rescheduleIndividualRecallTimeout(recallDisplayedFinder.analyze());
} else {
changedListeners.onIndividualRecallRemoved(this);
changedListeners.onActiveFlagsChanged(this);
unscheduleStateEvent(RaceStateEvents.INDIVIDUAL_RECALL_TIMEOUT);
}
}
@@ -0,0 +1,178 @@
package com.sap.sailing.domain.test;
import static org.junit.Assert.assertEquals;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.when;
import java.util.Calendar;
import java.util.Date;
import java.util.HashSet;
import java.util.Set;
import java.util.UUID;
import java.util.concurrent.ExecutionException;
import org.junit.Test;
import com.sap.sailing.domain.base.BoatClass;
import com.sap.sailing.domain.base.Competitor;
import com.sap.sailing.domain.base.ControlPoint;
import com.sap.sailing.domain.base.Course;
import com.sap.sailing.domain.base.CourseArea;
import com.sap.sailing.domain.base.DomainFactory;
import com.sap.sailing.domain.base.Fleet;
import com.sap.sailing.domain.base.RaceColumn;
import com.sap.sailing.domain.base.RaceDefinition;
import com.sap.sailing.domain.base.Regatta;
import com.sap.sailing.domain.base.Series;
import com.sap.sailing.domain.base.Sideline;
import com.sap.sailing.domain.base.Waypoint;
import com.sap.sailing.domain.base.impl.BoatClassImpl;
import com.sap.sailing.domain.base.impl.CompetitorImpl;
import com.sap.sailing.domain.base.impl.CourseImpl;
import com.sap.sailing.domain.base.impl.DomainFactoryImpl;
import com.sap.sailing.domain.base.impl.DynamicBoat;
import com.sap.sailing.domain.base.impl.DynamicTeam;
import com.sap.sailing.domain.base.impl.FleetImpl;
import com.sap.sailing.domain.base.impl.MarkImpl;
import com.sap.sailing.domain.base.impl.RegattaImpl;
import com.sap.sailing.domain.base.impl.SeriesImpl;
import com.sap.sailing.domain.base.impl.WaypointImpl;
import com.sap.sailing.domain.common.Color;
import com.sap.sailing.domain.common.NoWindException;
import com.sap.sailing.domain.common.TimePoint;
import com.sap.sailing.domain.common.dto.LeaderboardDTO;
import com.sap.sailing.domain.common.impl.MillisecondsTimePoint;
import com.sap.sailing.domain.leaderboard.Leaderboard;
import com.sap.sailing.domain.leaderboard.ScoringScheme;
import com.sap.sailing.domain.leaderboard.ThresholdBasedResultDiscardingRule;
import com.sap.sailing.domain.leaderboard.impl.LowPoint;
import com.sap.sailing.domain.leaderboard.impl.RegattaLeaderboardImpl;
import com.sap.sailing.domain.leaderboard.impl.ThresholdBasedResultDiscardingRuleImpl;
import com.sap.sailing.domain.racelog.tracking.EmptyGPSFixStore;
import com.sap.sailing.domain.tracking.DynamicTrackedRegatta;
import com.sap.sailing.domain.tracking.TrackedRace;
import com.sap.sailing.domain.tracking.TrackedRegatta;
import com.sap.sailing.domain.tracking.TrackedRegattaRegistry;
import com.sap.sailing.domain.tracking.impl.DynamicTrackedRaceImpl;
import com.sap.sailing.domain.tracking.impl.EmptyWindStore;
public class LeaderboardCourseChangeTest {
/**
* See bug 2011
*
* @throws NoWindException
* @throws InterruptedException
* @throws ExecutionException
*/
@Test
public void testLeaderboardDTOCreationForCourseChange() throws NoWindException, InterruptedException, ExecutionException {
Date date = Calendar.getInstance().getTime();
TimePoint timePoint = new MillisecondsTimePoint(date);
TrackedRegattaRegistry trackedRegattaRegistry = mock(TrackedRegattaRegistry.class);
Fleet fleet = new FleetImpl("TestFleet");
Series series = createSeries(trackedRegattaRegistry, fleet);
Set<Series> seriesSet = new HashSet<>();
seriesSet.add(series);
BoatClass boatClass = new BoatClassImpl("TestClass", true);
String raceColumnName = "TestRace";
RaceColumn raceColumn = series.addRaceColumn(raceColumnName, trackedRegattaRegistry);
ScoringScheme scoringScheme = new LowPoint();
Regatta mockedRegatta = new RegattaImpl("TestRegatta", boatClass, seriesSet, false, scoringScheme,
UUID.randomUUID(), mock(CourseArea.class));
ControlPoint start = new MarkImpl("Start");
ControlPoint m1 = new MarkImpl("M1");
ControlPoint m2 = new MarkImpl("M2");
ControlPoint finish = new MarkImpl("Finish");
Set<Waypoint> waypoints = new HashSet<>();
Waypoint startWaypoint = new WaypointImpl(start);
waypoints.add(startWaypoint);
Waypoint m1Waypoint1 = new WaypointImpl(m1);
Waypoint m2Waypoint1 = new WaypointImpl(m2);
Waypoint m1Waypoint2 = new WaypointImpl(m1);
Waypoint m2Waypoint2 = new WaypointImpl(m2);
Waypoint m1Waypoint3 = new WaypointImpl(m1);
waypoints.add(m1Waypoint1);
waypoints.add(m2Waypoint1);
waypoints.add(m1Waypoint2);
waypoints.add(m2Waypoint2);
waypoints.add(m1Waypoint3);
Waypoint finishWaypoint = new WaypointImpl(finish);
waypoints.add(finishWaypoint);
Course course = new CourseImpl(raceColumnName, waypoints);
TrackedRace mockedTrackedRace = createSpyedTrackedRace(mockedRegatta, course, timePoint, boatClass);
raceColumn.setTrackedRace(fleet, mockedTrackedRace);
Set<String> raceColumnNames = new HashSet<>();
raceColumnNames.add(raceColumnName);
int[] ruleRaw = { 5, 3, 2 };
ThresholdBasedResultDiscardingRule rule = new ThresholdBasedResultDiscardingRuleImpl(ruleRaw);
Leaderboard leaderboard = new RegattaLeaderboardImpl(mockedRegatta, rule);
DomainFactory baseDomainFactory = new DomainFactoryImpl();
LeaderboardDTO leaderboardDTO = leaderboard.getLeaderboardDTO(timePoint, raceColumnNames, false,
trackedRegattaRegistry, baseDomainFactory);
assertEquals(6, leaderboardDTO.rows.values().iterator().next().fieldsByRaceColumnName.values().iterator()
.next().legDetails.size());
course.removeWaypoint(2);
course.removeWaypoint(3);
leaderboardDTO = leaderboard.getLeaderboardDTO(timePoint, raceColumnNames, false, trackedRegattaRegistry,
baseDomainFactory);
assertEquals(4, leaderboardDTO.rows.values().iterator().next().fieldsByRaceColumnName.values().iterator()
.next().legDetails.size());
}
private TrackedRace createSpyedTrackedRace(Regatta regatta, Course course, TimePoint timePoint, BoatClass boatClass) {
TrackedRegatta mockedTrackedRegatta = createMockedTrackedRegatta(regatta);
RaceDefinition mockedRace = createMockedRace(course, boatClass);
TrackedRace spyedTrackedRace = spy(new DynamicTrackedRaceImpl(mockedTrackedRegatta, mockedRace,
new HashSet<Sideline>(), EmptyWindStore.INSTANCE, EmptyGPSFixStore.INSTANCE, 5000, 20000, 20000));
return spyedTrackedRace;
}
private RaceDefinition createMockedRace(Course course, BoatClass boatClass) {
RaceDefinition mockedRaceDefinition = mock(RaceDefinition.class);
when(mockedRaceDefinition.getCompetitors()).thenReturn(new HashSet<Competitor>());
when(mockedRaceDefinition.getCourse()).thenReturn(course);
when(mockedRaceDefinition.getBoatClass()).thenReturn(new BoatClassImpl("TestClass", true));
when(mockedRaceDefinition.getName()).thenReturn("TestRace");
Iterable<Competitor> competitorSet = createCompetitorSet(boatClass);
when(mockedRaceDefinition.getCompetitors()).thenReturn(competitorSet);
return mockedRaceDefinition;
}
private Iterable<Competitor> createCompetitorSet(BoatClass boatClass) {
Set<Competitor> competitors = new HashSet<>();
DynamicBoat mockedBoat = mock(DynamicBoat.class);
when(mockedBoat.getBoatClass()).thenReturn(boatClass);
competitors.add(new CompetitorImpl(UUID.randomUUID(), "TestCompetitor", Color.BLACK, mock(DynamicTeam.class),
mockedBoat));
return competitors;
}
private TrackedRegatta createMockedTrackedRegatta(Regatta regatta) {
TrackedRegatta mockedTrackedRegatta = mock(DynamicTrackedRegatta.class);
when(mockedTrackedRegatta.getRegatta()).thenReturn(regatta);
return mockedTrackedRegatta;
}
private Series createSeries(TrackedRegattaRegistry trackedRegattaRegistry, Fleet fleet) {
Set<Fleet> fleets = new HashSet<>();
fleets.add(fleet);
Series series = new SeriesImpl("TestSeries", false, fleets, new HashSet<String>(), trackedRegattaRegistry);
return series;
}
}
@@ -80,7 +80,6 @@ public class MultipleClassesInRegattaTest {
assertEquals("505", kiwotest2.getRegatta().getBoatClass().getName());
assertEquals("49er", kiwotest3.getRegatta().getBoatClass().getName());
assertEquals("STG", weym470may112014_2.getRegatta().getBoatClass().getName());
assertNotSame(weym470may112014_2.getRegatta(), kiwotest1.getRegatta()); // expecting that each race gets a distinct default regatta
assertNotSame(kiwotest1.getRegatta(), kiwotest2.getRegatta());
assertNotSame(kiwotest1.getRegatta(), kiwotest3.getRegatta());
assertNotSame(kiwotest2.getRegatta(), kiwotest3.getRegatta());
@@ -372,7 +372,7 @@ public class DomainFactoryImpl implements DomainFactory {
// This is particularly bad if a persistent regatta was loaded but a default regatta was accidentally created.
// Then, there is no way but restart the server to get rid of this stale cache entry here.
if (result == null) {
result = new RegattaImpl(raceLogStore, race.getName(), boatClass, trackedRegattaRegistry,
result = new RegattaImpl(raceLogStore, defaultRegattaNameAndBoatClass.getA(), boatClass, trackedRegattaRegistry,
// use the low-point system as the default scoring scheme
getBaseDomainFactory().createScoringScheme(ScoringSchemeType.LOW_POINT), race.getId(), null);
regattaCache.put(key, result);
@@ -389,7 +389,8 @@ public class DomainFactoryImpl implements DomainFactory {
for (IRaceCompetitor competitor : race.getRaceCompetitors()) {
competitorClassList.add(competitor.getCompetitor().getCompetitorClass());
}
Pair<String, BoatClass> defaultRegattaNameAndBoatClass = new Pair<String, BoatClass>(race.getName(), getDominantBoatClass(competitorClassList));
Pair<String, BoatClass> defaultRegattaNameAndBoatClass = new Pair<String, BoatClass>(race.getEvent().getName(),
getDominantBoatClass(competitorClassList));
return defaultRegattaNameAndBoatClass;
}
@@ -62,7 +62,7 @@ public class RegattaImpl extends NamedImpl implements Regatta, RaceColumnListene
private static final Logger logger = Logger.getLogger(RegattaImpl.class.getName());
private static final long serialVersionUID = 6509564189552478869L;
private final Set<RaceDefinition> races;
private Set<RaceDefinition> races;
private final BoatClass boatClass;
private transient Set<RegattaListener> regattaListeners;
private List<? extends Series> series;
@@ -185,6 +185,7 @@ public class RegattaImpl extends NamedImpl implements Regatta, RaceColumnListene
MasterDataImportInformation masterDataImportInformation = ongoingMasterDataImportInformation.get();
if (masterDataImportInformation != null) {
raceLogStore = masterDataImportInformation.getRaceLogStore();
races = new HashSet<RaceDefinition>();
} else {
raceLogStore = EmptyRaceLogStore.INSTANCE;
}
@@ -1,10 +1,11 @@
package com.sap.sailing.domain.leaderboard;
import java.util.HashMap;
import java.util.Collections;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.WeakHashMap;
import java.util.concurrent.ConcurrentHashMap;
import com.sap.sailing.domain.base.Competitor;
import com.sap.sailing.domain.base.CompetitorChangeListener;
@@ -29,6 +30,7 @@ import com.sap.sailing.domain.tracking.RaceChangeListener;
import com.sap.sailing.domain.tracking.TrackedRace;
import com.sap.sailing.domain.tracking.TrackedRaceStatus;
import com.sap.sailing.domain.tracking.Wind;
import com.sap.sailing.util.impl.ConcurrentWeakHashMap;
import com.sap.sailing.util.impl.LockUtil;
import com.sap.sailing.util.impl.NamedReentrantReadWriteLock;
@@ -45,7 +47,7 @@ public class LeaderboardCacheManager {
private final WeakHashMap<Leaderboard, CacheInvalidationUponScoreCorrectionListener> scoreCorrectionListeners;
private final NamedReentrantReadWriteLock scoreCorrectionAndCompetitorChangeListenersLock;
private final WeakHashMap<Leaderboard, CacheInvalidationUponCompetitorChangeListener> competitorChangeListeners;
private final WeakHashMap<Leaderboard, Map<TrackedRace, Set<CacheInvalidationListener>>> invalidationListenersPerLeaderboard;
private final ConcurrentWeakHashMap<Leaderboard, ConcurrentHashMap<TrackedRace, Set<CacheInvalidationListener>>> invalidationListenersPerLeaderboard;
private final WeakHashMap<Leaderboard, RaceColumnListener> raceColumnListeners;
private class CacheInvalidationListener implements RaceChangeListener {
@@ -103,6 +105,16 @@ public class LeaderboardCacheManager {
removeFromCache(leaderboard);
}
@Override
public void waypointAdded(int zeroBasedIndex, Waypoint waypointThatGotAdded) {
removeFromCache(leaderboard);
}
@Override
public void waypointRemoved(int zeroBasedIndex, Waypoint waypointThatGotRemoved) {
removeFromCache(leaderboard);
}
@Override
public void delayToLiveChanged(long delayToLiveInMillis) {
removeFromCache(leaderboard);
@@ -209,7 +221,7 @@ public class LeaderboardCacheManager {
public LeaderboardCacheManager(LeaderboardCache leaderboardCache) {
this.leaderboardCache = leaderboardCache;
this.invalidationListenersPerLeaderboard = new WeakHashMap<>();
this.invalidationListenersPerLeaderboard = new ConcurrentWeakHashMap<>();
this.raceColumnListeners = new WeakHashMap<Leaderboard, RaceColumnListener>();
this.scoreCorrectionListeners = new WeakHashMap<>();
this.scoreCorrectionAndCompetitorChangeListenersLock = new NamedReentrantReadWriteLock(
@@ -218,11 +230,10 @@ public class LeaderboardCacheManager {
}
private void removeFromCache(Leaderboard leaderboard) {
synchronized (invalidationListenersPerLeaderboard) {
Map<TrackedRace, Set<CacheInvalidationListener>> listenersMap = invalidationListenersPerLeaderboard
.remove(leaderboard);
if (listenersMap != null) {
for (Map.Entry<TrackedRace, Set<CacheInvalidationListener>> e : listenersMap.entrySet()) {
ConcurrentHashMap<TrackedRace, Set<CacheInvalidationListener>> listenersMap = invalidationListenersPerLeaderboard.remove(leaderboard);
if (listenersMap != null) {
for (Map.Entry<TrackedRace, Set<CacheInvalidationListener>> e : listenersMap.entrySet()) {
synchronized (e.getValue()) { // the Set is a Collections.synchronizedSet, and synchronization is required for iteration
for (CacheInvalidationListener listener : e.getValue()) {
listener.removeFromTrackedRace();
}
@@ -305,17 +316,7 @@ public class LeaderboardCacheManager {
@Override
public void trackedRaceUnlinked(RaceColumn raceColumn, Fleet fleet, TrackedRace trackedRace) {
removeFromCache(leaderboard);
Map<TrackedRace, Set<CacheInvalidationListener>> listenersMap = invalidationListenersPerLeaderboard
.get(leaderboard);
if (listenersMap != null) {
Set<CacheInvalidationListener> listeners = listenersMap.get(trackedRace);
if (listeners != null) {
for (CacheInvalidationListener listener : listeners) {
listener.removeFromTrackedRace();
}
}
}
removeFromCache(leaderboard); // removes all listeners from invalidationListenersPerLeaderboard and from their TrackedRaces
}
@Override
@@ -393,24 +394,20 @@ public class LeaderboardCacheManager {
}
private void registerListener(final Leaderboard leaderboard, TrackedRace trackedRace) {
Map<TrackedRace, Set<CacheInvalidationListener>> invalidationListeners;
ConcurrentHashMap<TrackedRace, Set<CacheInvalidationListener>> invalidationListeners;
final CacheInvalidationListener listener;
synchronized (invalidationListenersPerLeaderboard) {
listener = new CacheInvalidationListener(leaderboard, trackedRace);
trackedRace.addListener(listener);
invalidationListeners = invalidationListenersPerLeaderboard.get(leaderboard);
if (invalidationListeners == null) {
invalidationListeners = new HashMap<TrackedRace, Set<CacheInvalidationListener>>();
invalidationListenersPerLeaderboard.put(leaderboard, invalidationListeners);
}
listener = new CacheInvalidationListener(leaderboard, trackedRace);
trackedRace.addListener(listener);
invalidationListeners = invalidationListenersPerLeaderboard.get(leaderboard);
if (invalidationListeners == null) {
invalidationListeners = new ConcurrentHashMap<TrackedRace, Set<CacheInvalidationListener>>();
invalidationListenersPerLeaderboard.put(leaderboard, invalidationListeners);
}
Set<CacheInvalidationListener> listeners = invalidationListeners.get(trackedRace);
if (listeners == null) {
listeners = new HashSet<CacheInvalidationListener>();
listeners = Collections.synchronizedSet(new HashSet<CacheInvalidationListener>());
invalidationListeners.put(trackedRace, listeners);
}
listeners.add(listener);
}
}
@@ -287,6 +287,16 @@ public abstract class AbstractSimpleLeaderboardImpl implements Leaderboard, Race
invalidateCacheAndRemoveThisListenerFromTrackedRace();
}
@Override
public void waypointAdded(int zeroBasedIndex, Waypoint waypointThatGotAdded) {
invalidateCacheAndRemoveThisListenerFromTrackedRace();
}
@Override
public void waypointRemoved(int zeroBasedIndex, Waypoint waypointThatGotRemoved) {
invalidateCacheAndRemoveThisListenerFromTrackedRace();
}
@Override
public void statusChanged(TrackedRaceStatus newStatus) {
// when the status changes away from LOADING, calculations may start or resume, making it necessary to clear the cache
@@ -3,13 +3,14 @@ package com.sap.sailing.domain.tracking;
import java.util.Map;
import com.sap.sailing.domain.base.Competitor;
import com.sap.sailing.domain.base.CourseListener;
import com.sap.sailing.domain.base.Mark;
import com.sap.sailing.domain.base.Waypoint;
import com.sap.sailing.domain.common.TimePoint;
import com.sap.sailing.domain.common.WindSource;
public interface RaceChangeListener {
public interface RaceChangeListener extends CourseListener {
void competitorPositionChanged(GPSFixMoving fix, Competitor competitor);
void markPositionChanged(GPSFix fix, Mark mark);
@@ -578,8 +578,11 @@ public interface TrackedRace extends Serializable {
RaceLog getRaceLog(Serializable identifier);
/**
* a setter for the listener on course design changes. The listener is mostly part of the tracking provider adapter.
* @param listener the listener to operate with.
* A setter for the listener on course design changes suggested by one of the {@link RaceLog}s attached to this
* race. The listener is mostly part of the tracking provider adapter.
*
* @param listener
* the listener to operate with.
*/
void addCourseDesignChangedListener(CourseDesignChangedListener listener);
@@ -59,5 +59,13 @@ public abstract class AbstractRaceChangeListener implements RaceChangeListener {
@Override
public void delayToLiveChanged(long delayToLiveInMillis) {
}
@Override
public void waypointAdded(int zeroBasedIndex, Waypoint waypointThatGotAdded) {
}
@Override
public void waypointRemoved(int zeroBasedIndex, Waypoint waypointThatGotRemoved) {
}
}
@@ -1,64 +0,0 @@
package com.sap.sailing.domain.tracking.impl;
import java.util.Map;
import com.sap.sailing.domain.base.Competitor;
import com.sap.sailing.domain.base.Mark;
import com.sap.sailing.domain.base.Waypoint;
import com.sap.sailing.domain.common.TimePoint;
import com.sap.sailing.domain.common.WindSource;
import com.sap.sailing.domain.tracking.GPSFix;
import com.sap.sailing.domain.tracking.GPSFixMoving;
import com.sap.sailing.domain.tracking.MarkPassing;
import com.sap.sailing.domain.tracking.RaceChangeListener;
import com.sap.sailing.domain.tracking.TrackedRaceStatus;
import com.sap.sailing.domain.tracking.Wind;
public class BaseRaceChangeListener implements RaceChangeListener {
@Override
public void competitorPositionChanged(GPSFixMoving fix, Competitor competitor) {
}
@Override
public void markPositionChanged(GPSFix fix, Mark mark) {
}
@Override
public void markPassingReceived(Competitor competitor, Map<Waypoint, MarkPassing> oldMarkPassings,
Iterable<MarkPassing> markPassings) {
}
@Override
public void speedAveragingChanged(long oldMillisecondsOverWhichToAverage, long newMillisecondsOverWhichToAverage) {
}
@Override
public void windDataReceived(Wind wind, WindSource windSource) {
}
@Override
public void windDataRemoved(Wind wind, WindSource windSource) {
}
@Override
public void windAveragingChanged(long oldMillisecondsOverWhichToAverage, long newMillisecondsOverWhichToAverage) {
}
@Override
public void raceTimesChanged(TimePoint startOfTracking, TimePoint endOfTracking, TimePoint startTimeReceived) {
}
@Override
public void delayToLiveChanged(long delayToLiveInMillis) {
}
@Override
public void windSourcesToExcludeChanged(Iterable<? extends WindSource> windSourcesToExclude) {
}
@Override
public void statusChanged(TrackedRaceStatus newStatus) {
}
}
@@ -85,6 +85,15 @@ public class CrossTrackErrorCache extends AbstractRaceChangeListener {
private static final long serialVersionUID = 4884868659665863604L;
public void deleteAll() {
lockForWrite();
try {
getInternalRawFixes().clear();
} finally {
unlockAfterWrite();
}
}
public void deleteAllLaterThan(TimePoint from) {
// TODO use a specialized ArrayList in a specialized ArrayListNavigableSet and then make removeRange public
lockForWrite();
@@ -171,7 +180,11 @@ public class CrossTrackErrorCache extends AbstractRaceChangeListener {
FromTimePointToEndUpdateInterval updateInterval) {
CrossTrackErrorSumAndNumberOfFixesTrack result;
if (oldValue != null) {
oldValue.deleteAllLaterThan(updateInterval.getFrom());
if (updateInterval == null) {
oldValue.deleteAll();
} else {
oldValue.deleteAllLaterThan(updateInterval.getFrom());
}
computedCacheUpdate.lockForRead();
try {
for (CrossTrackErrorSumAndNumberOfFixes entry : computedCacheUpdate.getRawFixes()) {
@@ -434,6 +447,27 @@ public class CrossTrackErrorCache extends AbstractRaceChangeListener {
}
}
@Override
public void waypointAdded(int zeroBasedIndex, Waypoint waypointThatGotAdded) {
invalidate();
}
/**
* Invalidates all cache contents for all competitors from the beginning of time
*/
private void invalidate() {
final List<Competitor> shuffledCompetitors = new ArrayList<>(cachePerCompetitor.keySet());
Collections.shuffle(shuffledCompetitors);
for (Competitor competitor : shuffledCompetitors) {
cachePerCompetitor.triggerUpdate(competitor, null /* meaning: from the beginning of time */);
}
}
@Override
public void waypointRemoved(int zeroBasedIndex, Waypoint waypointThatGotRemoved) {
invalidate();
}
@Override
public String toString() {
return "CrossTrackErrorCache for competitors "+cachePerCompetitor.keySet();
@@ -356,6 +356,48 @@ DynamicTrackedRace, GPSTrackListener<Competitor, GPSFixMoving> {
}
}
private void notifyListenersWaypointAdded(int zeroBasedIndex, Waypoint waypointThatGotAdded) {
RaceChangeListener[] listeners;
synchronized (getListeners()) {
listeners = getListeners().toArray(new RaceChangeListener[getListeners().size()]);
}
for (RaceChangeListener listener : listeners) {
try {
listener.waypointAdded(zeroBasedIndex, waypointThatGotAdded);
} catch (Exception e) {
logger.log(Level.SEVERE, "RaceChangeListener " + listener + " threw exception " + e.getMessage());
logger.log(Level.SEVERE, "notifyListenersWaypointAdded(int, Waypoint)", e);
}
}
}
private void notifyListenersWaypointRemoved(int zeroBasedIndex, Waypoint waypointThatGotRemoved) {
RaceChangeListener[] listeners;
synchronized (getListeners()) {
listeners = getListeners().toArray(new RaceChangeListener[getListeners().size()]);
}
for (RaceChangeListener listener : listeners) {
try {
listener.waypointRemoved(zeroBasedIndex, waypointThatGotRemoved);
} catch (Exception e) {
logger.log(Level.SEVERE, "RaceChangeListener " + listener + " threw exception " + e.getMessage());
logger.log(Level.SEVERE, "notifyListenersWaypointRemoved(int, Waypoint)", e);
}
}
}
@Override
public void waypointAdded(int zeroBasedIndex, Waypoint waypointThatGotAdded) {
super.waypointAdded(zeroBasedIndex, waypointThatGotAdded);
notifyListenersWaypointAdded(zeroBasedIndex, waypointThatGotAdded);
}
@Override
public void waypointRemoved(int zeroBasedIndex, Waypoint waypointThatGotRemoved) {
super.waypointRemoved(zeroBasedIndex, waypointThatGotRemoved);
notifyListenersWaypointRemoved(zeroBasedIndex, waypointThatGotRemoved);
}
private void notifyListeners(GPSFix fix, Mark mark) {
RaceChangeListener[] listeners;
synchronized (getListeners()) {
@@ -677,6 +677,16 @@ public class TrackBasedEstimationWindTrackImpl extends VirtualWindTrackImpl impl
clearCache();
}
@Override
public void waypointAdded(int zeroBasedIndex, Waypoint waypointThatGotAdded) {
clearCache();
}
@Override
public void waypointRemoved(int zeroBasedIndex, Waypoint waypointThatGotRemoved) {
clearCache();
}
@Override
public void markPositionChanged(GPSFix fix, Mark mark) {
assert fix != null && fix.getTimePoint() != null;
@@ -198,6 +198,16 @@ public class TrackedLegImpl implements TrackedLeg, RaceChangeListener {
clearCaches();
}
@Override
public void waypointAdded(int zeroBasedIndex, Waypoint waypointThatGotAdded) {
clearCaches(); // necessary because the competitor tracks ordered by rank may change for legs adjacent to the waypoint added
}
@Override
public void waypointRemoved(int zeroBasedIndex, Waypoint waypointThatGotRemoved) {
clearCaches(); // necessary because the competitor tracks ordered by rank may change for legs adjacent to the waypoint removed
}
@Override
public void statusChanged(TrackedRaceStatus newStatus) {
// no-op; the leg doesn't mind the tracked race's status being updated
@@ -2026,6 +2026,7 @@ public abstract class TrackedRaceImpl extends TrackedRaceWithWindEssentials impl
GPSFixMoving next = approximationPointsIter.next();
speedWithBearingOnApproximationFromCurrentToNext = current.getSpeedAndBearingRequiredToReach(next);
// compute course change on "approximation track"
// FIXME bug 2009: when a maneuver (particularly a penalty circle) is executed at high turn rates, approximations may lead to turns >180deg, hence inferred to turn the wrong way; need to loop across the non-approximated fixes here!
CourseChange courseChange = speedWithBearingOnApproximationFromPreviousToCurrent
.getCourseChangeRequiredToReach(speedWithBearingOnApproximationFromCurrentToNext);
com.sap.sse.common.Util.Pair<GPSFixMoving, CourseChange> courseChangeAtFix = new com.sap.sse.common.Util.Pair<GPSFixMoving, CourseChange>(current,
@@ -8,7 +8,8 @@ Bundle-Vendor: SAP
Bundle-RequiredExecutionEnvironment: JavaSE-1.7
Import-Package: com.sap.sailing.resultimport,
com.sap.sailing.resultimport.impl,
org.osgi.framework;version="1.3.0"
org.osgi.framework;version="1.3.0",
org.osgi.util.tracker;version="1.5.1"
Bundle-ActivationPolicy: lazy
Require-Bundle: com.sap.sailing.domain.common,
com.sap.sailing.domain,
@@ -4,9 +4,11 @@ import java.util.logging.Logger;
import org.osgi.framework.BundleActivator;
import org.osgi.framework.BundleContext;
import org.osgi.util.tracker.ServiceTracker;
import com.sap.sailing.domain.common.ScoreCorrectionProvider;
import com.sap.sailing.resultimport.ResultUrlRegistry;
import com.sap.sailing.resultimport.impl.ResultUrlRegistryServiceTrackerCustomizer;
public class Activator implements BundleActivator {
private static final Logger logger = Logger.getLogger(Activator.class.getName());
@@ -14,6 +16,8 @@ public class Activator implements BundleActivator {
private static final String SCAN_DIR_PATH_PROPERTY_NAME = "freg.results";
private static final String DEFAULT_SCAN_DIR = "fregresults";
private ServiceTracker<ResultUrlRegistry, ResultUrlRegistry> resultUrlRegistryServiceTracker;
/*
* For testing, consider using the following URLs:
* allUrls.add(new URL("http://www.axel-uhl.de/freg/freg_html_export_sample.html"));
@@ -24,11 +28,26 @@ public class Activator implements BundleActivator {
if (scanDirPath == null) {
scanDirPath = System.getProperty(SCAN_DIR_PATH_PROPERTY_NAME, DEFAULT_SCAN_DIR);
}
final ScoreCorrectionProviderImpl service = new ScoreCorrectionProviderImpl(ResultUrlRegistry.INSTANCE);
bundleContext.registerService(ScoreCorrectionProvider.class, service, /* properties */null);
logger.info("Scanning " + scanDirPath + " for official result lists of " + service.getName());
logger.info("Scanning " + scanDirPath + " for official result lists of "
+ ScoreCorrectionProviderImpl.PROVIDER_NAME);
resultUrlRegistryServiceTracker = new ServiceTracker<>(bundleContext, ResultUrlRegistry.class,
new ResultUrlRegistryServiceTrackerCustomizer(bundleContext) {
@Override
protected ScoreCorrectionProvider configureScoreCorrectionProvider(
ResultUrlRegistry resultUrlRegistry) {
final ScoreCorrectionProviderImpl service = new ScoreCorrectionProviderImpl(resultUrlRegistry);
return service;
}
});
resultUrlRegistryServiceTracker.open();
}
public void stop(BundleContext bundleContext) throws Exception {
resultUrlRegistryServiceTracker.close();
}
}
@@ -6,11 +6,9 @@ import java.util.List;
import com.google.gwt.core.client.GWT;
import com.google.gwt.uibinder.client.UiBinder;
import com.google.gwt.uibinder.client.UiField;
import com.google.gwt.user.client.ui.Anchor;
import com.google.gwt.user.client.ui.Composite;
import com.google.gwt.user.client.ui.Widget;
import com.sap.sailing.gwt.home.client.place.event.header.EventHeader;
import com.sap.sailing.gwt.home.client.place.event.header.EventHeaderResources;
import com.sap.sailing.gwt.home.client.place.event.media.EventMedia;
import com.sap.sailing.gwt.home.client.place.event.overview.EventOverview;
import com.sap.sailing.gwt.home.client.place.event.regattalist.EventRegattaList;
@@ -223,15 +223,16 @@ public class CompetitorSelectionModel implements CompetitorSelectionProvider {
@Override
public Color getColor(CompetitorDTO competitor) {
Color result = null;
final Color result;
if (allCompetitors.contains(competitor)) {
if (competitor.getColor() != null) {
result = competitor.getColor();
} else {
result = competitorsColorMap.getColorByID(competitor);
}
} else {
result = null;
}
return result;
}
@@ -1044,7 +1044,7 @@ public interface StringMessages extends Messages {
String eventLogoImageURL();
String showPingMarkMappings();
String regattaNameMustNotContainSlashes();
String showNumberOfRacesCompleted();
String racesCompleted();
String racesCompletedTooltip();
String showNumberOfRacesScored();
String racesScored();
String racesScoredTooltip();
}
@@ -1030,6 +1030,6 @@ eventOfficialWebsiteURL=Official Website URL
eventLogoImageURL=Logo Image URL
showPingMarkMappings=Show Mappings for pinged Marks
regattaNameMustNotContainSlashes=Regatta name must not contain slashes
showNumberOfRacesCompleted=Show number of races completed
racesCompleted=Races completed
racesCompletedTooltip=Number of races the competitor has completed in this leaderboard.
showNumberOfRacesScored=Number of races scored
racesScored=Races scored
racesScoredTooltip=Number of races the competitor has completed or gotten a score for in this leaderboard.
@@ -1024,6 +1024,6 @@ eventOfficialWebsiteURL=URL der offiziellen Veranstaltungs-Website
eventLogoImageURL=URL des Veranstaltungs-Logos
showPingMarkMappings=Mappings für gepingte Marks zeigen
regattaNameMustNotContainSlashes=Regattaname darf keine Schrägstriche enthalten
showNumberOfRacesCompleted=Anzahl vollendeter Rennen
racesCompleted=Vollendete Rennen
racesCompletedTooltip=Anzahl von Rennen, die der Segler vollendet hat
showNumberOfRacesScored=Anzahl bepunkteter Rennen
racesScored=Bepunktete Rennen
racesScoredTooltip=Anzahl von Rennen, die der Segler vollendet oder für die er Punkte bekommen hat
@@ -982,7 +982,7 @@ pleaseSelectAScoringResult=Please select a scoring result...
eventOfficialWebsiteURL=Official Website URL
eventLogoImageURL=Logo Image URL
showPingMarkMappings=Show Mappings for pinged Marks
showNumberOfRacesCompleted=Показать количество завершенных гонок
racesCompleted=Завершенные гонки
racesCompletedTooltip=Количество гонок завершенное участником в данной таблице лидеров
regattaNameMustNotContainSlashes=Regatta name must not contain slashes
showNumberOfRacesScored=Показать количество завершенных гонок
racesScored=Завершенные гонки
racesScoredTooltip=Количество гонок завершенное участником в данной таблице лидеров
regattaNameMustNotContainSlashes=Regatta name must not contain slashes
@@ -1336,7 +1336,7 @@ public class LeaderboardPanel extends SimplePanel implements TimeListener, PlayS
@Override
public SafeHtmlHeader getHeader() {
return new SafeHtmlHeaderWithTooltip(SafeHtmlUtils.fromString(stringMessages.racesCompleted()), stringMessages.racesCompletedTooltip());
return new SafeHtmlHeaderWithTooltip(SafeHtmlUtils.fromString(stringMessages.racesScored()), stringMessages.racesScoredTooltip());
}
}
@@ -180,8 +180,8 @@ public class LeaderboardSettingsDialogComponent implements SettingsDialogCompone
overallDetailCheckboxes);
overallDetailDialogContent.add(checkbox);
}
showOverallColumnWithNumberOfRacesSailedPerCompetitorCheckBox = dialog.createCheckbox(stringMessages.showNumberOfRacesCompleted());
dialog.addTooltip(showOverallColumnWithNumberOfRacesSailedPerCompetitorCheckBox, stringMessages.showNumberOfRacesCompleted());
showOverallColumnWithNumberOfRacesSailedPerCompetitorCheckBox = dialog.createCheckbox(stringMessages.showNumberOfRacesScored());
dialog.addTooltip(showOverallColumnWithNumberOfRacesSailedPerCompetitorCheckBox, stringMessages.showNumberOfRacesScored());
showOverallColumnWithNumberOfRacesSailedPerCompetitorCheckBox.setValue(showOverallColumnWithNumberOfRacesSailedPerCompetitor);
overallDetailDialogContent.add(showOverallColumnWithNumberOfRacesSailedPerCompetitorCheckBox);
overallDetailDialog.add(overallDetailDialogContent);
@@ -5,7 +5,13 @@ import java.util.Collections;
import java.util.List;
import com.google.gwt.core.client.GWT;
import com.google.gwt.core.client.Scheduler;
import com.google.gwt.dom.client.NativeEvent;
import com.google.gwt.dom.client.Style.Unit;
import com.google.gwt.user.client.Command;
import com.google.gwt.user.client.Event;
import com.google.gwt.user.client.Event.NativePreviewEvent;
import com.google.gwt.user.client.Event.NativePreviewHandler;
import com.google.gwt.user.client.Window;
import com.google.gwt.user.client.rpc.ServiceDefTarget;
import com.google.gwt.user.client.ui.DockLayoutPanel;
@@ -59,6 +65,8 @@ public class RaceBoardEntryPoint extends AbstractEntryPoint {
private final MediaServiceAsync mediaService = GWT.create(MediaService.class);
private final UserManagementServiceAsync userManagementService = GWT.create(UserManagementService.class);
private boolean toolbarAndLogoAndTitleBarHidden;
@Override
protected void doOnModuleLoad() {
super.doOnModuleLoad();
@@ -92,9 +100,10 @@ public class RaceBoardEntryPoint extends AbstractEntryPoint {
final boolean canReplayWhileLiveIsPossible = GwtHttpRequestUtils.getBooleanParameter(RaceBoardViewConfiguration.PARAM_CAN_REPLAY_DURING_LIVE_RACES, false);
final boolean autoSelectMedia = GwtHttpRequestUtils.getBooleanParameter(RaceBoardViewConfiguration.PARAM_AUTOSELECT_MEDIA, false);
final boolean showMapControls = GwtHttpRequestUtils.getBooleanParameter(RaceBoardViewConfiguration.PARAM_VIEW_SHOW_MAPCONTROLS, true /* default*/);
raceboardViewConfig = new RaceBoardViewConfiguration(activeCompetitorsFilterSetName, showLeaderboard, showWindChart,
showCompetitorsChart, canReplayWhileLiveIsPossible, autoSelectMedia);
final boolean showNavigationPanel = GwtHttpRequestUtils.getBooleanParameter(RaceBoardViewConfiguration.PARAM_VIEW_SHOW_NAVIGATION_PANEL, true /* default */);
raceboardViewConfig = new RaceBoardViewConfiguration(activeCompetitorsFilterSetName, showLeaderboard,
showWindChart, showCompetitorsChart, canReplayWhileLiveIsPossible, autoSelectMedia, showNavigationPanel);
final ParallelExecutionCallback<List<String>> getLeaderboardNamesCallback = new ParallelExecutionCallback<List<String>>();
final ParallelExecutionCallback<List<RegattaDTO>> getRegattasCallback = new ParallelExecutionCallback<List<RegattaDTO>>();
final ParallelExecutionCallback<LeaderboardGroupDTO> getLeaderboardGroupByNameCallback = new ParallelExecutionCallback<LeaderboardGroupDTO>();
@@ -165,7 +174,7 @@ public class RaceBoardEntryPoint extends AbstractEntryPoint {
RaceBoardPanel raceBoardPanel = new RaceBoardPanel(sailingService, mediaService, user, timer, raceSelectionModel, leaderboardName,
leaderboardGroupName, raceboardViewConfig, RaceBoardEntryPoint.this, stringMessages, userAgent, raceTimesInfoProvider, showMapControls);
raceBoardPanel.fillRegattas(regattas);
createRaceBoardInOneScreenMode(raceBoardPanel);
createRaceBoardInOneScreenMode(raceBoardPanel, raceboardViewConfig);
}
private RaceDTO findRace(String regattaName, String raceName, List<RegattaDTO> regattas) {
@@ -217,21 +226,47 @@ public class RaceBoardEntryPoint extends AbstractEntryPoint {
return logoAndTitlePanel;
}
private void createRaceBoardInOneScreenMode(RaceBoardPanel raceBoardPanel) {
DockLayoutPanel p = new DockLayoutPanel(Unit.PX);
private void createRaceBoardInOneScreenMode(RaceBoardPanel raceBoardPanel,
RaceBoardViewConfiguration raceboardViewConfiguration) {
final DockLayoutPanel p = new DockLayoutPanel(Unit.PX);
RootLayoutPanel.get().add(p);
Panel toolbarPanel = raceBoardPanel.getToolbarPanel();
final Panel toolbarPanel = raceBoardPanel.getToolbarPanel();
if (!UserAgentChecker.INSTANCE.isUserAgentSupported(userAgent)) {
HTML lbl = new HTML(stringMessages.warningBrowserUnsupported());
lbl.setStyleName("browserOptimizedMessage");
toolbarPanel.add(lbl);
}
FlowPanel logoAndTitlePanel = createLogoAndTitlePanel(raceBoardPanel);
final FlowPanel logoAndTitlePanel = createLogoAndTitlePanel(raceBoardPanel);
FlowPanel timePanel = createTimePanel(raceBoardPanel);
p.addNorth(logoAndTitlePanel, 68);
p.addNorth(toolbarPanel, 40);
p.addSouth(timePanel, 90);
toolbarAndLogoAndTitleBarHidden = false;
if (!raceboardViewConfiguration.isShowNavigationPanel()) {
p.setWidgetHidden(toolbarPanel, true);
globalNavigationPanel.setVisible(false);
toolbarAndLogoAndTitleBarHidden = true;
}
Event.addNativePreviewHandler(new NativePreviewHandler() {
@Override
public void onPreviewNativeEvent(NativePreviewEvent event) {
NativeEvent ne = event.getNativeEvent();
if ("keydown".equals(ne.getType()) && ne.getCtrlKey()
&& (ne.getKeyCode() == 'm' || ne.getKeyCode() == 'M')) {
ne.preventDefault();
Scheduler.get().scheduleDeferred(new Command() {
@Override
public void execute() {
p.setWidgetHidden(toolbarPanel, !toolbarAndLogoAndTitleBarHidden);
globalNavigationPanel.setVisible(toolbarAndLogoAndTitleBarHidden);
toolbarAndLogoAndTitleBarHidden = !toolbarAndLogoAndTitleBarHidden;
}
});
}
}
});
p.addSouth(timePanel, 90);
p.add(raceBoardPanel);
p.addStyleName("dockLayoutPanel");
}
}
}
@@ -163,6 +163,7 @@ public class RaceBoardPanel extends SimplePanel implements RegattasDisplayer, Ra
componentControlsPanel = new FlowPanel();
componentControlsPanel.addStyleName("raceBoardNavigation");
toolbarPanel.add(componentControlsPanel);
viewControlsPanel = new FlowPanel();
viewControlsPanel.addStyleName("raceBoardControls");
toolbarPanel.add(viewControlsPanel);
@@ -12,6 +12,7 @@ public class RaceBoardViewConfiguration {
private String activeCompetitorsFilterSetName;
private boolean canReplayDuringLiveRaces;
private final boolean autoSelectMedia;
private final boolean showNavigationPanel;
public static final String PARAM_VIEW_MODE = "viewMode";
public static final String PARAM_VIEW_SHOW_LEADERBOARD = "viewShowLeaderboard";
@@ -28,16 +29,19 @@ public class RaceBoardViewConfiguration {
showWindChart = false;
showCompetitorsChart = false;
autoSelectMedia = false;
showNavigationPanel = true;
}
public RaceBoardViewConfiguration(String activeCompetitorsFilterSetName, boolean showLeaderboard,
boolean showWindChart, boolean showCompetitorsChart, boolean canReplayDuringLiveRaces, boolean autoSelectMedia) {
boolean showWindChart, boolean showCompetitorsChart, boolean canReplayDuringLiveRaces,
boolean autoSelectMedia, boolean showNavigationPanel) {
this.activeCompetitorsFilterSetName = activeCompetitorsFilterSetName;
this.showLeaderboard = showLeaderboard;
this.showWindChart = showWindChart;
this.showCompetitorsChart = showCompetitorsChart;
this.canReplayDuringLiveRaces = canReplayDuringLiveRaces;
this.autoSelectMedia = autoSelectMedia;
this.autoSelectMedia = autoSelectMedia;
this.showNavigationPanel = showNavigationPanel;
}
public boolean isShowLeaderboard() {
@@ -64,4 +68,8 @@ public class RaceBoardViewConfiguration {
return autoSelectMedia;
}
public boolean isShowNavigationPanel() {
return showNavigationPanel;
}
}
@@ -31,7 +31,7 @@ public class RaceDetailPanel extends SimplePanel {
d = -d;
}
NumberFormat decimalFormat = NumberFormat.getFormat("##.###");
return "" + d + '\u00B0' + m + '\u2032' + decimalFormat.format(s) + '\u2033'; // add º, ', " symbols
return "" + d + '\u00B0' + m + '\u2032' + decimalFormat.format(s) + '\u2033'; // add �, ', " symbols
}
private static final int MAX_PROCEDURE_FIELDS = 2;
@@ -50,7 +50,9 @@ public class RaceDetailPanel extends SimplePanel {
private final Label finishTimeLabel = new Label();
private final Label finishDurationLabel = new Label();
private final Label protestTimeLabel = new Label();
private final Label protestDateLabel = new Label();
private final Label updateTimeLabel = new Label();
private final Label updateDateLabel = new Label();
private final Label vesselPositionLabel = new Label();
private final Label windLabel = new Label();
private final Label startProcedureLabel = new Label();
@@ -94,9 +96,9 @@ public class RaceDetailPanel extends SimplePanel {
basicsGrid.setWidget(2, 1, protestTimeLabel);
basicsGrid.setWidget(0, 2, startDateLabel);
basicsGrid.setWidget(1, 2, finishDurationLabel);
basicsGrid.setWidget(2, 2, new Label(""));
basicsGrid.setWidget(2, 2, protestDateLabel);
Grid managementGrid = new Grid(3, 2);
Grid managementGrid = new Grid(3, 3);
managementGrid.setCellSpacing(cellSpacing);
managementGrid.setWidget(0, 0, new Label("Last update at"));
managementGrid.setWidget(1, 0, new Label("Vessel position"));
@@ -104,6 +106,7 @@ public class RaceDetailPanel extends SimplePanel {
managementGrid.setWidget(0, 1, updateTimeLabel);
managementGrid.setWidget(1, 1, vesselPositionLabel);
managementGrid.setWidget(2, 1, windLabel);
managementGrid.setWidget(0, 2, updateDateLabel);
procedureGrid = new FlexTable();
procedureGrid.setCellSpacing(cellSpacing);
@@ -166,10 +169,18 @@ public class RaceDetailPanel extends SimplePanel {
.format(data.raceInfo.protestFinishTime);
protestTimeLabel.setText(protestTimeText);
String protestDateText = data.raceInfo.protestFinishTime == null ? "" : dateFormatter
.format(data.raceInfo.protestFinishTime);
protestDateLabel.setText(protestDateText);
String updateTimeText = data.raceInfo.lastUpdateTime == null ? "-" : timeFormatter
.format(data.raceInfo.lastUpdateTime);
updateTimeLabel.setText(updateTimeText);
String updateDateText = data.raceInfo.lastUpdateTime == null ? "" : dateFormatter
.format(data.raceInfo.lastUpdateTime);
updateDateLabel.setText(updateDateText);
String vesselPositionText = stringMessages.unknown();
String windText = stringMessages.unknown();
if (data.raceInfo.lastWind != null) {
@@ -186,27 +186,30 @@ public class RegattaOverviewPanel extends SimplePanel {
flexTable.setWidget(0, 0, eventVenueGrid);
flexTable.getCellFormatter().setVerticalAlignment(0, 0, HasVerticalAlignment.ALIGN_MIDDLE);
boolean showLeaderboardButton = Window.Location.getParameter("enableLeaderboard") != null
final boolean showLeaderboardButton = Window.Location.getParameter("enableLeaderboard") != null
&& Window.Location.getParameter("enableLeaderboard").equalsIgnoreCase("true");
if (showLeaderboardButton) {
leaderboardCheckBox = addLeaderboardEnablerButton();
leaderboardCheckBox.getElement().getStyle().setMarginLeft(20.0, Unit.PX);
leaderboardsTabPanel = new TabPanel();
leaderboardsTabPanel.setStyleName("RegattaOverview-Leaderboards");
mainPanel.add(leaderboardsTabPanel);
} else {
leaderboardCheckBox = null;
leaderboardsTabPanel = null;
}
HorizontalPanel refreshStartStopClockPanel = getRefreshStartStopClockPanel();
flexTable.setWidget(0, 1, refreshStartStopClockPanel);
mainPanel.add(flexTable);
mainPanel.add(regattaRaceStatesComponent);
if (showLeaderboardButton) {
leaderboardsTabPanel = new TabPanel();
leaderboardsTabPanel.setStyleName("RegattaOverview-Leaderboards");
leaderboardsTabPanel.setVisible(false);
mainPanel.add(leaderboardsTabPanel);
} else {
leaderboardsTabPanel = null;
}
onUpdateUI(uiUpdateTimer.getLiveTimePointAsDate());
}
@@ -254,8 +257,13 @@ public class RegattaOverviewPanel extends SimplePanel {
errorReporter, stringMessages, userAgent, /*showRaceDetails*/false);
leaderboardsTabPanel.add(leaderboardPanel, leaderboard.getDisplayName() + " " + stringMessages.leaderboard());
}
leaderboardsTabPanel.setVisible(true);
leaderboardsTabPanel.selectTab(0);
if (!result.isEmpty()) {
leaderboardsTabPanel.setVisible(true);
leaderboardsTabPanel.selectTab(0);
} else {
leaderboardCheckBox.setValue(false);
errorReporter.reportError("Error trying to load leaderboard. Event could not be associated to Regatta.");
}
}
@Override
public void onFailure(Throwable caught) {
@@ -16,6 +16,7 @@ import com.google.gwt.core.client.GWT;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.i18n.client.DateTimeFormat;
import com.google.gwt.i18n.client.DateTimeFormat.PredefinedFormat;
import com.google.gwt.json.client.JSONObject;
import com.google.gwt.json.client.JSONParser;
import com.google.gwt.json.client.JSONValue;
@@ -38,6 +39,7 @@ import com.google.gwt.user.client.ui.Label;
import com.google.gwt.user.client.ui.SimplePanel;
import com.google.gwt.user.client.ui.VerticalPanel;
import com.google.gwt.user.client.ui.Widget;
import com.google.gwt.user.datepicker.client.CalendarUtil;
import com.google.gwt.view.client.ListDataProvider;
import com.sap.sailing.domain.common.LeaderboardNameConstants;
import com.sap.sailing.domain.common.PassingInstruction;
@@ -83,6 +85,7 @@ public class RegattaRaceStatesComponent extends SimplePanel implements Component
private ListDataProvider<RegattaOverviewEntryDTO> regattaOverviewDataProvider;
private final VerticalPanel mainPanel;
private final DateTimeFormat timeFormatter = DateTimeFormat.getFormat("HH:mm:ss");
private final DateTimeFormat dateFormatter = DateTimeFormat.getFormat(PredefinedFormat.DATE_SHORT);
private final SailingServiceAsync sailingService;
private final StringMessages stringMessages;
@@ -207,6 +210,18 @@ public class RegattaRaceStatesComponent extends SimplePanel implements Component
}
}));
}
private String formatTime(Date time) {
String result = "-";
if (time != null) {
result = "";
if (! CalendarUtil.isSameDate(time, new Date())) {
result += dateFormatter.format(time) + " ";
}
result += timeFormatter.format(time);
}
return result;
}
private CellTable<RegattaOverviewEntryDTO> createRegattaTable() {
CellTable<RegattaOverviewEntryDTO> table = new CellTable<RegattaOverviewEntryDTO>(/* pageSize */10000, tableRes);
@@ -341,11 +356,7 @@ public class RegattaRaceStatesComponent extends SimplePanel implements Component
TextColumn<RegattaOverviewEntryDTO> raceStartTimeColumn = new TextColumn<RegattaOverviewEntryDTO>() {
@Override
public String getValue(RegattaOverviewEntryDTO entryDTO) {
String result = "-";
if (entryDTO.raceInfo.startTime != null) {
result = timeFormatter.format(entryDTO.raceInfo.startTime);
}
return result;
return formatTime(entryDTO.raceInfo.startTime);
}
};
raceStartTimeColumn.setHorizontalAlignment(HasHorizontalAlignment.ALIGN_CENTER);
@@ -459,11 +470,7 @@ public class RegattaRaceStatesComponent extends SimplePanel implements Component
TextColumn<RegattaOverviewEntryDTO> lastUpdateColumn = new TextColumn<RegattaOverviewEntryDTO>() {
@Override
public String getValue(RegattaOverviewEntryDTO entryDTO) {
String lastUpdateTime = "-";
if (entryDTO.raceInfo.lastUpdateTime != null) {
lastUpdateTime = timeFormatter.format(entryDTO.raceInfo.lastUpdateTime);
}
return lastUpdateTime;
return formatTime(entryDTO.raceInfo.lastUpdateTime);
}
};
lastUpdateColumn.setSortable(true);
@@ -396,6 +396,8 @@ public class SailingServiceImpl extends ProxiedRemoteServiceServlet implements S
private final ServiceTracker<ReplicationService, ReplicationService> replicationServiceTracker;
private final ServiceTracker<ResultUrlRegistry, ResultUrlRegistry> resultUrlRegistryServiceTracker;
private final ServiceTracker<ScoreCorrectionProvider, ScoreCorrectionProvider> scoreCorrectionProviderServiceTracker;
private final MongoObjectFactory mongoObjectFactory;
@@ -450,6 +452,7 @@ public class SailingServiceImpl extends ProxiedRemoteServiceServlet implements S
context = Activator.getDefault();
racingEventServiceTracker = createAndOpenRacingEventServiceTracker(context);
replicationServiceTracker = createAndOpenReplicationServiceTracker(context);
resultUrlRegistryServiceTracker = createAndOpenResultUrlRegistryServiceTracker(context);
swissTimingAdapterTracker = createAndOpenSwissTimingAdapterTracker(context);
tractracAdapterTracker = createAndOpenTracTracAdapterTracker(context);
raceLogTrackingAdapterTracker = createAndOpenRaceLogTrackingAdapterTracker(context);
@@ -555,6 +558,14 @@ public class SailingServiceImpl extends ProxiedRemoteServiceServlet implements S
return result;
}
protected ServiceTracker<ResultUrlRegistry, ResultUrlRegistry> createAndOpenResultUrlRegistryServiceTracker(
BundleContext context) {
ServiceTracker<ResultUrlRegistry, ResultUrlRegistry> result = new ServiceTracker<ResultUrlRegistry, ResultUrlRegistry>(
context, ResultUrlRegistry.class.getName(), null);
result.open();
return result;
}
/**
* Asks the OSGi system for registered score correction provider services
*/
@@ -1387,9 +1398,11 @@ public class SailingServiceImpl extends ProxiedRemoteServiceServlet implements S
public CompactRaceMapDataDTO getRaceMapData(RegattaAndRaceIdentifier raceIdentifier, Date date,
Map<String, Date> fromPerCompetitorIdAsString, Map<String, Date> toPerCompetitorIdAsString,
boolean extrapolate) throws NoWindException {
return new CompactRaceMapDataDTO(getBoatPositions(raceIdentifier, fromPerCompetitorIdAsString,
toPerCompetitorIdAsString, extrapolate), getCoursePositions(raceIdentifier, date), getCourseSidelines(raceIdentifier, date), getQuickRanks(
raceIdentifier, date));
final Map<CompetitorDTO, List<GPSFixDTO>> boatPositions = getBoatPositions(raceIdentifier, fromPerCompetitorIdAsString, toPerCompetitorIdAsString, extrapolate);
final CoursePositionsDTO coursePositions = getCoursePositions(raceIdentifier, date);
final List<SidelineDTO> courseSidelines = getCourseSidelines(raceIdentifier, date);
final List<QuickRankDTO> quickRanks = getQuickRanks(raceIdentifier, date);
return new CompactRaceMapDataDTO(boatPositions, coursePositions, courseSidelines, quickRanks);
}
/**
@@ -3387,8 +3400,9 @@ public class SailingServiceImpl extends ProxiedRemoteServiceServlet implements S
public List<String> getResultImportUrls(String resultProviderName) {
List<String> result = new ArrayList<String>();
ResultUrlProvider urlBasedScoreCorrectionProvider = getUrlBasedScoreCorrectionProvider(resultProviderName);
ResultUrlRegistry resultUrlRegistry = getResultUrlRegistry();
if (urlBasedScoreCorrectionProvider != null) {
Iterable<URL> allUrls = ResultUrlRegistry.INSTANCE.getResultUrls(resultProviderName);
Iterable<URL> allUrls = resultUrlRegistry.getResultUrls(resultProviderName);
for (URL url : allUrls) {
result.add(url.toString());
}
@@ -3399,9 +3413,10 @@ public class SailingServiceImpl extends ProxiedRemoteServiceServlet implements S
@Override
public void removeResultImportURLs(String resultProviderName, Set<String> toRemove) throws Exception {
ResultUrlProvider urlBasedScoreCorrectionProvider = getUrlBasedScoreCorrectionProvider(resultProviderName);
ResultUrlRegistry resultUrlRegistry = getResultUrlRegistry();
if (urlBasedScoreCorrectionProvider != null) {
for (String urlToRemove : toRemove) {
ResultUrlRegistry.INSTANCE.unregisterResultUrl(resultProviderName, new URL(urlToRemove));
resultUrlRegistry.unregisterResultUrl(resultProviderName, new URL(urlToRemove));
}
}
}
@@ -3410,8 +3425,13 @@ public class SailingServiceImpl extends ProxiedRemoteServiceServlet implements S
public void addResultImportUrl(String resultProviderName, String url) throws Exception {
ResultUrlProvider urlBasedScoreCorrectionProvider = getUrlBasedScoreCorrectionProvider(resultProviderName);
if (urlBasedScoreCorrectionProvider != null) {
ResultUrlRegistry.INSTANCE.registerResultUrl(resultProviderName, new URL(url));
ResultUrlRegistry resultUrlRegistry = getResultUrlRegistry();
resultUrlRegistry.registerResultUrl(resultProviderName, new URL(url));
}
}
private ResultUrlRegistry getResultUrlRegistry() {
return resultUrlRegistryServiceTracker.getService();
}
@Override
@@ -104,11 +104,13 @@ public class LeaderboardGroupPanel extends SimplePanel implements HasWelcomeWidg
private final boolean showRaceDetails;
private final boolean canReplayDuringLiveRaces;
private final boolean showMapControls;
private final boolean showNavigationPanel;
private final Timer timerForClientServerOffset;
public LeaderboardGroupPanel(SailingServiceAsync sailingService, StringMessages stringConstants,
ErrorReporter errorReporter, final String groupName, String root, String viewMode, boolean embedded,
boolean showRaceDetails, boolean canReplayDuringLiveRaces, boolean showMapControls) {
boolean showRaceDetails, boolean canReplayDuringLiveRaces, boolean showMapControls,
boolean showNavigationPanel) {
super();
this.isEmbedded = embedded;
this.showRaceDetails = showRaceDetails;
@@ -117,6 +119,7 @@ public class LeaderboardGroupPanel extends SimplePanel implements HasWelcomeWidg
this.sailingService = sailingService;
this.stringMessages = stringConstants;
this.errorReporter = errorReporter;
this.showNavigationPanel = showNavigationPanel;
this.root = (root == null || root.length() == 0) ? "leaderboardGroupPanel" : root;
this.viewMode = viewMode;
setWidth("95%");
@@ -424,6 +427,8 @@ public class LeaderboardGroupPanel extends SimplePanel implements HasWelcomeWidg
linkParams.put(RaceBoardViewConfiguration.PARAM_CAN_REPLAY_DURING_LIVE_RACES, "true");
}
linkParams.put(RaceBoardViewConfiguration.PARAM_VIEW_SHOW_MAPCONTROLS, Boolean.toString(showMapControls));
linkParams.put(RaceBoardViewConfiguration.PARAM_VIEW_SHOW_NAVIGATION_PANEL,
Boolean.toString(showNavigationPanel));
linkParams.put("regattaName", raceIdentifier.getRegattaName());
linkParams.put("leaderboardGroupName", leaderboardGroup.getName());
if (viewMode != null && !viewMode.isEmpty()) {
@@ -43,6 +43,8 @@ public class SpectatorEntryPoint extends AbstractEntryPoint implements RegattaRe
RaceBoardViewConfiguration.PARAM_CAN_REPLAY_DURING_LIVE_RACES, /* defaultValue */ false);
final boolean showMapControls = GwtHttpRequestUtils.getBooleanParameter(
RaceBoardViewConfiguration.PARAM_VIEW_SHOW_MAPCONTROLS, /* defaultValue */ true);
final boolean showNavigationPanel = GwtHttpRequestUtils.getBooleanParameter(
RaceBoardViewConfiguration.PARAM_VIEW_SHOW_NAVIGATION_PANEL, true /* default */);
boolean showRaceDetails = Window.Location.getParameter("showRaceDetails") != null
&& Window.Location.getParameter("showRaceDetails").equalsIgnoreCase("true");
final String groupName;
@@ -93,7 +95,8 @@ public class SpectatorEntryPoint extends AbstractEntryPoint implements RegattaRe
rootPanel.add(groupOverviewPanel);
} else {
LeaderboardGroupPanel groupPanel = new LeaderboardGroupPanel(sailingService, stringMessages, this,
groupName, root, viewModeParamValue, embedded, showRaceDetails, canReplayDuringLiveRaces, showMapControls);
groupName, root, viewModeParamValue, embedded, showRaceDetails, canReplayDuringLiveRaces,
showMapControls, showNavigationPanel);
groupAndFeedbackPanel.add(groupPanel);
if (!embedded) {
groupPanel.setWelcomeWidget(new SimpleWelcomeWidget(stringMessages.welcomeToSailingAnalytics(),
@@ -58,8 +58,9 @@ public class TVEntryPoint extends AbstractEntryPoint {
RaceBoardViewConfiguration.PARAM_VIEW_SHOW_COMPETITORSCHART, false /* default */);
String activeCompetitorsFilterSetName = GwtHttpRequestUtils.getStringParameter(RaceBoardViewConfiguration.PARAM_VIEW_COMPETITOR_FILTER, null /* default*/);
final boolean autoSelectMedia = GwtHttpRequestUtils.getBooleanParameter(RaceBoardViewConfiguration.PARAM_AUTOSELECT_MEDIA, false);
raceboardViewConfig = new RaceBoardViewConfiguration(activeCompetitorsFilterSetName,
showLeaderboard, showWindChart, showCompetitorsChart, /* canReplayWhileLiveIsPossible */ false, autoSelectMedia);
raceboardViewConfig = new RaceBoardViewConfiguration(activeCompetitorsFilterSetName, showLeaderboard,
showWindChart, showCompetitorsChart, /* canReplayWhileLiveIsPossible */false, autoSelectMedia,
showNavigationPanel);
sailingService.getLeaderboardNames(new AsyncCallback<List<String>>() {
@Override
@@ -5,7 +5,15 @@ Bundle-SymbolicName: com.sap.sailing.manage2sail.resultimport.test
Bundle-Version: 1.0.0.qualifier
Bundle-Vendor: SAP
Bundle-RequiredExecutionEnvironment: JavaSE-1.7
Import-Package: org.osgi.framework;version="1.5.0"
Import-Package: com.sap.sailing.domain.common,
com.sap.sailing.domain.leaderboard,
com.sap.sailing.domain.persistence,
com.sap.sailing.server,
com.sap.sailing.server.impl,
org.osgi.framework;version="1.5.0"
Fragment-Host: com.sap.sailing.manage2sail.resultimport
Require-Bundle: org.junit4;bundle-version="4.8.2",
com.sap.sse.common
com.sap.sse.common,
org.mockito.mockito-core;bundle-version="1.9.5",
org.objenesis;bundle-version="1.3.0",
org.hamcrest;bundle-version="1.1.0"
@@ -2,6 +2,7 @@ package com.sap.sailing.manage2sail.resultimport.test;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.mockito.Mockito.mock;
import java.io.File;
import java.io.FileInputStream;
@@ -25,11 +26,14 @@ import com.sap.sailing.domain.common.RegattaScoreCorrections;
import com.sap.sailing.domain.common.RegattaScoreCorrections.ScoreCorrectionsForRace;
import com.sap.sailing.domain.common.TimePoint;
import com.sap.sailing.domain.common.impl.MillisecondsTimePoint;
import com.sap.sailing.domain.persistence.DomainObjectFactory;
import com.sap.sailing.domain.persistence.MongoObjectFactory;
import com.sap.sailing.manage2sail.resultimport.ScoreCorrectionProviderImpl;
import com.sap.sailing.resultimport.ResultDocumentDescriptor;
import com.sap.sailing.resultimport.ResultDocumentProvider;
import com.sap.sailing.resultimport.ResultUrlRegistry;
import com.sap.sailing.resultimport.impl.ResultDocumentDescriptorImpl;
import com.sap.sailing.resultimport.impl.ResultUrlRegistryImpl;
import com.sap.sailing.xrr.resultimport.ParserFactory;
import com.sap.sailing.xrr.resultimport.schema.RegattaResults;
import com.sap.sse.common.Util;
@@ -95,8 +99,10 @@ public class ParserTest {
@Test
public void testScoreCorrectionProviderFeedingAndHasResults() throws IOException, SAXException,
ParserConfigurationException, JAXBException {
ScoreCorrectionProviderImpl scoreCorrectionProvider = new ScoreCorrectionProviderImpl(getTestDocumentProvider(),
ParserFactory.INSTANCE, ResultUrlRegistry.INSTANCE);
ResultUrlRegistry resultUrlRegistry = new ResultUrlRegistryImpl(mock(MongoObjectFactory.class),
mock(DomainObjectFactory.class));
ScoreCorrectionProviderImpl scoreCorrectionProvider = new ScoreCorrectionProviderImpl(
getTestDocumentProvider(), ParserFactory.INSTANCE, resultUrlRegistry);
Map<String, Set<com.sap.sse.common.Util.Pair<String, TimePoint>>> hasResultsFor = scoreCorrectionProvider.getHasResultsForBoatClassFromDateByEventName();
Set<com.sap.sse.common.Util.Pair<String, TimePoint>> resultsForYES = hasResultsFor.get(YES_EVENT_NAME);
@@ -107,8 +113,10 @@ public class ParserTest {
@Test
public void testScoreCorrectionProvider() throws Exception {
ScoreCorrectionProviderImpl scoreCorrectionProvider = new ScoreCorrectionProviderImpl(getTestDocumentProvider(),
ParserFactory.INSTANCE, ResultUrlRegistry.INSTANCE);
ResultUrlRegistry resultUrlRegistry = new ResultUrlRegistryImpl(mock(MongoObjectFactory.class),
mock(DomainObjectFactory.class));
ScoreCorrectionProviderImpl scoreCorrectionProvider = new ScoreCorrectionProviderImpl(
getTestDocumentProvider(), ParserFactory.INSTANCE, resultUrlRegistry);
Map<String, Set<com.sap.sse.common.Util.Pair<String, TimePoint>>> hasResultsFor = scoreCorrectionProvider.getHasResultsForBoatClassFromDateByEventName();
Set<com.sap.sse.common.Util.Pair<String, TimePoint>> resultsForYES = hasResultsFor.get(YES_EVENT_NAME);
com.sap.sse.common.Util.Pair<String, TimePoint> resultFor29er = null;
@@ -0,0 +1,49 @@
package com.sap.sailing.manage2sail.resultimport.test;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.Map;
import java.util.Set;
import junit.framework.Assert;
import org.junit.Test;
import com.sap.sailing.domain.persistence.DomainObjectFactory;
import com.sap.sailing.domain.persistence.MongoObjectFactory;
import com.sap.sailing.resultimport.ResultUrlRegistry;
import com.sap.sailing.resultimport.impl.ResultUrlRegistryImpl;
import com.sap.sailing.server.RacingEventService;
import com.sap.sailing.server.impl.RacingEventServiceImpl;
@SuppressWarnings("restriction")
public class PersistenceTest {
@Test
public void testResultUrlStoring() throws MalformedURLException {
RacingEventService racingEventService = new RacingEventServiceImpl();
DomainObjectFactory domainObjectFactory = racingEventService.getDomainObjectFactory();
MongoObjectFactory mongoObjectFactory = racingEventService.getMongoObjectFactory();
ResultUrlRegistry resultUrlRegistry = new ResultUrlRegistryImpl(mongoObjectFactory, domainObjectFactory);
String testProviderName = "TestProvider";
URL testUrl = new URL(
"http://manage2sail.com/api/public/links/event/d30883d3-2876-4d7e-af49-891af6cbae1b?accesstoken=bDAv8CwsTM94ujZ&mediaType=json");
resultUrlRegistry.registerResultUrl(testProviderName, testUrl);
Map<String, Set<URL>> resultUrls = domainObjectFactory.loadResultUrls();
Assert.assertTrue(resultUrls.containsKey(testProviderName));
Set<URL> urls = resultUrls.get(testProviderName);
Assert.assertEquals(1, urls.size());
URL url = urls.iterator().next();
Assert.assertEquals(testUrl, url);
resultUrlRegistry.unregisterResultUrl(testProviderName, testUrl);
resultUrls = domainObjectFactory.loadResultUrls();
Assert.assertFalse(resultUrls.containsKey(testProviderName));
}
}
@@ -6,7 +6,8 @@ Bundle-Version: 1.0.0.qualifier
Bundle-Activator: com.sap.sailing.manage2sail.resultimport.Activator
Bundle-Vendor: SAP
Bundle-RequiredExecutionEnvironment: JavaSE-1.7
Import-Package: org.osgi.framework;version="1.5.0"
Import-Package: org.osgi.framework;version="1.5.0",
org.osgi.util.tracker;version="1.5.1"
Bundle-ActivationPolicy: lazy
Require-Bundle: com.sap.sailing.manage2sail,
com.sap.sailing.domain.common,
@@ -1,6 +1,5 @@
package com.sap.sailing.manage2sail.resultimport;
import java.net.URL;
import java.security.cert.CertificateException;
import javax.net.ssl.HostnameVerifier;
@@ -12,26 +11,36 @@ import javax.net.ssl.X509TrustManager;
import org.osgi.framework.BundleActivator;
import org.osgi.framework.BundleContext;
import org.osgi.util.tracker.ServiceTracker;
import com.sap.sailing.domain.common.ScoreCorrectionProvider;
import com.sap.sailing.resultimport.ResultUrlRegistry;
import com.sap.sailing.resultimport.impl.ResultUrlRegistryServiceTrackerCustomizer;
import com.sap.sailing.xrr.resultimport.ParserFactory;
public class Activator implements BundleActivator {
// private static String MANAGE2SAIL_KIELWEEK_2013_URL = "http://manage2sail.com/api/public/links/event/da33884e-24fe-44f6-8501-d253587f7cc8?accesstoken=bDAv8CwsTM94ujZ&mediaType=json";
private static String MANAGE2SAIL_TW_2013_URL = "http://manage2sail.com/api/public/links/event/937a5c0a-5a28-4a07-806a-8c8ec1efc85c?accesstoken=bDAv8CwsTM94ujZ&mediaType=json";
private ServiceTracker<ResultUrlRegistry, ResultUrlRegistry> resultUrlRegistryServiceTracker;
public void start(BundleContext bundleContext) throws Exception {
final ScoreCorrectionProviderImpl service = new ScoreCorrectionProviderImpl(ParserFactory.INSTANCE, ResultUrlRegistry.INSTANCE);
bundleContext.registerService(ScoreCorrectionProvider.class, service, /* properties */null);
// ResultUrlRegistry.INSTANCE.registerResultUrl(ScoreCorrectionProviderImpl.NAME, new URL(MANAGE2SAIL_KIELWEEK_2013_URL));
ResultUrlRegistry.INSTANCE.registerResultUrl(ScoreCorrectionProviderImpl.NAME, new URL(MANAGE2SAIL_TW_2013_URL));
resultUrlRegistryServiceTracker = new ServiceTracker<>(bundleContext, ResultUrlRegistry.class,
new ResultUrlRegistryServiceTrackerCustomizer(bundleContext) {
@Override
protected ScoreCorrectionProvider configureScoreCorrectionProvider(
ResultUrlRegistry resultUrlRegistry) {
final ScoreCorrectionProviderImpl service = new ScoreCorrectionProviderImpl(
ParserFactory.INSTANCE, resultUrlRegistry);
return service;
}
});
resultUrlRegistryServiceTracker.open();
createAnAllCertificatesTrustingManagerforSSL();
}
public void stop(BundleContext bundleContext) throws Exception {
resultUrlRegistryServiceTracker.close();
}
private void createAnAllCertificatesTrustingManagerforSSL() throws Exception {
@@ -101,7 +101,7 @@ public class ScoreCorrectionProviderImpl implements ScoreCorrectionProvider, Res
if(divisionGender != null) {
divisionBoatClassAndGender += ", " + divisionGender.name();
}
if (boatClassName.equalsIgnoreCase(divisionBoatClassAndGender)) {
if (boatClassName.equalsIgnoreCase(divisionBoatClassAndGender) || boatClassName.contains(divisionBoatClassAndGender)) {
return new XRRRegattaResultsAsScoreCorrections(event, division, this,
parser);
}
@@ -3,6 +3,7 @@ Bundle-ManifestVersion: 2
Bundle-Name: Shared result import APIs
Bundle-SymbolicName: com.sap.sailing.resultimport
Bundle-Version: 1.0.0.qualifier
Bundle-Activator: com.sap.sailing.resultimport.Activator
Bundle-Vendor: SAP
Bundle-RequiredExecutionEnvironment: JavaSE-1.7
Bundle-ActivationPolicy: lazy
@@ -11,5 +12,8 @@ Export-Package: com.sap.sailing.resultimport,
Import-Package: com.sap.sailing.domain.base.impl,
com.sap.sailing.domain.common,
com.sap.sailing.domain.common.impl,
org.osgi.framework;version="1.5.0"
com.sap.sailing.domain.persistence,
com.sap.sailing.server,
org.osgi.framework;version="1.5.0",
org.osgi.util.tracker;version="1.5.1"
Require-Bundle: com.sap.sse.common
@@ -0,0 +1,56 @@
package com.sap.sailing.resultimport;
import org.osgi.framework.BundleActivator;
import org.osgi.framework.BundleContext;
import org.osgi.framework.ServiceReference;
import org.osgi.util.tracker.ServiceTracker;
import org.osgi.util.tracker.ServiceTrackerCustomizer;
import com.sap.sailing.resultimport.impl.ResultUrlRegistryImpl;
import com.sap.sailing.server.RacingEventService;
public class Activator implements BundleActivator {
private ServiceTracker<RacingEventService, RacingEventService> racingEventServiceTracker;
@Override
public void start(BundleContext context) throws Exception {
racingEventServiceTracker = new ServiceTracker<RacingEventService, RacingEventService>(context,
RacingEventService.class.getName(), new RacingEventServiceTrackerCustomizer(context));
racingEventServiceTracker.open();
}
@Override
public void stop(BundleContext context) throws Exception {
racingEventServiceTracker.close();
}
private class RacingEventServiceTrackerCustomizer implements
ServiceTrackerCustomizer<RacingEventService, RacingEventService> {
private final BundleContext context;
public RacingEventServiceTrackerCustomizer(BundleContext context) {
this.context = context;
}
@Override
public RacingEventService addingService(ServiceReference<RacingEventService> reference) {
RacingEventService racingEventService = context.getService(reference);
ResultUrlRegistry resultUrlRegistryService = new ResultUrlRegistryImpl(
racingEventService.getMongoObjectFactory(), racingEventService.getDomainObjectFactory());
context.registerService(ResultUrlRegistry.class, resultUrlRegistryService, null);
return racingEventService;
}
@Override
public void modifiedService(ServiceReference<RacingEventService> reference, RacingEventService service) {
}
@Override
public void removedService(ServiceReference<RacingEventService> reference, RacingEventService service) {
}
}
}
@@ -2,15 +2,11 @@ package com.sap.sailing.resultimport;
import java.net.URL;
import com.sap.sailing.resultimport.impl.ResultUrlRegistryImpl;
/**
* A registry for result URL's of score correction providers
* @author Frank
*/
public interface ResultUrlRegistry {
ResultUrlRegistry INSTANCE = new ResultUrlRegistryImpl();
void registerResultUrl(String resultProviderName, URL url);
void unregisterResultUrl(String resultProviderName, URL url);
@@ -2,18 +2,21 @@ package com.sap.sailing.resultimport.impl;
import java.net.URL;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import com.sap.sailing.domain.persistence.DomainObjectFactory;
import com.sap.sailing.domain.persistence.MongoObjectFactory;
import com.sap.sailing.resultimport.ResultUrlRegistry;
public class ResultUrlRegistryImpl implements ResultUrlRegistry {
private Map<String, Set<URL>> resultUrls;
private final Map<String, Set<URL>> resultUrls;
private final MongoObjectFactory mongoObjectFactory;
public ResultUrlRegistryImpl() {
resultUrls = new HashMap<String, Set<URL>>();
public ResultUrlRegistryImpl(MongoObjectFactory mongoObjectFactory, DomainObjectFactory domainObjectFactory) {
this.mongoObjectFactory = mongoObjectFactory;
resultUrls = domainObjectFactory.loadResultUrls();
}
@Override
@@ -24,6 +27,7 @@ public class ResultUrlRegistryImpl implements ResultUrlRegistry {
resultUrls.put(resultProviderName, urlSet);
}
urlSet.add(url);
mongoObjectFactory.storeResultUrl(resultProviderName, url);
}
@Override
@@ -31,6 +35,7 @@ public class ResultUrlRegistryImpl implements ResultUrlRegistry {
Set<URL> urlSet = resultUrls.get(resultProviderName);
if(urlSet != null) {
urlSet.remove(url);
mongoObjectFactory.removeResultUrl(resultProviderName, url);
}
}
@@ -0,0 +1,40 @@
package com.sap.sailing.resultimport.impl;
import org.osgi.framework.BundleContext;
import org.osgi.framework.ServiceReference;
import org.osgi.util.tracker.ServiceTrackerCustomizer;
import com.sap.sailing.domain.common.ScoreCorrectionProvider;
import com.sap.sailing.resultimport.ResultUrlRegistry;
public abstract class ResultUrlRegistryServiceTrackerCustomizer implements
ServiceTrackerCustomizer<ResultUrlRegistry, ResultUrlRegistry> {
private final BundleContext bundleContext;
public ResultUrlRegistryServiceTrackerCustomizer(BundleContext bundleContext) {
this.bundleContext = bundleContext;
}
@Override
public ResultUrlRegistry addingService(ServiceReference<ResultUrlRegistry> reference) {
ServiceReference<ResultUrlRegistry> serviceRefUrlRegistry = bundleContext
.getServiceReference(ResultUrlRegistry.class);
ResultUrlRegistry resultUrlRegistry = bundleContext.getService(serviceRefUrlRegistry);
ScoreCorrectionProvider scoreCorrectionProvider = configureScoreCorrectionProvider(resultUrlRegistry);
bundleContext.registerService(ScoreCorrectionProvider.class, scoreCorrectionProvider, /* properties */null);
return resultUrlRegistry;
}
protected abstract ScoreCorrectionProvider configureScoreCorrectionProvider(ResultUrlRegistry resultUrlRegistry);
@Override
public void modifiedService(ServiceReference<ResultUrlRegistry> reference, ResultUrlRegistry service) {
}
@Override
public void removedService(ServiceReference<ResultUrlRegistry> reference, ResultUrlRegistry service) {
}
}
@@ -32,7 +32,7 @@ public class TestLeaderboardEditing extends AbstractSeleniumTest {
private static final TrackableRaceDescriptor TRACKABLE_RACE = new TrackableRaceDescriptor(
BMW_CUP_REGATTA, BMW_CUP_RACE_8, BMW_CUP_BOAT_CLASS);
private static final TrackedRaceDescriptor TRACKED_RACE = new TrackedRaceDescriptor(
BMW_CUP_RACE_8 + " (" + BMW_CUP_BOAT_CLASS + ")", BMW_CUP_BOAT_CLASS, BMW_CUP_RACE_8);
BMW_CUP_REGATTA + " (" + BMW_CUP_BOAT_CLASS + ")", BMW_CUP_BOAT_CLASS, BMW_CUP_RACE_8);
private static final RaceDescriptor RACE_COLUMN = new RaceDescriptor("R1", "Default", false, false, 0.0);
@Before
@@ -39,6 +39,8 @@ import com.sap.sailing.server.gateway.SailingServerHttpServlet;
public class WindStatusServlet extends SailingServerHttpServlet implements IgtimiWindListener, BulkFixReceiver {
private static final long serialVersionUID = -6791613843435003810L;
private final int NUMBER_OF_MESSAGES_TO_SHOW=20;
private static List<ExpeditionMessageInfo> lastExpeditionMessages;
private static int igtimiRawMessageCount;
@@ -82,14 +84,18 @@ public class WindStatusServlet extends SailingServerHttpServlet implements Igtim
out.println("</head>");
out.println("<body>");
out.println("<h3>Igtimi Wind Status ("+igtimiRawMessageCount+" raw messages received)</h3>");
if (lastIgtimiMessages != null && lastIgtimiMessages.size() > 0) {
if (lastIgtimiMessages != null && !lastIgtimiMessages.isEmpty()) {
final List<IgtimiMessageInfo> copyOfLastIgtimiMessages;
synchronized (lastIgtimiMessages) {
copyOfLastIgtimiMessages = new ArrayList<>(WindStatusServlet.lastIgtimiMessages);
}
int counter = 0;
for (ListIterator<IgtimiMessageInfo> iterator = WindStatusServlet.lastIgtimiMessages.listIterator(WindStatusServlet.lastIgtimiMessages.size()); iterator.hasPrevious();) {
for (ListIterator<IgtimiMessageInfo> iterator = copyOfLastIgtimiMessages.listIterator(copyOfLastIgtimiMessages.size()); iterator.hasPrevious();) {
counter++;
IgtimiMessageInfo message = iterator.previous();
out.println(message);
out.println("<br/>");
if (counter >= 10) {
if (counter >= NUMBER_OF_MESSAGES_TO_SHOW) {
break;
}
}
@@ -101,9 +107,20 @@ public class WindStatusServlet extends SailingServerHttpServlet implements Igtim
}
}
out.println("<h3>Expedition Wind Status</h3>");
if (lastExpeditionMessages.size()>0) {
for (ExpeditionMessageInfo message : lastExpeditionMessages) {
if (lastExpeditionMessages != null && !lastExpeditionMessages.isEmpty()) {
final List<ExpeditionMessageInfo> copyOfLastExpeditionMessages;
synchronized (lastExpeditionMessages) {
copyOfLastExpeditionMessages = new ArrayList<>(WindStatusServlet.lastExpeditionMessages);
}
int expeditionMsgCounter = 0;
for (ListIterator<ExpeditionMessageInfo> iterator = copyOfLastExpeditionMessages.listIterator(copyOfLastExpeditionMessages.size()); iterator.hasPrevious();) {
expeditionMsgCounter++;
ExpeditionMessageInfo message = iterator.previous();
out.println(message);
out.println("<br/>");
if (expeditionMsgCounter >= NUMBER_OF_MESSAGES_TO_SHOW) {
break;
}
}
} else {
out.println("<i>No Expedition messages received so far!</i>");
@@ -146,12 +163,14 @@ public class WindStatusServlet extends SailingServerHttpServlet implements Igtim
receiver.addListener(new ExpeditionListener() {
@Override
public void received(ExpeditionMessage message) {
if(message != null && message.getBoatID() >= 0) {
if (message != null && message.getBoatID() >= 0) {
ExpeditionMessageInfo info = new ExpeditionMessageInfo();
info.boatID = message.getBoatID();
info.message = message;
info.messageReceivedAt = new Date();
lastExpeditionMessages.add(info);
synchronized (lastExpeditionMessages) {
lastExpeditionMessages.add(info);
}
}
}
}
@@ -566,6 +566,7 @@ public class RegattasResource extends AbstractSailingServerResource {
JSONObject jsonRaceResults = new JSONObject();
jsonRaceResults.put("name", trackedRace.getRace().getName());
jsonRaceResults.put("regatta", regatta.getName());
jsonRaceResults.put("startOfRace-ms", trackedRace.getStartOfRace() == null ? null : trackedRace.getStartOfRace().asMillis());
JSONArray jsonLegs = new JSONArray();
for (TrackedLeg leg : trackedRace.getTrackedLegs()) {
@@ -132,7 +132,7 @@ public class TrackRaceReplicationTest extends AbstractServerReplicationTest {
// anyway. When the tracked race then is loaded it is expected
// to automatically be linked to the leaderboard column.
master.apply(new ConnectTrackedRaceToLeaderboardColumn(leaderboardName, columnName, defaultFleet.getName(),
new RegattaNameAndRaceName("weym470may122011 (STG)", "weym470may122011")));
new RegattaNameAndRaceName("Academy Tracking 2011 (STG)", "weym470may122011")));
startTracking();
assertNotNull(masterColumn.getTrackedRace(defaultFleet)); // ensure the re-assignment worked on the master
Thread.sleep(1000);
@@ -151,6 +151,13 @@ public class TrackRaceReplicationTest extends AbstractServerReplicationTest {
@Test
public void testRaceTimeReplication() throws InterruptedException, Exception {
startTracking();
// now wait at least until the start of tracking time has been received on the master copy
boolean receivedStartOfTracking = master.getTrackedRace(raceIdentifier).getStartOfTracking() != null;
while (!receivedStartOfTracking) { // relying on the Timeout rule for this test
Thread.sleep(10);
receivedStartOfTracking = master.getTrackedRace(raceIdentifier).getStartOfTracking() != null &&
master.getTrackedRace(raceIdentifier).getEndOfTracking() != null;
}
Thread.sleep(2000); // kept failing several times for a 1000ms timeout
TrackedRace replicaTrackedRace = replica.getTrackedRace(raceIdentifier);
assertEquals(masterTrackedRace.getStartOfTracking(), replicaTrackedRace.getStartOfTracking());
@@ -297,6 +297,8 @@ public class MasterDataImportTest {
Regatta regattaOnTarget = destService.getRegattaByName(TEST_LEADERBOARD_NAME);
Assert.assertNotNull(regattaOnTarget);
Assert.assertEquals(false, regattaOnTarget.getAllRaces().iterator().hasNext());
Assert.assertEquals(courseAreaUUID, eventOnTarget.getVenue().getCourseAreas().iterator().next().getId());
RaceColumn raceColumnOnTarget = leaderboardOnTarget.getRaceColumnByName(raceColumnName);
@@ -1328,6 +1328,16 @@ public class RacingEventServiceImpl implements RacingEventServiceWithTestSupport
public void raceTimesChanged(TimePoint startOfTracking, TimePoint endOfTracking, TimePoint startTimeReceived) {
replicate(new UpdateRaceTimes(getRaceIdentifier(), startOfTracking, endOfTracking, startTimeReceived));
}
@Override
public void waypointAdded(int zeroBasedIndex, Waypoint waypointThatGotAdded) {
// no-op; the course change is replicated by the separate CourseChangeReplicator
}
@Override
public void waypointRemoved(int zeroBasedIndex, Waypoint waypointThatGotRemoved) {
// no-op; the course change is replicated by the separate CourseChangeReplicator
}
@Override
public void delayToLiveChanged(long delayToLiveInMillis) {
@@ -34,6 +34,7 @@ import com.sap.sailing.domain.tracking.TrackedLegOfCompetitor;
import com.sap.sailing.domain.tracking.TrackedRace;
import com.sap.sailing.server.RacingEventService;
import com.sap.sse.common.Util;
import com.sap.sse.common.Util.Triple;
public abstract class ExportAction {
private HttpServletRequest req;
@@ -175,7 +176,8 @@ public abstract class ExportAction {
return result;
}
public com.sap.sse.common.Util.Triple<GPSFixMoving, Speed, TrackedLegOfCompetitor> getMaximumSpeedOverGround(Competitor competitor, TrackedRace trackedRace) {
public Triple<GPSFixMoving, Speed, TrackedLegOfCompetitor> getMaximumSpeedOverGround(Competitor competitor, TrackedRace trackedRace) {
Triple<GPSFixMoving, Speed, TrackedLegOfCompetitor> result = null;
com.sap.sse.common.Util.Pair<GPSFixMoving, Speed> speedWithGPSFix = null;
TrackedLegOfCompetitor legOfCompetitorWhereSpeedHasBeenReached = null;
if (Util.contains(trackedRace.getRace().getCompetitors(), competitor)) {
@@ -187,9 +189,10 @@ public abstract class ExportAction {
}
if (speedWithGPSFix != null) {
legOfCompetitorWhereSpeedHasBeenReached = trackedRace.getTrackedLeg(competitor, speedWithGPSFix.getA().getTimePoint());
result = new Triple<GPSFixMoving, Speed, TrackedLegOfCompetitor>(speedWithGPSFix.getA(), speedWithGPSFix.getB(), legOfCompetitorWhereSpeedHasBeenReached);
}
}
return new com.sap.sse.common.Util.Triple<GPSFixMoving, Speed, TrackedLegOfCompetitor>(speedWithGPSFix.getA(), speedWithGPSFix.getB(), legOfCompetitorWhereSpeedHasBeenReached);
return result;
}
public Speed getAverageSpeedOverGround(Leaderboard leaderboard, Competitor competitor, TimePoint timePoint, boolean alsoIncludeNonFinishedRaces) {
@@ -30,6 +30,7 @@ import com.sap.sailing.domain.common.Bearing;
import com.sap.sailing.domain.common.Distance;
import com.sap.sailing.domain.common.Duration;
import com.sap.sailing.domain.common.MaxPointsReason;
import com.sap.sailing.domain.common.NauticalSide;
import com.sap.sailing.domain.common.NoWindException;
import com.sap.sailing.domain.common.Position;
import com.sap.sailing.domain.common.Speed;
@@ -227,8 +228,10 @@ public class LeaderboardData extends ExportAction {
LineDetails start = race.getStartLine(race.getStartOfTracking());
addNamedElementWithValue(raceElement, "start_line_length_in_meters", start.getLength().getMeters());
addNamedElementWithValue(raceElement, "start_advantage_in_meters", start.getAdvantage().getMeters());
addNamedElementWithValue(raceElement, "advantageous_side_while_approaching_start_line", start.getAdvantageousSideWhileApproachingLine().name());
Distance advantage = start.getAdvantage();
addNamedElementWithValue(raceElement, "start_advantage_in_meters", advantage != null ? advantage.getMeters() : 0);
NauticalSide nauticalSideWhileApproaching = start.getAdvantageousSideWhileApproachingLine();
addNamedElementWithValue(raceElement, "advantageous_side_while_approaching_start_line", nauticalSideWhileApproaching != null ? nauticalSideWhileApproaching.name() : "UNKNOWN");
Distance raceCourseLength = race.getCourseLength();
if (raceCourseLength == null) {
@@ -435,7 +438,7 @@ public class LeaderboardData extends ExportAction {
}
addNamedElementWithValue(competitorRaceDataElement, "speed_when_crossing_start_line_in_knots", speedWhenCrossingStartline != null ? speedWhenCrossingStartline.getKnots() : 0);
com.sap.sse.common.Util.Triple<GPSFixMoving, Speed, TrackedLegOfCompetitor> gpsFixWithSpeedAndLegInformation = getMaximumSpeedOverGround(competitor, race);
if (gpsFixWithSpeedAndLegInformation.getB() != null) {
if (gpsFixWithSpeedAndLegInformation != null && gpsFixWithSpeedAndLegInformation.getB() != null) {
addNamedElementWithValue(competitorRaceDataElement, "maximum_race_speed_over_ground_in_knots", gpsFixWithSpeedAndLegInformation.getB().getKnots());
competitorRaceDataElement.addContent(createTimedXML("maximum_race_speed_measured_at_", gpsFixWithSpeedAndLegInformation.getA().getTimePoint()));
if (gpsFixWithSpeedAndLegInformation.getC() != null) {
@@ -460,6 +463,8 @@ public class LeaderboardData extends ExportAction {
} else {
addNamedElementWithValue(competitorRaceDataElement, "maximum_race_speed_over_ground_in_knots", 0.0);
competitorRaceDataElement.addContent(createTimedXML("maximum_race_speed_measured_at_", race.getStartOfRace()));
addNamedElementWithValue(competitorRaceDataElement, "maximum_race_speed_over_ground_reached_in_leg_with_type", "UNKNOWN");
addNamedElementWithValue(competitorRaceDataElement, "maximum_race_speed_over_ground_reached_in_leg", 0);
raceConfidenceAndErrorMessages = updateConfidence("Competitor " + competitor.getName() + " has no valid maximum speed for this race!", 0.5, raceConfidenceAndErrorMessages);
}
Distance distanceTraveledInThisRace = race.getDistanceTraveled(competitor, race.getEndOfRace());
+11 -7
View File
@@ -1,7 +1,11 @@
#!/bin/sh
# source variables
. `pwd`/env.sh
if [ "$TMP" = "" ]; then
TMP=/tmp
fi
PWD=`pwd`
. "$PWD/env.sh"
PARAM=$@
@@ -36,13 +40,13 @@ if [[ $TELNET_ACTIVE != "" ]]; then
fi
scriptdir=`dirname "$0"`
LIB_DIR=`pwd`/native-libraries
LIB_DIR="$PWD/native-libraries"
if [[ ! -d `pwd`/logs ]]; then
if [[ ! -d "$PWD/logs" ]]; then
mkdir logs
fi
if [[ ! -d `pwd`/tmp ]]; then
if [[ ! -d "$PWD/tmp" ]]; then
mkdir tmp
fi
@@ -72,7 +76,7 @@ APP_PARAMETERS="-Dmongo.host=$MONGODB_HOST -Dmongo.port=$MONGODB_PORT -Dmongo.db
REPLICATION_PARAMETERS="-Dreplicate.on.start=$REPLICATE_ON_START -Dreplicate.master.servlet.host=$REPLICATE_MASTER_SERVLET_HOST -Dreplicate.master.servlet.port=$REPLICATE_MASTER_SERVLET_PORT -Dreplicate.master.queue.host=$REPLICATE_MASTER_QUEUE_HOST -Dreplicate.master.queue.port=$REPLICATE_MASTER_QUEUE_PORT"
if [[ $PARAM == "" ]] || [[ $PARAM == "no-update" ]]; then
nohup $JAVA_BINARY -D$SERVER_NAME $ADDITIONAL_JAVA_ARGS -Dcom.sap.sailing.server.name=$SERVER_NAME $APP_PARAMETERS $REPLICATION_PARAMETERS -Djava.io.tmpdir=`pwd`/tmp -Dfile.encoding=cp1252 -Djetty.home=$scriptdir/configuration/jetty -Djava.util.logging.config.file=$scriptdir/configuration/logging.properties -Djava.library.path=$LIB_DIR -Dosgi.shell.telnet.port=$TELNET_PORT -Xmx$MEMORY -jar plugins/org.eclipse.equinox.launcher_1.3.0.v20130327-1440.jar -configuration ./ -clean 2>/dev/null >/dev/null &
nohup $JAVA_BINARY -D$SERVER_NAME $ADDITIONAL_JAVA_ARGS -Dcom.sap.sailing.server.name=$SERVER_NAME $APP_PARAMETERS $REPLICATION_PARAMETERS -Djava.io.tmpdir="$PWD/tmp" -Dfile.encoding=cp1252 -Djetty.home=$scriptdir/configuration/jetty -Djava.util.logging.config.file=$scriptdir/configuration/logging.properties -Djava.library.path=$LIB_DIR -Dosgi.shell.telnet.port=$TELNET_PORT -Xmx$MEMORY -jar plugins/org.eclipse.equinox.launcher_1.3.0.v20130327-1440.jar -configuration ./ -clean 2>/dev/null >/dev/null &
JAVA_PID=$!
echo "Starting server... (PID: $JAVA_PID)"
echo "SERVER_NAME: $SERVER_NAME"
@@ -127,10 +131,10 @@ if [[ $PARAM == "" ]] || [[ $PARAM == "no-update" ]]; then
fi
elif [[ $PARAM == "debug" ]]; then
echo "Starting remote debugging session on port 8000 - make sure this port is open and reachable from the outside"
$JAVA_BINARY -Xdebug -Xrunjdwp:server=y,transport=dt_socket,address=8000,suspend=y -D$SERVER_NAME $ADDITIONAL_JAVA_ARGS -Dcom.sap.sailing.server.name=$SERVER_NAME $APP_PARAMETERS $REPLICATION_PARAMETERS -Djava.io.tmpdir=`pwd`/tmp -Dfile.encoding=cp1252 -Djetty.home=$scriptdir/configuration/jetty -Djava.util.logging.config.file=$scriptdir/configuration/logging.properties -Djava.library.path=$LIB_DIR -Xmx$MEMORY -jar plugins/org.eclipse.equinox.launcher_1.3.0.v20130327-1440.jar -console -configuration ./ -clean
$JAVA_BINARY -Xdebug -Xrunjdwp:server=y,transport=dt_socket,address=8000,suspend=y -D$SERVER_NAME $ADDITIONAL_JAVA_ARGS -Dcom.sap.sailing.server.name=$SERVER_NAME $APP_PARAMETERS $REPLICATION_PARAMETERS -Djava.io.tmpdir="$PWD/tmp" -Dfile.encoding=cp1252 -Djetty.home=$scriptdir/configuration/jetty -Djava.util.logging.config.file=$scriptdir/configuration/logging.properties -Djava.library.path=$LIB_DIR -Xmx$MEMORY -jar plugins/org.eclipse.equinox.launcher_1.3.0.v20130327-1440.jar -console -configuration ./ -clean
elif [[ $PARAM == "fg" ]]; then
$JAVA_BINARY -D$SERVER_NAME $ADDITIONAL_JAVA_ARGS -Dcom.sap.sailing.server.name=$SERVER_NAME $APP_PARAMETERS $REPLICATION_PARAMETERS -Djava.io.tmpdir=`pwd`/tmp -Dfile.encoding=cp1252 -Djetty.home=$scriptdir/configuration/jetty -Djava.util.logging.config.file=$scriptdir/configuration/logging.properties -Djava.library.path=$LIB_DIR -Xmx$MEMORY -jar plugins/org.eclipse.equinox.launcher_1.3.0.v20130327-1440.jar -console -configuration ./ -clean
$JAVA_BINARY -D$SERVER_NAME $ADDITIONAL_JAVA_ARGS -Dcom.sap.sailing.server.name=$SERVER_NAME $APP_PARAMETERS $REPLICATION_PARAMETERS -Djava.io.tmpdir="$PWD/tmp" -Dfile.encoding=cp1252 -Djetty.home=$scriptdir/configuration/jetty -Djava.util.logging.config.file=$scriptdir/configuration/logging.properties -Djava.library.path=$LIB_DIR -Xmx$MEMORY -jar plugins/org.eclipse.equinox.launcher_1.3.0.v20130327-1440.jar -console -configuration ./ -clean
fi
@@ -1,8 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.sap.sailing.racecommittee.app"
android:versionCode="4"
android:versionName="4.1 - Khalid" >
android:versionCode="5"
android:versionName="5 - Laser" >
<uses-sdk
android:maxSdkVersion="17"
@@ -0,0 +1,23 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:dslv="http://schemas.android.com/apk**/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:baselineAligned="false"
android:orientation="vertical"
tools:ignore="ResAuto" >
<GridView
android:id="@+id/byNameCourseDesignGrid"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:numColumns="10"
android:horizontalSpacing="20dp"
android:verticalSpacing="20dp"
android:columnWidth="40dp"
android:padding="10dp"
>
</GridView>
</LinearLayout>
@@ -9,7 +9,7 @@
<item name="android:actionDropDownStyle">@style/MyDropDownNav</item>
<item name="android:actionBarStyle">@style/Widget.Welter.ActionBar</item>
<item name="android:textColorPrimary">@color/welter_deep_gray</item>
<item name="android:actionOverflowButtonStyle">@android:style/Widget.Holo.ActionButton.Overflow</item>>
<!-- <item name="timePickerStyle">@style/Widget.TimePicker</item> -->
@@ -163,7 +163,7 @@ public abstract class BaseActivity extends LoggableActivity {
sendingServiceStatus = String.format("Currently %d events waiting to be sent.\nLast successful sent was at %s",
errorCount, lastSuccessfulSend == null ? "never" : lastSuccessfulSend);
} else {
menuItemLive.setIcon(R.drawable.ic_menu_share_holo_light);
menuItemLive.setIcon(R.drawable.ic_menu_share);
sendingServiceStatus = String.format("Currently no event waiting to be sent.", errorCount);
}
}
@@ -187,7 +187,6 @@ public class LoginActivity extends BaseActivity implements EventSelectedListener
public void onDialogPositiveButton(AttachedDialogFragment dialog) {
// We have to take the passed instance, LoginActivity.this might be a new instance!
LoginDialog localLoginDialog = (LoginDialog) dialog;
preferences.setAuthor(localLoginDialog.getAuthor());
switch (localLoginDialog.getSelectedLoginType()) {
case OFFICER:
ExLog.i(TAG, "Communication with backend is active.");
@@ -203,6 +202,7 @@ public class LoginActivity extends BaseActivity implements EventSelectedListener
Toast.LENGTH_LONG).show();
return;
}
preferences.setAuthor(localLoginDialog.getAuthor());
if (selectedCourseArea == null) {
Toast.makeText(LoginActivity.this, "The selected course area was lost.", Toast.LENGTH_LONG).show();
@@ -1,18 +1,24 @@
package com.sap.sailing.racecommittee.app.ui.fragments.dialogs.coursedesign;
import java.util.Collections;
import java.util.List;
import android.app.Activity;
import android.content.Context;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.Button;
import android.widget.TableLayout;
import android.widget.TableRow;
import android.widget.GridView;
import android.widget.ListAdapter;
import com.sap.sailing.domain.base.CourseBase;
import com.sap.sailing.domain.base.impl.CourseDataImpl;
import com.sap.sailing.domain.common.impl.MillisecondsTimePoint;
import com.sap.sailing.domain.common.impl.NaturalComparator;
import com.sap.sailing.racecommittee.app.R;
import com.sap.sailing.racecommittee.app.ui.fragments.dialogs.RaceDialogFragment;
@@ -29,36 +35,61 @@ public class ByNameCourseDesignDialog extends RaceDialogFragment {
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
TableLayout holder = new TableLayout(getActivity());
for (String courseName : preferences.getByNameCourseDesignerCourseNames()) {
TableRow rowLayout = new TableRow(getActivity());
Button courseButton = new Button(getActivity());
courseButton.setText(courseName);
courseButton.setOnClickListener( new OnClickListener() {
@Override
public void onClick(View v) {
onCourseSelectionButtonClicked(v);
}
});
rowLayout.addView(courseButton);
holder.addView(rowLayout);
}
return holder;
return inflater.inflate(R.layout.race_choose_by_name_course_design_view, container);
}
@Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
getDialog().setTitle(getString(R.string.set_course_layout));
GridView grid = (GridView) getView().findViewById(R.id.byNameCourseDesignGrid);
final List<String> courses = preferences.getByNameCourseDesignerCourseNames();
Collections.sort(courses, new NaturalComparator());
ListAdapter buttonAdapter = new BaseAdapter() {
public int getCount() {
return courses.size();
}
public Object getItem(int position) {
return null;
}
public long getItemId(int position) {
return 0;
}
public View getView(int position, View convertView, ViewGroup parent) {
Button button;
if (convertView == null) { // if it's not recycled, initialize some attributes
Context ctx = ByNameCourseDesignDialog.this.getView().getContext();
button = new Button(ctx);
button.setTextSize(ctx.getResources().getDimension(R.dimen.Welter_BigTitleTextSize));
button.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
onCourseSelectionButtonClicked(v);
}
});
} else {
button = (Button) convertView;
}
button.setText(courses.get(position));
return button;
}
};
grid.setAdapter(buttonAdapter);
}
protected void onCourseSelectionButtonClicked(View v) {
Button selectedButton = (Button) v;
String internalCourseName = (String) selectedButton.getText();
CourseBase courseLayout = new CourseDataImpl(internalCourseName);
getRaceState().setCourseDesign(MillisecondsTimePoint.now(), courseLayout);
dismiss();
}
+7 -5
View File
@@ -186,13 +186,15 @@ dir-etc mongodb-databases mysql-databases
- Let's assume that you want to recover some score corrections from the archive server. We need to have a look at mongodb-databases and check what is contained there. Keep in mind that wind information is only updated once a week so that not every named backup will contain wind information.
<pre>
[backup@ip-172-31-25-136 database]$ /opt/bup/bup -d /home/backup/database/ ls mongodb-databases
2014-05-27-170544 latest
[backup@ip-172-31-25-136 database]$ /opt/bup/bup -d /home/backup/database/ ls mongodb-databases/latest
[backup@ip-172-31-25-136 restored-files]$ /opt/bup/bup -d /home/backup/database/ ls databases/
2014-05-27-212037 2014-05-29-233001 2014-06-01-233001 2014-06-04-203001 2014-06-06-233001 2014-06-09-233001 2014-06-11-233001 2014-06-14-233002 2014-06-17-233001 2014-06-19-233001
2014-05-28-203001 2014-05-30-233001 2014-06-02-233001 2014-06-04-233001 2014-06-07-233001 2014-06-10-233001 2014-06-12-233001 2014-06-15-233002 2014-06-18-203001 latest
2014-05-28-233001 2014-05-31-233001 2014-06-03-233001 2014-06-05-233001 2014-06-08-233001 2014-06-11-203001 2014-06-13-233001 2014-06-16-233001 2014-06-18-233001
[backup@ip-172-31-25-136 database]$ /opt/bup/bup -d /home/backup/database/ ls databases/latest
var
[backup@ip-172-31-25-136 database]$ /opt/bup/bup -d /home/backup/database/ ls mongodb-databases/latest/var/lib/mysql/backup
[backup@ip-172-31-25-136 database]$ /opt/bup/bup -d /home/backup/database/ ls databases/latest/var/lib/mysql/backup
mongodb-10201 mongodb-10201-wind mongodb-10202 mongodb-10202-wind mysql
[backup@ip-172-31-25-136 database]$ /opt/bup/bup -d /home/backup/database/ ls mongodb-databases/latest/var/lib/mysql/backup/mongodb-10202
[backup@ip-172-31-25-136 database]$ /opt/bup/bup -d /home/backup/database/ ls databases/latest/var/lib/mysql/backup/mongodb-10202
COMMAND_MESSAGES.json CONFIGURATIONS.json LAST_MESSAGE_COUNT.json LEADERBOARD_GROUPS.json RACE_LOGS.json REGATTA_FOR_RACE_ID.json VIDEOS.json
COMPETITORS.json EVENTS.json LEADERBOARDS.json RACES_MESSAGES.json REGATTAS.json TRACTRAC_CONFIGURATIONS.json
</pre>