Merge branch 'master' into igtimi

This commit is contained in:
Axel Uhl committed 2013-11-15 15:41:29 +01:00
commit dab2cfd2a9
17 files changed
+242 -45

No files matched your search

+2
View File
@@ -25,6 +25,8 @@ Like businesses, sailors need the latest information to make strategic decisions
* [[Development Environment|wiki/development-environment]]
* [[Working with GWT Locally|wiki/local-gwt]]
* [[Mobile Development|wiki/mobile-development]]
* Information for Webdesigners
* [[Layout repository|wiki/webdesign]]
* General Information
* [[Architecture and Infrastructure|wiki/architecture-and-infrastructure]]
* [[Sailing Domain Algorithms|wiki/sailing-domain-algorithms]]
@@ -1,6 +1,6 @@
package com.sap.sailing.domain.common;
public enum TrackedRaceStatusEnum { PREPARED(0), LOADING(1), TRACKING(2), FINISHED(3);
public enum TrackedRaceStatusEnum { PREPARED(0), LOADING(1), TRACKING(2), FINISHED(3), ERROR(4);
private final int order;
@@ -16,5 +16,5 @@
<stringAttribute key="org.eclipse.jdt.junit.TEST_KIND" value="org.eclipse.jdt.junit.loader.junit4"/>
<stringAttribute key="org.eclipse.jdt.launching.MAIN_TYPE" value=""/>
<stringAttribute key="org.eclipse.jdt.launching.PROJECT_ATTR" value="com.sap.sailing.domain.test"/>
<stringAttribute key="org.eclipse.jdt.launching.VM_ARGUMENTS" value="-Dhttp.proxyHost=proxy -Dhttp.proxyPort=8080 -XX:+UseParallelGC -Dtractrac.tunnel=true -Dtractrac.tunnel.host=10.18.22.156 -ea -Djava.util.logging.config.file=${project_loc:com.sap.sailing.server}/../target/configuration/logging_debug.properties"/>
<stringAttribute key="org.eclipse.jdt.launching.VM_ARGUMENTS" value="-Dhttp.proxyHost=proxy -Dhttp.proxyPort=8080 -XX:+UseParallelGC -Dtractrac.tunnel=true -Dtractrac.tunnel.host=localhost -ea -Djava.util.logging.config.file=${project_loc:com.sap.sailing.server}/../target/configuration/logging_debug.properties"/>
</launchConfiguration>
@@ -14,18 +14,25 @@ import java.util.Set;
import org.junit.Test;
import com.sap.sailing.domain.base.BoatClass;
import com.sap.sailing.domain.base.Mark;
import com.sap.sailing.domain.base.Competitor;
import com.sap.sailing.domain.base.DomainFactory;
import com.sap.sailing.domain.base.Mark;
import com.sap.sailing.domain.base.Nationality;
import com.sap.sailing.domain.base.Waypoint;
import com.sap.sailing.domain.base.impl.BoatImpl;
import com.sap.sailing.domain.base.impl.CompetitorImpl;
import com.sap.sailing.domain.base.impl.CourseAreaImpl;
import com.sap.sailing.domain.base.impl.DomainFactoryImpl;
import com.sap.sailing.domain.base.impl.PersonImpl;
import com.sap.sailing.domain.base.impl.TeamImpl;
import com.sap.sailing.domain.common.impl.Util.Pair;
import com.sap.sailing.domain.leaderboard.Leaderboard;
import com.sap.sailing.domain.leaderboard.LeaderboardGroup;
import com.sap.sailing.domain.leaderboard.impl.FlexibleLeaderboardImpl;
import com.sap.sailing.domain.leaderboard.impl.HighPoint;
import com.sap.sailing.domain.leaderboard.impl.LeaderboardGroupImpl;
import com.sap.sailing.domain.leaderboard.impl.ThresholdBasedResultDiscardingRuleImpl;
import com.sap.sailing.domain.leaderboard.meta.LeaderboardGroupMetaLeaderboard;
public class OfflineSerializationTest extends AbstractSerializationTest {
/**
@@ -87,6 +94,22 @@ public class OfflineSerializationTest extends AbstractSerializationTest {
clone.getDiscardIndexResultsStartingWithHowManyRaces()));
}
// see bug 1605
@Test
public void testSerializingOverallLeaderboardWithFactorOnColumn() throws ClassNotFoundException, IOException {
Leaderboard leaderboard = new FlexibleLeaderboardImpl("Test Leaderboard", new ThresholdBasedResultDiscardingRuleImpl(new int[] { 3, 5 }), new HighPoint(), new CourseAreaImpl("Alpha", "Alpha"));
LeaderboardGroup leaderboardGroup = new LeaderboardGroupImpl("LeaderboardGroup", "Test Leaderboard Group", /* displayGroupsInReverseOrder */ false, Arrays.asList(new Leaderboard[] { leaderboard }));
final LeaderboardGroupMetaLeaderboard overallLeaderboard = new LeaderboardGroupMetaLeaderboard(leaderboardGroup, new HighPoint(), new ThresholdBasedResultDiscardingRuleImpl(new int[0]));
leaderboardGroup.setOverallLeaderboard(overallLeaderboard);
final double FACTOR = 2.0;
overallLeaderboard.getRaceColumnByName("Test Leaderboard").setFactor(FACTOR);
DomainFactory receiverDomainFactory = new DomainFactoryImpl();
LeaderboardGroup clone = cloneBySerialization(leaderboardGroup, receiverDomainFactory);
assertEquals(FACTOR, overallLeaderboard.getRaceColumnByName("Test Leaderboard").getFactor(), 0.00000001);
assertEquals(FACTOR, clone.getOverallLeaderboard().getRaceColumnByName("Test Leaderboard").getFactor(), 0.00000001);
}
@Test
public void testIdentityStabilityOfMarkSerialization() throws ClassNotFoundException, IOException {
DomainFactory senderDomainFactory = new DomainFactoryImpl();
@@ -14,6 +14,7 @@ import java.net.URL;
import java.text.ParseException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
@@ -81,6 +82,13 @@ public class TracTracRaceTrackerImpl extends AbstractRaceTrackerImpl implements
* with static position information otherwise not available through {@link MarkPassingReceiver}'s events.
*/
static final ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1);
/**
* This value indicated how many stored data packets we allow that are not in the right sequence
* Background: It can happen that the progress for storedData hops around and delivers a progress
* that is lower than one received before. This can happen but only at a maximum of times this constant describes.
*/
static final Integer MAX_STORED_PACKET_HOP_ALLOWANCE = 3;
private final Event tractracEvent;
private final com.sap.sailing.domain.base.Regatta regatta;
@@ -92,6 +100,7 @@ public class TracTracRaceTrackerImpl extends AbstractRaceTrackerImpl implements
private final Set<RaceDefinition> races;
private final DynamicTrackedRegatta trackedRegatta;
private TrackedRaceStatus lastStatus;
private HashMap<Triple<URL, URI, URI>, Pair<Integer, Float>> lastProgressPerID;
/**
* paramURL, liveURI and storedURI for TracTrac connection
@@ -192,6 +201,7 @@ public class TracTracRaceTrackerImpl extends AbstractRaceTrackerImpl implements
this.races = new HashSet<RaceDefinition>();
this.windStore = windStore;
this.domainFactory = domainFactory;
this.lastProgressPerID = new HashMap<Triple<URL, URI, URI>, Pair<Integer, Float>>();
final Simulator simulator;
if (simulateWithStartTimeNow) {
simulator = new Simulator(windStore);
@@ -673,11 +683,29 @@ public class TracTracRaceTrackerImpl extends AbstractRaceTrackerImpl implements
@Override
public void storedDataProgress(float progress) {
logger.info("Stored data progress in tracker "+getID()+" for race(s) "+getRaces()+": "+progress);
if (progress != 0.0 && progress < lastStatus.getLoadingProgress()) {
// this should never happen but it happens - let's at least write some log about this problem
logger.severe("I got a loading progress "+progress+" that is smaller than the one already received "+lastStatus.getLoadingProgress());
Integer counter = 0;
final Pair<Integer, Float> lastProgressPair = lastProgressPerID.get(getID());
if (lastProgressPair != null) {
Float lastProgress = lastProgressPair.getB();
counter = lastProgressPair.getA();
if (progress < lastProgress.floatValue()) {
if (counter.intValue() > MAX_STORED_PACKET_HOP_ALLOWANCE) {
try {
logger.severe("Got " + MAX_STORED_PACKET_HOP_ALLOWANCE + " times a value for progress " + progress + " that is lower than one already received " + lastProgress + "! This is a severe error - stopping receivers for " + getID() + " now!");
stop(/* stopReceiversPreemptively */ true);
/* make sure to indicate that this race is erroneous */
lastStatus = new TrackedRaceStatusImpl(TrackedRaceStatusEnum.ERROR, 0.0);
updateStatusOfTrackedRaces();
} catch (InterruptedException e) {
e.printStackTrace();
}
} else {
counter += 1;
}
}
}
lastStatus = new TrackedRaceStatusImpl(progress==1.0 ? TrackedRaceStatusEnum.TRACKING : TrackedRaceStatusEnum.LOADING, progress);
lastProgressPerID.put(getID(), new Pair<Integer, Float>(counter, progress));
updateStatusOfTrackedRaces();
}
@@ -63,8 +63,13 @@ public class UpdateHandler {
}
protected URL buildUpdateURL(HashMap<String, String> additionalParameters) throws MalformedURLException, UnsupportedEncodingException {
String serverUpdateURI = this.updateURI.toString();
// make sure that the update URI always ends with a slash
if (!serverUpdateURI.endsWith("/")) {
serverUpdateURI = serverUpdateURI + "/";
}
String url = String.format(UpdateUrlTemplate,
this.updateURI.toString(),
serverUpdateURI.toString(),
this.action,
URLEncoder.encode(this.tracTracEventId.toString(), EncodingUtf8),
URLEncoder.encode(this.raceId.toString(), EncodingUtf8),
@@ -134,7 +134,7 @@ public abstract class AbstractSimpleLeaderboardImpl implements Leaderboard, Race
private final Set<Competitor> suppressedCompetitors;
private final NamedReentrantReadWriteLock suppressedCompetitorsLock;
private final Map<Pair<TrackedRace, Competitor>, RunnableFuture<RaceDetails>> raceDetailsAtEndOfTrackingCache;
private transient Map<Pair<TrackedRace, Competitor>, RunnableFuture<RaceDetails>> raceDetailsAtEndOfTrackingCache;
/**
* This executor needs to be a different one than {@link #executor} because the tasks run by {@link #executor}
@@ -369,6 +369,7 @@ public abstract class AbstractSimpleLeaderboardImpl implements Leaderboard, Race
}
private void initTransientFields() {
this.raceDetailsAtEndOfTrackingCache = new HashMap<Util.Pair<TrackedRace,Competitor>, RunnableFuture<RaceDetails>>();
this.raceDetailsExecutor = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors());
this.cacheInvalidationListeners = new HashSet<CacheInvalidationListener>();
// When many updates are triggered in a short period of time by a single thread, ensure that the single thread
@@ -2,9 +2,13 @@ package com.sap.sailing.domain.leaderboard.meta;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.WeakHashMap;
@@ -48,10 +52,22 @@ public abstract class AbstractMetaLeaderboard extends AbstractSimpleLeaderboardI
private final Fleet metaFleet;
private final ScoringScheme scoringScheme;
private final String name;
private transient WeakHashMap<Leaderboard, RaceColumn> columnsForLeaderboards;
/**
* Weak hash maps cannot be serialized. Therefore, this field is serialized as a {@link HashMap} in {@link #writeObject(ObjectOutputStream)}
* and de-serialized into a new {@link WeakHashMap} in {@link #readObject(ObjectInputStream)} again.
*/
private transient WeakHashMap<Leaderboard, MetaLeaderboardColumn> columnsForLeaderboards;
/**
* Weak hash maps cannot be serialized. Therefore, this field is serialized as a {@link HashMap} in {@link #writeObject(ObjectOutputStream)}
* and de-serialized into a new {@link WeakHashMap} in {@link #readObject(ObjectInputStream)} again.
*/
private transient WeakHashMap<Leaderboard, ScoreCorrectionListener> scoreCorrectionChangeForwardersByLeaderboard;
private class ScoreCorrectionChangeForwarder implements ScoreCorrectionListener {
private class ScoreCorrectionChangeForwarder implements ScoreCorrectionListener, Serializable {
private static final long serialVersionUID = 915433462154943441L;
@Override
public void correctedScoreChanced(Competitor competitor, RaceColumn raceColumn, Double oldCorrectedScore, Double newCorrectedScore) {
getScoreCorrection().notifyListeners(competitor, raceColumn, oldCorrectedScore, newCorrectedScore);
@@ -88,12 +104,20 @@ public abstract class AbstractMetaLeaderboard extends AbstractSimpleLeaderboardI
return new MetaLeaderboardScoreCorrection(this);
}
private void writeObject(ObjectOutputStream oos) throws IOException {
oos.defaultWriteObject();
oos.writeObject(new HashMap<Leaderboard, MetaLeaderboardColumn>(columnsForLeaderboards));
oos.writeObject(new HashMap<Leaderboard, ScoreCorrectionListener>(scoreCorrectionChangeForwardersByLeaderboard));
}
private void readObject(ObjectInputStream ois) throws ClassNotFoundException, IOException {
ois.defaultReadObject();
columnsForLeaderboards = new WeakHashMap<>();
scoreCorrectionChangeForwardersByLeaderboard = new WeakHashMap<Leaderboard, ScoreCorrectionListener>();
@SuppressWarnings("unchecked")
Map<? extends Leaderboard, ? extends MetaLeaderboardColumn> columnsForLeaderboardAsStrongMap = (Map<? extends Leaderboard, ? extends MetaLeaderboardColumn>) ois.readObject();
columnsForLeaderboards = new WeakHashMap<Leaderboard, MetaLeaderboardColumn>(columnsForLeaderboardAsStrongMap);
@SuppressWarnings("unchecked")
Map<? extends Leaderboard, ? extends ScoreCorrectionListener> scoreCorrectionChangeForwardersByLeaderboardAsStrongMap = (Map<? extends Leaderboard, ? extends ScoreCorrectionListener>) ois.readObject();
scoreCorrectionChangeForwardersByLeaderboard = new WeakHashMap<Leaderboard, ScoreCorrectionListener>(scoreCorrectionChangeForwardersByLeaderboardAsStrongMap);
}
public abstract Iterable<Leaderboard> getLeaderboards();
@@ -134,7 +158,7 @@ public abstract class AbstractMetaLeaderboard extends AbstractSimpleLeaderboardI
}
protected RaceColumn getColumnForLeaderboard(Leaderboard leaderboard) {
RaceColumn result = columnsForLeaderboards.get(leaderboard);
MetaLeaderboardColumn result = columnsForLeaderboards.get(leaderboard);
if (result == null) {
result = new MetaLeaderboardColumn(leaderboard, metaFleet);
result.addRaceColumnListener(this);
@@ -435,6 +435,7 @@ public abstract class TrackedRaceImpl implements TrackedRace, CourseListener {
directionFromStartToNextMarkCache = new HashMap<TimePoint, Future<Wind>>();
crossTrackErrorCache = new CrossTrackErrorCache(this);
maneuverCache = createManeuverCache();
logger.info("Deserialized race " + getRace().getName());
}
@Override
@@ -1626,12 +1627,14 @@ public abstract class TrackedRaceImpl implements TrackedRace, CourseListener {
clearDirectionFromStartToNextMarkCache();
stopAndRemoveStartToNextMarkCacheInvalidationListener(waypointThatGotRemoved);
Iterator<Waypoint> waypointsIter = getRace().getCourse().getWaypoints().iterator();
waypointsIter.next(); // skip first
if (waypointsIter.hasNext()) {
waypointsIter.next(); // skip second
if (waypointsIter.hasNext()) { // catches the case of a course being empty
waypointsIter.next(); // skip first
if (waypointsIter.hasNext()) {
Waypoint newSecond = waypointsIter.next();
addStartToNextMarkCacheInvalidationListener(newSecond);
waypointsIter.next(); // skip second
if (waypointsIter.hasNext()) {
Waypoint newSecond = waypointsIter.next();
addStartToNextMarkCacheInvalidationListener(newSecond);
}
}
}
}
@@ -2443,7 +2446,11 @@ public abstract class TrackedRaceImpl implements TrackedRace, CourseListener {
@Override
public void attachRaceLog(RaceLog raceLog) {
this.attachedRaceLogs.put(raceLog.getId(), raceLog);
if (raceLog != null) {
this.attachedRaceLogs.put(raceLog.getId(), raceLog);
} else {
logger.severe("Got a request to attach race log for an empty race log!");
}
}
@Override
@@ -4,7 +4,7 @@
<stringAttribute key="com.google.gdt.eclipse.suiteMainTypeProcessor.PREVIOUSLY_SET_MAIN_TYPE_NAME" value="com.google.gwt.dev.GWTShell"/>
<booleanAttribute key="com.google.gdt.eclipse.suiteWarArgumentProcessor.IS_WAR_FROM_PROJECT_PROPERTIES" value="true"/>
<listAttribute key="com.google.gwt.eclipse.core.ENTRY_POINT_MODULES">
<listEntry value="com.sap.sailing.gwt.ui.Simulator"/>
<listEntry value="com.sap.sailing.gwt.ui.PolarSheets"/>
</listAttribute>
<stringAttribute key="com.google.gwt.eclipse.core.URL" value="/gwt/AdminConsole.html"/>
<listAttribute key="org.eclipse.debug.core.MAPPED_RESOURCE_PATHS">
@@ -21,7 +21,6 @@
<listEntry value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#13;&#10;&lt;runtimeClasspathEntry containerPath=&quot;org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.6&quot; javaProject=&quot;com.sap.sailing.gwt.ui&quot; path=&quot;1&quot; type=&quot;4&quot;/&gt;&#13;&#10;"/>
<listEntry value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#13;&#10;&lt;runtimeClasspathEntry internalArchive=&quot;/com.sap.sailing.gwt.ui/src/main/resources&quot; path=&quot;3&quot; type=&quot;2&quot;/&gt;&#13;&#10;"/>
<listEntry value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#13;&#10;&lt;runtimeClasspathEntry internalArchive=&quot;/com.sap.sailing.gwt.ui/src/main/java&quot; path=&quot;3&quot; type=&quot;2&quot;/&gt;&#13;&#10;"/>
<listEntry value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#13;&#10;&lt;runtimeClasspathEntry internalArchive=&quot;/com.sap.sailing.simulator/src&quot; path=&quot;3&quot; type=&quot;2&quot;/&gt;&#13;&#10;"/>
<listEntry value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#13;&#10;&lt;runtimeClasspathEntry internalArchive=&quot;/com.sap.sailing.domain/src&quot; path=&quot;3&quot; type=&quot;2&quot;/&gt;&#13;&#10;"/>
<listEntry value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#13;&#10;&lt;runtimeClasspathEntry internalArchive=&quot;/com.googlecode.java-diff-utils/src&quot; path=&quot;3&quot; type=&quot;2&quot;/&gt;&#13;&#10;"/>
<listEntry value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#13;&#10;&lt;runtimeClasspathEntry internalArchive=&quot;/com.sap.sailing.domain.common/src&quot; path=&quot;3&quot; type=&quot;2&quot;/&gt;&#13;&#10;"/>
@@ -48,7 +47,7 @@
<stringAttribute key="org.eclipse.jdt.launching.CLASSPATH_PROVIDER" value="com.google.gwt.eclipse.core.moduleClasspathProvider"/>
<booleanAttribute key="org.eclipse.jdt.launching.DEFAULT_CLASSPATH" value="false"/>
<stringAttribute key="org.eclipse.jdt.launching.MAIN_TYPE" value="com.google.gwt.dev.DevMode"/>
<stringAttribute key="org.eclipse.jdt.launching.PROGRAM_ARGUMENTS" value="-war &quot;${project_loc:com.sap.sailing.gwt.ui}&quot; -noserver -remoteUI &quot;${gwt_remote_ui_server_port}:${unique_id}&quot; -logLevel INFO -codeServerPort 9997 -startupUrl /gwt/AdminConsole.html com.sap.sailing.gwt.ui.AdminConsole -startupUrl /gwt/LeaderboardEditing.html com.sap.sailing.gwt.ui.LeaderboardEditing -startupUrl /gwt/UserManagement.html com.sap.sailing.gwt.ui.UserManagement -startupUrl /gwt/Leaderboard.html com.sap.sailing.gwt.ui.Leaderboard -startupUrl /gwt/Spectator.html com.sap.sailing.gwt.ui.Spectator -startupUrl /gwt/RaceBoard.html com.sap.sailing.gwt.ui.RaceBoard -startupUrl /gwt/TvView.html com.sap.sailing.gwt.ui.TvView -startupUrl /gwt/PolarSheets.html com.sap.sailing.gwt.ui.PolarSheets -startupUrl /gwt/RegattaOverview.html com.sap.sailing.gwt.ui.RegattaOverview -startupUrl /gwt/Simulator.html com.sap.sailing.gwt.ui.Simulator"/>
<stringAttribute key="org.eclipse.jdt.launching.PROGRAM_ARGUMENTS" value="-war &quot;${project_loc:com.sap.sailing.gwt.ui}&quot; -noserver -remoteUI &quot;${gwt_remote_ui_server_port}:${unique_id}&quot; -logLevel INFO -codeServerPort 9997 -startupUrl /gwt/AdminConsole.html com.sap.sailing.gwt.ui.AdminConsole -startupUrl /gwt/LeaderboardEditing.html com.sap.sailing.gwt.ui.LeaderboardEditing -startupUrl /gwt/UserManagement.html com.sap.sailing.gwt.ui.UserManagement -startupUrl /gwt/Leaderboard.html com.sap.sailing.gwt.ui.Leaderboard -startupUrl /gwt/Spectator.html com.sap.sailing.gwt.ui.Spectator -startupUrl /gwt/RaceBoard.html com.sap.sailing.gwt.ui.RaceBoard -startupUrl /gwt/TvView.html com.sap.sailing.gwt.ui.TvView -startupUrl /gwt/PolarSheets.html com.sap.sailing.gwt.ui.PolarSheets -startupUrl /gwt/RegattaOverview.html com.sap.sailing.gwt.ui.PolarSheets"/>
<stringAttribute key="org.eclipse.jdt.launching.PROJECT_ATTR" value="com.sap.sailing.gwt.ui"/>
<stringAttribute key="org.eclipse.jdt.launching.VM_ARGUMENTS" value="-Xmx2048m -XX:MaxPermSize=512m"/>
</launchConfiguration>
@@ -1490,24 +1490,28 @@ public class SailingServiceImpl extends ProxiedRemoteServiceServlet implements S
// set the positions of start and finish
Waypoint firstWaypoint = course.getFirstWaypoint();
if (firstWaypoint != null) {
if (firstWaypoint != null && Util.size(firstWaypoint.getMarks())==2) {
final LineLengthAndAdvantage markPositionDTOsAndLineAdvantage = trackedRace.getStartLine(dateAsTimePoint);
final List<PositionDTO> startMarkPositionDTOs = getMarkPositionDTOs(dateAsTimePoint, trackedRace, firstWaypoint);
result.startMarkPositions = startMarkPositionDTOs;
result.startLineLengthInMeters = markPositionDTOsAndLineAdvantage.getLength().getMeters();
result.startLineAngleToCombinedWind = markPositionDTOsAndLineAdvantage.getAbsoluteAngleDifferenceToTrueWind().getDegrees();
result.startLineAdvantageousSide = markPositionDTOsAndLineAdvantage.getAdvantageousSideWhileApproachingLine();
result.startLineAdvantageInMeters = markPositionDTOsAndLineAdvantage.getAdvantage().getMeters();
if (markPositionDTOsAndLineAdvantage != null) {
final List<PositionDTO> startMarkPositionDTOs = getMarkPositionDTOs(dateAsTimePoint, trackedRace, firstWaypoint);
result.startMarkPositions = startMarkPositionDTOs;
result.startLineLengthInMeters = markPositionDTOsAndLineAdvantage.getLength().getMeters();
result.startLineAngleToCombinedWind = markPositionDTOsAndLineAdvantage.getAbsoluteAngleDifferenceToTrueWind().getDegrees();
result.startLineAdvantageousSide = markPositionDTOsAndLineAdvantage.getAdvantageousSideWhileApproachingLine();
result.startLineAdvantageInMeters = markPositionDTOsAndLineAdvantage.getAdvantage().getMeters();
}
}
Waypoint lastWaypoint = course.getLastWaypoint();
if (lastWaypoint != null) {
if (lastWaypoint != null && Util.size(lastWaypoint.getMarks())==2) {
final LineLengthAndAdvantage markPositionDTOsAndLineAdvantage = trackedRace.getFinishLine(dateAsTimePoint);
final List<PositionDTO> finishMarkPositionDTOs = getMarkPositionDTOs(dateAsTimePoint, trackedRace, lastWaypoint);
result.finishMarkPositions = finishMarkPositionDTOs;
result.finishLineLengthInMeters = markPositionDTOsAndLineAdvantage.getLength().getMeters();
result.finishLineAngleToCombinedWind = markPositionDTOsAndLineAdvantage.getAbsoluteAngleDifferenceToTrueWind().getDegrees();
result.finishLineAdvantageousSide = markPositionDTOsAndLineAdvantage.getAdvantageousSideWhileApproachingLine();
result.finishLineAdvantageInMeters = markPositionDTOsAndLineAdvantage.getAdvantage().getMeters();
if (markPositionDTOsAndLineAdvantage != null) {
final List<PositionDTO> finishMarkPositionDTOs = getMarkPositionDTOs(dateAsTimePoint, trackedRace, lastWaypoint);
result.finishMarkPositions = finishMarkPositionDTOs;
result.finishLineLengthInMeters = markPositionDTOsAndLineAdvantage.getLength().getMeters();
result.finishLineAngleToCombinedWind = markPositionDTOsAndLineAdvantage.getAbsoluteAngleDifferenceToTrueWind().getDegrees();
result.finishLineAdvantageousSide = markPositionDTOsAndLineAdvantage.getAdvantageousSideWhileApproachingLine();
result.finishLineAdvantageInMeters = markPositionDTOsAndLineAdvantage.getAdvantage().getMeters();
}
}
}
}
@@ -71,6 +71,7 @@ public class LeaderboardGroupMasterDataJsonSerializer implements JsonSerializer<
jsonLeaderboardGroup.put(FIELD_DESCRIPTION, leaderboardGroup.getDescription());
jsonLeaderboardGroup.put(FIELD_HAS_OVERALL_LEADERBOARD, leaderboardGroup.getOverallLeaderboard() != null);
if (leaderboardGroup.getOverallLeaderboard() != null) {
// TODO see bug 1605; the overall leaderboard's column factors also need to be serialized
jsonLeaderboardGroup.put(FIELD_OVERALL_LEADERBOARD_DISCARDING_THRESHOLDS,
LeaderboardMasterDataJsonSerializer.createJsonForResultDiscardingRule(leaderboardGroup
.getOverallLeaderboard().getResultDiscardingRule()));
@@ -1632,7 +1632,7 @@ public class RacingEventServiceImpl implements RacingEventService, RegattaListen
logger.info("Serializing persisted competitors...");
oos.writeObject(competitorStore);
logoutput.append("Serialized " + competitorStore.size() + " persisted competitors\n");
logger.fine(logoutput.toString());
logger.info(logoutput.toString());
}
@SuppressWarnings("unchecked")
@@ -1659,6 +1659,7 @@ public class RacingEventServiceImpl implements RacingEventService, RegattaListen
}
}
logger.info("Clearing all data structures...");
regattaTrackingCache.clear();
leaderboardGroupsByName.clear();
leaderboardsByName.clear();
@@ -1668,12 +1669,14 @@ public class RacingEventServiceImpl implements RacingEventService, RegattaListen
StringBuffer logoutput = new StringBuffer();
logger.info("Reading all events...");
eventsById.putAll((Map<Serializable, Event>) ois.readObject());
logoutput.append("\nReceived " + eventsById.size() + " NEW events\n");
for (Event event : eventsById.values()) {
logoutput.append(String.format("%3s\n", event.toString()));
}
logger.info("Reading all regattas...");
regattasByName.putAll((Map<String, Regatta>) ois.readObject());
logoutput.append("Received " + regattasByName.size() + " NEW regattas\n");
for (Regatta regatta : regattasByName.values()) {
@@ -1682,19 +1685,23 @@ public class RacingEventServiceImpl implements RacingEventService, RegattaListen
// it is important that the leaderboards and tracked regattas are cleared before auto-linking to
// old leaderboards takes place which then don't match the new ones
logger.info("Reading all dynamic tracked regattas...");
for (DynamicTrackedRegatta trackedRegattaToObserve : (Set<DynamicTrackedRegatta>) ois.readObject()) {
ensureRegattaIsObservedForDefaultLeaderboardAndAutoLeaderboardLinking(trackedRegattaToObserve);
}
logger.info("Reading all of the regatta tracking cache...");
regattaTrackingCache.putAll((Map<Regatta, DynamicTrackedRegatta>) ois.readObject());
logoutput.append("Received " + regattaTrackingCache.size() + " NEW regatta tracking cache entries\n");
logger.info("Reading leaderboard groups...");
leaderboardGroupsByName.putAll((Map<String, LeaderboardGroup>) ois.readObject());
logoutput.append("Received " + leaderboardGroupsByName.size() + " NEW leaderboard groups\n");
for (LeaderboardGroup lg : leaderboardGroupsByName.values()) {
logoutput.append(String.format("%3s\n", lg.toString()));
}
logger.info("Reading leaderboards by name...");
leaderboardsByName.putAll((Map<String, Leaderboard>) ois.readObject());
logoutput.append("Received " + leaderboardsByName.size() + " NEW leaderboards\n");
for (Leaderboard leaderboard : leaderboardsByName.values()) {
@@ -1709,6 +1716,7 @@ public class RacingEventServiceImpl implements RacingEventService, RegattaListen
}
}
logger.info("Reading media library...");
mediaLibrary.deserialize(ois);
logoutput.append("Received " + mediaLibrary.allTracks().size() + " NEW media tracks\n");
for (MediaTrack mediatrack : mediaLibrary.allTracks()) {
@@ -1717,14 +1725,15 @@ public class RacingEventServiceImpl implements RacingEventService, RegattaListen
// only copy the competitors from the deserialized competitor store; don't use it because it will have set
// a default Mongo object factory
logger.info("Reading competitors...");
for (Competitor competitor : ((CompetitorStore) ois.readObject()).getCompetitors()) {
DynamicCompetitor dynamicCompetitor = (DynamicCompetitor) competitor;
competitorStore.getOrCreateCompetitor(dynamicCompetitor.getId(), dynamicCompetitor.getName(), dynamicCompetitor.getTeam(), dynamicCompetitor.getBoat());
}
logoutput.append("\nReceived " + competitorStore.size() + " NEW competitors\n");
logger.info(logoutput.toString());
logger.info("Done with initial replication on " + this);
logger.info(logoutput.toString());
} finally {
Thread.currentThread().setContextClassLoader(oldContextClassloader);
}
@@ -169,8 +169,10 @@ public class RegattaDataPerRaceAction extends HttpAction {
final Element competitors_node = addNamedElement(race_node, "competitors"); // add node that contains all competitors
for (Competitor competitor : trackedRace.getCompetitorsFromBestToWorst(trackedRace.getEndOfTracking())) {
int rank = 0;
List<Competitor> competitorsFromBestToWorst = leaderboard.getCompetitorsFromBestToWorst(trackedRace.getEndOfTracking());
for (Competitor competitor : competitorsFromBestToWorst) {
rank += 1;
final Element competitor_node = addNamedElement(competitors_node, "competitor"); // add competitor node
try {
@@ -200,9 +202,9 @@ public class RegattaDataPerRaceAction extends HttpAction {
addNamedElementWithValue(competitor_node, "sail_id_formatted", sail_id);
}
addNamedElementWithValue(competitor_node, "race_final_rank", trackedRace.getRank(competitor, now));
addNamedElementWithValue(competitor_node, "race_final_rank", rank);
addNamedElementWithValue(competitor_node, "race_participants", trackedRace.getCompetitorsFromBestToWorst(trackedRace.getStartOfTracking()).size());
addNamedElementWithValue(competitor_node, "race_relative_final_rank", 1.0 - ((trackedRace.getRank(competitor, now) - 1.0)/(trackedRace.getCompetitorsFromBestToWorst(trackedRace.getStartOfTracking()).size() - 1.0)));
addNamedElementWithValue(competitor_node, "race_relative_final_rank", 1.0 - ((rank - 1.0)/(leaderboard.getCompetitorsFromBestToWorst(trackedRace.getStartOfTracking()).size() - 1.0)));
addNamedElementWithValue(competitor_node, "distance_traveled_m", trackedRace.getDistanceTraveled(competitor, trackedRace.getEndOfTracking()).getMeters());
addNamedElementWithValue(competitor_node, "avg_xte_m", trackedRace.getAverageCrossTrackError(competitor, trackedRace.getEndOfTracking(), true).getMeters());
@@ -278,7 +280,7 @@ public class RegattaDataPerRaceAction extends HttpAction {
addNamedElementWithValue(competitor_node, "rank_gains", posGLlist.toString()); // Ranks Gained/Lost
addNamedElementWithValue(competitor_node, "rank_after_first_leg", rankAfterFirstLeg); // Rank after first leg
addNamedElementWithValue(competitor_node, "rank_gain_between_first_and_finish", rankAfterFirstLeg - trackedRace.getRank(competitor, now)); // Rank gain between first leg and finish
addNamedElementWithValue(competitor_node, "rank_gain_between_first_and_finish", rankAfterFirstLeg - rank); // Rank gain between first leg and finish
addNamedElementWithValue(competitor_node, "race_time_s", race_time);
+3 -1
View File
@@ -56,4 +56,6 @@ The links above lead to short write-ups of the respective business case behind t
[[ISAF-Internal Projects|wiki/planning/ISAFInternalProjects]]
[[Microcopter Integration|wiki/planning/Microcopter]]
[[Microcopter Integration|wiki/planning/Microcopter]]
[[Race Rendering Technology|wiki/planning/RaceRenderingTechnology]]
+78
View File
@@ -0,0 +1,78 @@
# Rendering Technologies for Races
Here we want to collect technology options to build a new innovative race viewer.
## Usage scenarios
* TV + data overlays
* Deep analytics
* Casual user race viewer
* Big screen / public viewing
* Raw data viewer (jury support)
* Moderator cockpit
## Unity Gaming Engine
Unity is a cross-platform game engine with a built-in IDE developed by Unity Technologies. It is used to develop video games for web plugins, desktop platforms, consoles and mobile devices. It grew from an OS X supported game development tool in 2005 to a multi-platform game engine.
The latest update, Unity 4.3, was released November 2013. It currently supports development for iOS, Android, Windows, BlackBerry 10, OS X, Linux, web browsers, Flash, PlayStation 3, Xbox 360, Windows Phone 8, and Wii. Two versions of the game engine are available for download, Unity and Unity Pro.
* Product Owner: Unity
* Web: http://unity3d.com/
* Unity 4.3 and 2D: http://unity3d.com/unity/whats-new/unity-4.3
* Web Player Support: http://unity3d.com/webplayer/
* Mobile Support: http://unity3d.com/unity/multiplatform/mobile
## OpenLayers v3
OpenLayers is a JavaScript library for displaying map data in web browsers. It provides an API for building rich web-based geographic applications similar to Google Maps and Bing Maps.
* Product Owner: Opensource
* Web: http://ol3js.org/
* Demos: http://ol3js.org/en/master/examples/
* Map rotation demo : http://ol3js.org/en/master/examples/drag-rotate-and-zoom.html
* Licence: BSD
## Lienzo Framework
Lienzo allows you to build scalable graphics applications (in Java) that will run in any browser or device that supports the HTML5 Canvas API, including smart phones and tablets.
* Product Owner: Emitrom
* Web: http://emitrom.com/lienzo
* Demos: http://emitrom-lienzo.appspot.com/
* Technology: GWT
* Licence: Apache
## Google Maps
* Product Owner: Google
* Web: https://developers.google.com/maps/documentation/javascript/
* Technology: Javascript
* Licence: Google Licence
Google Maps based on WebGL
## CAAT: Canvas Advanced Animation Tookit
CAAT is a director-based Scene graph manager.
It is able to render using Canvas, WebGL and CSS without making changes to the applications that sit on top of it.
* Product Owner
* Web: https://github.com/hyperandroid/caat
* Demos: http://hyperandroid.github.io/CAAT/documentation/demos/
* Affine transformations demo: http://hyperandroid.github.io/CAAT/documentation/demos/demo7/anchors_org.html
* Licence: MIT
* Technology: Javascript
## D3
D3 is a JavaScript library for manipulating documents based on data. D3 helps you bring data to life using HTML, SVG and CSS. D3’s emphasis on web standards gives you the full capabilities of modern browsers without tying yourself to a proprietary framework, combining powerful visualization components and a data-driven approach to DOM manipulation.
* Product Owner: OpenSource
* Web: http://d3js.org/
* Demos: https://github.com/mbostock/d3/wiki/Gallery
* Wind field demo: http://air.nullschool.net/
* Technology: Javascript
* Licence: BSD
## Standards to consider
### GeoJson
* http://en.wikipedia.org/wiki/GeoJSON
* MongoDB Geo support. http://docs.mongodb.org/manual/applications/geospatial-indexes/
### WebGL
* http://en.wikipedia.org/wiki/WebGL
* Demos: http://www.chromeexperiments.com/webgl/
## Other cool stuff
* XNA Planet Renderer - Terrain & Ocean: http://www.youtube.com/watch?v=OiGADgezjC8
+12
View File
@@ -0,0 +1,12 @@
# Webdesign
This document contains some information for web designers and user interaction experts
### Layout Repository
#### Git
1. Get the content of the layout git repository
Clone the repository to your local file system from `ssh://[SAP-User]@git.wdf.sap.corp:29418/SAPSail/sapsailing_layouts.git`
2. Check out the 'master' branch from the git repository. The 'master' branch is the main branch. Please check that you start your work on this branch.