From e6f9f86f52353b1dd9ad4ffbb53c36b421334e26 Mon Sep 17 00:00:00 2001 From: Frank Mittag Date: Tue, 12 Nov 2013 13:59:35 +0100 Subject: [PATCH 01/22] Updated home (markdown) --- home.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/home.md b/home.md index f7e1bd80e7f..be197f82e95 100644 --- a/home.md +++ b/home.md @@ -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 + * [[Webdesign repository|wiki/webdesign]] * General Information * [[Architecture and Infrastructure|wiki/architecture-and-infrastructure]] * [[Sailing Domain Algorithms|wiki/sailing-domain-algorithms]] From c77ea5fc00f3b8a8b2f675268855802f9f945494 Mon Sep 17 00:00:00 2001 From: Frank Mittag Date: Tue, 12 Nov 2013 14:02:43 +0100 Subject: [PATCH 02/22] Created webdesign (markdown) --- wiki/webdesign.md | 12 ++++++++++++ 1 file changed, 12 insertions(+) create mode 100644 wiki/webdesign.md diff --git a/wiki/webdesign.md b/wiki/webdesign.md new file mode 100644 index 00000000000..4fcfaf5db54 --- /dev/null +++ b/wiki/webdesign.md @@ -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. From 0c2163ea0f57feec44952d9f534bd064bf02e369 Mon Sep 17 00:00:00 2001 From: Frank Mittag Date: Tue, 12 Nov 2013 14:03:43 +0100 Subject: [PATCH 03/22] Updated webdesign (markdown) --- wiki/webdesign.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wiki/webdesign.md b/wiki/webdesign.md index 4fcfaf5db54..f35bb6ac8d4 100644 --- a/wiki/webdesign.md +++ b/wiki/webdesign.md @@ -7,6 +7,6 @@ This document contains some information for web designers and user interaction e #### 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` +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. From e50d5ec49d96925630d5e978bd27ebad39889705 Mon Sep 17 00:00:00 2001 From: Frank Mittag Date: Tue, 12 Nov 2013 14:04:18 +0100 Subject: [PATCH 04/22] Updated home (markdown) --- home.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/home.md b/home.md index be197f82e95..e2e7a8403d0 100644 --- a/home.md +++ b/home.md @@ -26,7 +26,7 @@ Like businesses, sailors need the latest information to make strategic decisions * [[Working with GWT Locally|wiki/local-gwt]] * [[Mobile Development|wiki/mobile-development]] * Information for Webdesigners - * [[Webdesign repository|wiki/webdesign]] + * [[Layout repository|wiki/webdesign]] * General Information * [[Architecture and Infrastructure|wiki/architecture-and-infrastructure]] * [[Sailing Domain Algorithms|wiki/sailing-domain-algorithms]] From 373ea945da66030eb7b6e2d04be950699447538d Mon Sep 17 00:00:00 2001 From: Frank Mittag Date: Thu, 14 Nov 2013 13:32:03 +0100 Subject: [PATCH 05/22] Updated planning (markdown) --- wiki/planning.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/wiki/planning.md b/wiki/planning.md index 499381d32da..fade3609ed5 100644 --- a/wiki/planning.md +++ b/wiki/planning.md @@ -52,4 +52,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]] \ No newline at end of file +[[Microcopter Integration|wiki/planning/Microcopter]] + +[[Race Rendering Technology|wiki/planning/RaceRenderingTechnology]] From cdd8eb4f45004f2584aa1e42dd7ea09a7ad423e8 Mon Sep 17 00:00:00 2001 From: Frank Mittag Date: Thu, 14 Nov 2013 13:51:52 +0100 Subject: [PATCH 06/22] Created racerenderingtechnology (markdown) --- wiki/planning/racerenderingtechnology.md | 67 ++++++++++++++++++++++++ 1 file changed, 67 insertions(+) create mode 100644 wiki/planning/racerenderingtechnology.md diff --git a/wiki/planning/racerenderingtechnology.md b/wiki/planning/racerenderingtechnology.md new file mode 100644 index 00000000000..fbd8b7a4df3 --- /dev/null +++ b/wiki/planning/racerenderingtechnology.md @@ -0,0 +1,67 @@ +# Rendering Technologies for Races + +Here we want to collect technology options to build a new innovative race viewer. + +## 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 + +* 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 +* 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 +* 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 From 39c432beca9ed557616761b45276f5a5d89f2d12 Mon Sep 17 00:00:00 2001 From: Frank Mittag Date: Thu, 14 Nov 2013 14:17:19 +0100 Subject: [PATCH 07/22] Updated racerenderingtechnology (markdown) --- wiki/planning/racerenderingtechnology.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/wiki/planning/racerenderingtechnology.md b/wiki/planning/racerenderingtechnology.md index fbd8b7a4df3..d313efebf78 100644 --- a/wiki/planning/racerenderingtechnology.md +++ b/wiki/planning/racerenderingtechnology.md @@ -22,7 +22,7 @@ OpenLayers is a JavaScript library for displaying map data in web browsers. It p * 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/ @@ -38,6 +38,8 @@ OpenLayers is a JavaScript library for displaying map data in web browsers. It p 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/ @@ -46,6 +48,7 @@ Google Maps based on WebGL * 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 From 9c0d011416f50e385aeec7505b67dca2891baf8b Mon Sep 17 00:00:00 2001 From: Axel Uhl Date: Thu, 14 Nov 2013 15:20:43 +0100 Subject: [PATCH 08/22] start and finish are not necessarily a line; fixed NPE --- .../gwt/ui/server/SailingServiceImpl.java | 32 +++++++++++-------- 1 file changed, 18 insertions(+), 14 deletions(-) diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/server/SailingServiceImpl.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/server/SailingServiceImpl.java index a6a900b74cc..81a0231341a 100755 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/server/SailingServiceImpl.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/server/SailingServiceImpl.java @@ -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 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 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 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 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(); + } } } } From e2089f4e701a540f321d40dc95dce36ddff01d4e Mon Sep 17 00:00:00 2001 From: Axel Uhl Date: Thu, 14 Nov 2013 15:26:50 +0100 Subject: [PATCH 09/22] fixing NoSuchElementException in TrackedRaceImpl.updateStartToNextMarkCacheInvalidationCacheListenersAfterWaypointRemoved for empty course --- .../domain/tracking/impl/TrackedRaceImpl.java | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/impl/TrackedRaceImpl.java b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/impl/TrackedRaceImpl.java index 5b4dd9efb29..d72efce6bd4 100755 --- a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/impl/TrackedRaceImpl.java +++ b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/impl/TrackedRaceImpl.java @@ -1626,12 +1626,14 @@ public abstract class TrackedRaceImpl implements TrackedRace, CourseListener { clearDirectionFromStartToNextMarkCache(); stopAndRemoveStartToNextMarkCacheInvalidationListener(waypointThatGotRemoved); Iterator 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); + } } } } From 54d679ce33b88261aaa58b1b79fcd03cb7bd89a3 Mon Sep 17 00:00:00 2001 From: Frank Mittag Date: Thu, 14 Nov 2013 18:28:41 +0100 Subject: [PATCH 10/22] Updated racerenderingtechnology (markdown) --- wiki/planning/racerenderingtechnology.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/wiki/planning/racerenderingtechnology.md b/wiki/planning/racerenderingtechnology.md index d313efebf78..eeedd178e33 100644 --- a/wiki/planning/racerenderingtechnology.md +++ b/wiki/planning/racerenderingtechnology.md @@ -2,6 +2,14 @@ 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. From 0b462e04e3e22c0a2e1790cd638251f195d58955 Mon Sep 17 00:00:00 2001 From: Simon Pamies Date: Thu, 14 Nov 2013 18:25:38 -0200 Subject: [PATCH 11/22] Making sure to always use score corrected rank --- .../xcelsiusadapter/RegattaDataPerRaceAction.java | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/java/com.sap.sailing.xcelsiusadapter/src/com/sap/sailing/xcelsiusadapter/RegattaDataPerRaceAction.java b/java/com.sap.sailing.xcelsiusadapter/src/com/sap/sailing/xcelsiusadapter/RegattaDataPerRaceAction.java index 63e126653f5..b1fc52e3e38 100644 --- a/java/com.sap.sailing.xcelsiusadapter/src/com/sap/sailing/xcelsiusadapter/RegattaDataPerRaceAction.java +++ b/java/com.sap.sailing.xcelsiusadapter/src/com/sap/sailing/xcelsiusadapter/RegattaDataPerRaceAction.java @@ -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 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); From ca527bc0e65bbdbecf6666de3d0fbafe7ff2ad7e Mon Sep 17 00:00:00 2001 From: Simon Pamies Date: Thu, 14 Nov 2013 19:03:53 -0200 Subject: [PATCH 12/22] Trying to recover gracefully from endless recursion that sometimes can happen with TracTrac DataController --- .../domain/common/TrackedRaceStatusEnum.java | 2 +- .../impl/TracTracRaceTrackerImpl.java | 35 +++++++++++++++++-- 2 files changed, 33 insertions(+), 4 deletions(-) diff --git a/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/TrackedRaceStatusEnum.java b/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/TrackedRaceStatusEnum.java index 4a370b9ce88..84c7ff08162 100755 --- a/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/TrackedRaceStatusEnum.java +++ b/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/TrackedRaceStatusEnum.java @@ -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; diff --git a/java/com.sap.sailing.domain.tractracadapter/src/com/sap/sailing/domain/tractracadapter/impl/TracTracRaceTrackerImpl.java b/java/com.sap.sailing.domain.tractracadapter/src/com/sap/sailing/domain/tractracadapter/impl/TracTracRaceTrackerImpl.java index e7e22d7296f..0ba153d850c 100755 --- a/java/com.sap.sailing.domain.tractracadapter/src/com/sap/sailing/domain/tractracadapter/impl/TracTracRaceTrackerImpl.java +++ b/java/com.sap.sailing.domain.tractracadapter/src/com/sap/sailing/domain/tractracadapter/impl/TracTracRaceTrackerImpl.java @@ -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 races; private final DynamicTrackedRegatta trackedRegatta; private TrackedRaceStatus lastStatus; + private HashMap, Pair> lastProgressPerID; /** * paramURL, liveURI and storedURI for TracTrac connection @@ -192,6 +201,7 @@ public class TracTracRaceTrackerImpl extends AbstractRaceTrackerImpl implements this.races = new HashSet(); this.windStore = windStore; this.domainFactory = domainFactory; + this.lastProgressPerID = new HashMap, Pair>(); final Simulator simulator; if (simulateWithStartTimeNow) { simulator = new Simulator(windStore); @@ -673,11 +683,30 @@ 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; + if (lastProgressPerID.get(getID()) != null) { + Float lastProgress = lastProgressPerID.get(getID()).getB(); + counter = lastProgressPerID.get(getID()).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(); + throw new InterruptedException("Interrupted"); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } else { + counter += 1; + } + } } lastStatus = new TrackedRaceStatusImpl(progress==1.0 ? TrackedRaceStatusEnum.TRACKING : TrackedRaceStatusEnum.LOADING, progress); + lastProgressPerID.put(getID(), new Pair(counter, progress)); updateStatusOfTrackedRaces(); } From 5a3b0830f367ab5dc9d37a763b97b3bce4721b31 Mon Sep 17 00:00:00 2001 From: Simon Pamies Date: Thu, 14 Nov 2013 19:09:45 -0200 Subject: [PATCH 13/22] Make sure that update uri always ends with a slash --- .../sailing/domain/tractracadapter/impl/UpdateHandler.java | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/java/com.sap.sailing.domain.tractracadapter/src/com/sap/sailing/domain/tractracadapter/impl/UpdateHandler.java b/java/com.sap.sailing.domain.tractracadapter/src/com/sap/sailing/domain/tractracadapter/impl/UpdateHandler.java index cc5c1d5c722..e12246c80f7 100644 --- a/java/com.sap.sailing.domain.tractracadapter/src/com/sap/sailing/domain/tractracadapter/impl/UpdateHandler.java +++ b/java/com.sap.sailing.domain.tractracadapter/src/com/sap/sailing/domain/tractracadapter/impl/UpdateHandler.java @@ -63,8 +63,13 @@ public class UpdateHandler { } protected URL buildUpdateURL(HashMap 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), From 14f451dd27a630bcfa8f785df080cfb3d3abb14a Mon Sep 17 00:00:00 2001 From: Simon Pamies Date: Thu, 14 Nov 2013 19:57:05 -0200 Subject: [PATCH 14/22] Fixed nasty replication error with HashMap containing FutureTask instances that can't be serialized --- .../impl/AbstractSimpleLeaderboardImpl.java | 3 ++- .../sailing/server/impl/RacingEventServiceImpl.java | 11 ++++++++++- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/leaderboard/impl/AbstractSimpleLeaderboardImpl.java b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/leaderboard/impl/AbstractSimpleLeaderboardImpl.java index 61ab6408f6e..0417a2439d7 100755 --- a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/leaderboard/impl/AbstractSimpleLeaderboardImpl.java +++ b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/leaderboard/impl/AbstractSimpleLeaderboardImpl.java @@ -134,7 +134,7 @@ public abstract class AbstractSimpleLeaderboardImpl implements Leaderboard, Race private final Set suppressedCompetitors; private final NamedReentrantReadWriteLock suppressedCompetitorsLock; - private final Map, RunnableFuture> raceDetailsAtEndOfTrackingCache; + private transient Map, RunnableFuture> 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, RunnableFuture>(); this.raceDetailsExecutor = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors()); this.cacheInvalidationListeners = new HashSet(); // When many updates are triggered in a short period of time by a single thread, ensure that the single thread diff --git a/java/com.sap.sailing.server/src/com/sap/sailing/server/impl/RacingEventServiceImpl.java b/java/com.sap.sailing.server/src/com/sap/sailing/server/impl/RacingEventServiceImpl.java index b17961d69b5..1b957a76e7c 100755 --- a/java/com.sap.sailing.server/src/com/sap/sailing/server/impl/RacingEventServiceImpl.java +++ b/java/com.sap.sailing.server/src/com/sap/sailing/server/impl/RacingEventServiceImpl.java @@ -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) 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) 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) ois.readObject()) { ensureRegattaIsObservedForDefaultLeaderboardAndAutoLeaderboardLinking(trackedRegattaToObserve); } + logger.info("Reading all of the regatta tracking cache..."); regattaTrackingCache.putAll((Map) ois.readObject()); logoutput.append("Received " + regattaTrackingCache.size() + " NEW regatta tracking cache entries\n"); + logger.info("Reading leaderboard groups..."); leaderboardGroupsByName.putAll((Map) 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) 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); } From 6618e9e7f97abe96fa54a3b493766c97cba39fdd Mon Sep 17 00:00:00 2001 From: Axel Uhl Date: Thu, 14 Nov 2013 23:29:15 +0100 Subject: [PATCH 15/22] minor performance tweak for storedDataProgress; removed redundant throwing of InterruptedException --- .../tractracadapter/impl/TracTracRaceTrackerImpl.java | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/java/com.sap.sailing.domain.tractracadapter/src/com/sap/sailing/domain/tractracadapter/impl/TracTracRaceTrackerImpl.java b/java/com.sap.sailing.domain.tractracadapter/src/com/sap/sailing/domain/tractracadapter/impl/TracTracRaceTrackerImpl.java index 0ba153d850c..d758605facb 100755 --- a/java/com.sap.sailing.domain.tractracadapter/src/com/sap/sailing/domain/tractracadapter/impl/TracTracRaceTrackerImpl.java +++ b/java/com.sap.sailing.domain.tractracadapter/src/com/sap/sailing/domain/tractracadapter/impl/TracTracRaceTrackerImpl.java @@ -684,19 +684,18 @@ public class TracTracRaceTrackerImpl extends AbstractRaceTrackerImpl implements public void storedDataProgress(float progress) { logger.info("Stored data progress in tracker "+getID()+" for race(s) "+getRaces()+": "+progress); Integer counter = 0; - if (lastProgressPerID.get(getID()) != null) { - Float lastProgress = lastProgressPerID.get(getID()).getB(); - counter = lastProgressPerID.get(getID()).getA(); + final Pair 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(); - throw new InterruptedException("Interrupted"); } catch (InterruptedException e) { e.printStackTrace(); } From de7c2a2b9d4be810cdd480169a3170e0e78d1c37 Mon Sep 17 00:00:00 2001 From: Simon Pamies Date: Thu, 14 Nov 2013 22:13:47 -0200 Subject: [PATCH 16/22] It can happen that for some unknown reason the hashmap containing the racelogs has not been initialized (yet). Avoid NPE and make sure that racelogs are stored correctly. --- .../com/sap/sailing/domain/tracking/impl/TrackedRaceImpl.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/impl/TrackedRaceImpl.java b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/impl/TrackedRaceImpl.java index d72efce6bd4..f434e67e5e0 100755 --- a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/impl/TrackedRaceImpl.java +++ b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/impl/TrackedRaceImpl.java @@ -2445,6 +2445,9 @@ public abstract class TrackedRaceImpl implements TrackedRace, CourseListener { @Override public void attachRaceLog(RaceLog raceLog) { + if (this.attachedRaceLogs == null) { + this.attachedRaceLogs = new HashMap(); + } this.attachedRaceLogs.put(raceLog.getId(), raceLog); } From b9901e0ecfc004f7a1effc647c8215340ad6543f Mon Sep 17 00:00:00 2001 From: Simon Pamies Date: Fri, 15 Nov 2013 10:12:47 -0200 Subject: [PATCH 17/22] Checking for the right cause of a possible NPE --- .../sap/sailing/domain/tracking/impl/TrackedRaceImpl.java | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/impl/TrackedRaceImpl.java b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/impl/TrackedRaceImpl.java index f434e67e5e0..48104bfe561 100755 --- a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/impl/TrackedRaceImpl.java +++ b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/impl/TrackedRaceImpl.java @@ -2445,10 +2445,11 @@ public abstract class TrackedRaceImpl implements TrackedRace, CourseListener { @Override public void attachRaceLog(RaceLog raceLog) { - if (this.attachedRaceLogs == null) { - this.attachedRaceLogs = new HashMap(); + if (raceLog != null) { + this.attachedRaceLogs.put(raceLog.getId(), raceLog); + } else { + logger.severe("Got a request to attach race log for an empty race log!"); } - this.attachedRaceLogs.put(raceLog.getId(), raceLog); } @Override From 613e199b31b879636cc36d8454fe194013c7226c Mon Sep 17 00:00:00 2001 From: Simon Pamies Date: Fri, 15 Nov 2013 10:32:48 -0200 Subject: [PATCH 18/22] Added logging about deserialized races as this helps showing progress --- .../com/sap/sailing/domain/tracking/impl/TrackedRaceImpl.java | 1 + 1 file changed, 1 insertion(+) diff --git a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/impl/TrackedRaceImpl.java b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/impl/TrackedRaceImpl.java index 48104bfe561..322b33f36c8 100755 --- a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/impl/TrackedRaceImpl.java +++ b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/impl/TrackedRaceImpl.java @@ -435,6 +435,7 @@ public abstract class TrackedRaceImpl implements TrackedRace, CourseListener { directionFromStartToNextMarkCache = new HashMap>(); crossTrackErrorCache = new CrossTrackErrorCache(this); maneuverCache = createManeuverCache(); + logger.info("Deserialized race " + getRace().getName()); } @Override From 7009450110ee86294cdf20a6b16a703741240639 Mon Sep 17 00:00:00 2001 From: Simon Pamies Date: Fri, 15 Nov 2013 10:33:13 -0200 Subject: [PATCH 19/22] Changed logging level to see when replication has been finished --- .../src/com/sap/sailing/server/impl/RacingEventServiceImpl.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/java/com.sap.sailing.server/src/com/sap/sailing/server/impl/RacingEventServiceImpl.java b/java/com.sap.sailing.server/src/com/sap/sailing/server/impl/RacingEventServiceImpl.java index 1b957a76e7c..5ff21b0595e 100755 --- a/java/com.sap.sailing.server/src/com/sap/sailing/server/impl/RacingEventServiceImpl.java +++ b/java/com.sap.sailing.server/src/com/sap/sailing/server/impl/RacingEventServiceImpl.java @@ -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") From b5b46e9d56e8ed6d4b12fff553cb0d1f3eb0dbc2 Mon Sep 17 00:00:00 2001 From: Axel Uhl Date: Fri, 15 Nov 2013 15:04:12 +0100 Subject: [PATCH 20/22] added failing test case for bug 1605 (serialization of factors on overall leaderboards) --- .../domain/test/OfflineSerializationTest.java | 25 ++++++++++++++++++- .../meta/AbstractMetaLeaderboard.java | 4 +-- java/com.sap.sailing.gwt.ui/SailingGWT.launch | 5 ++-- ...derboardGroupMasterDataJsonSerializer.java | 1 + 4 files changed, 29 insertions(+), 6 deletions(-) diff --git a/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/OfflineSerializationTest.java b/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/OfflineSerializationTest.java index d52445f78f3..0219fb6699a 100755 --- a/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/OfflineSerializationTest.java +++ b/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/OfflineSerializationTest.java @@ -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(); diff --git a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/leaderboard/meta/AbstractMetaLeaderboard.java b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/leaderboard/meta/AbstractMetaLeaderboard.java index aeb39a751b8..bdffc4b2b18 100755 --- a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/leaderboard/meta/AbstractMetaLeaderboard.java +++ b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/leaderboard/meta/AbstractMetaLeaderboard.java @@ -48,7 +48,7 @@ public abstract class AbstractMetaLeaderboard extends AbstractSimpleLeaderboardI private final Fleet metaFleet; private final ScoringScheme scoringScheme; private final String name; - private transient WeakHashMap columnsForLeaderboards; + private transient WeakHashMap columnsForLeaderboards; private transient WeakHashMap scoreCorrectionChangeForwardersByLeaderboard; private class ScoreCorrectionChangeForwarder implements ScoreCorrectionListener { @@ -134,7 +134,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); diff --git a/java/com.sap.sailing.gwt.ui/SailingGWT.launch b/java/com.sap.sailing.gwt.ui/SailingGWT.launch index d3acf8a9e01..d6c65c5debc 100755 --- a/java/com.sap.sailing.gwt.ui/SailingGWT.launch +++ b/java/com.sap.sailing.gwt.ui/SailingGWT.launch @@ -4,7 +4,7 @@ - + @@ -21,7 +21,6 @@ - @@ -48,7 +47,7 @@ - + diff --git a/java/com.sap.sailing.server.gateway.serialization/src/com/sap/sailing/server/gateway/serialization/masterdata/impl/LeaderboardGroupMasterDataJsonSerializer.java b/java/com.sap.sailing.server.gateway.serialization/src/com/sap/sailing/server/gateway/serialization/masterdata/impl/LeaderboardGroupMasterDataJsonSerializer.java index c16ded207a3..5d70ae1ab15 100644 --- a/java/com.sap.sailing.server.gateway.serialization/src/com/sap/sailing/server/gateway/serialization/masterdata/impl/LeaderboardGroupMasterDataJsonSerializer.java +++ b/java/com.sap.sailing.server.gateway.serialization/src/com/sap/sailing/server/gateway/serialization/masterdata/impl/LeaderboardGroupMasterDataJsonSerializer.java @@ -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())); From efac9b14e0a075bef1b8fc03c24ef5ceebbd1266 Mon Sep 17 00:00:00 2001 From: Axel Uhl Date: Fri, 15 Nov 2013 15:13:03 +0100 Subject: [PATCH 21/22] fixed bug 1605 by serializing the transient WeakHashMaps through HashMaps and copying into the WeakHashMaps after deserialization again --- .../meta/AbstractMetaLeaderboard.java | 32 ++++++++++++++++--- 1 file changed, 28 insertions(+), 4 deletions(-) diff --git a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/leaderboard/meta/AbstractMetaLeaderboard.java b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/leaderboard/meta/AbstractMetaLeaderboard.java index bdffc4b2b18..3908026462b 100755 --- a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/leaderboard/meta/AbstractMetaLeaderboard.java +++ b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/leaderboard/meta/AbstractMetaLeaderboard.java @@ -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; + + /** + * 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 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 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(columnsForLeaderboards)); + oos.writeObject(new HashMap(scoreCorrectionChangeForwardersByLeaderboard)); + } private void readObject(ObjectInputStream ois) throws ClassNotFoundException, IOException { ois.defaultReadObject(); - columnsForLeaderboards = new WeakHashMap<>(); - scoreCorrectionChangeForwardersByLeaderboard = new WeakHashMap(); + @SuppressWarnings("unchecked") + Map columnsForLeaderboardAsStrongMap = (Map) ois.readObject(); + columnsForLeaderboards = new WeakHashMap(columnsForLeaderboardAsStrongMap); + @SuppressWarnings("unchecked") + Map scoreCorrectionChangeForwardersByLeaderboardAsStrongMap = (Map) ois.readObject(); + scoreCorrectionChangeForwardersByLeaderboard = new WeakHashMap(scoreCorrectionChangeForwardersByLeaderboardAsStrongMap); } public abstract Iterable getLeaderboards(); From 1ec26d9e90bdf4af35251fe2ebaeeca47ab8e19f Mon Sep 17 00:00:00 2001 From: Axel Uhl Date: Fri, 15 Nov 2013 15:31:18 +0100 Subject: [PATCH 22/22] use local tunnel --- .../SailingDomainTest (Proxy).launch | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/java/com.sap.sailing.domain.test/SailingDomainTest (Proxy).launch b/java/com.sap.sailing.domain.test/SailingDomainTest (Proxy).launch index d4bfd80bb8b..2000cb87e8f 100755 --- a/java/com.sap.sailing.domain.test/SailingDomainTest (Proxy).launch +++ b/java/com.sap.sailing.domain.test/SailingDomainTest (Proxy).launch @@ -16,5 +16,5 @@ - +