Merge branch 'master' into foiling

This commit is contained in:
Steffen Schaefer
2016-06-29 09:01:17 +02:00
18 changed files with 184 additions and 102 deletions
@@ -5,5 +5,5 @@ public enum ScoringSchemeType {
LOW_POINT, HIGH_POINT, HIGH_POINT_ESS_OVERALL,HIGH_POINT_ESS_OVERALL_12, HIGH_POINT_LAST_BREAKS_TIE, HIGH_POINT_FIRST_GETS_TEN,
HIGH_POINT_FIRST_GETS_ONE, LOW_POINT_WINNER_GETS_ZERO, HIGH_POINT_WINNER_GETS_SIX, HIGH_POINT_WINNER_GETS_FIVE, HIGH_POINT_WINNER_GETS_EIGHT,
HIGH_POINT_WINNER_GETS_EIGHT_AND_INTERPOLATION, HIGH_POINT_FIRST_GETS_TEN_OR_EIGHT, HIGH_POINT_FIRST_GETS_TWELVE_OR_EIGHT, LOW_POINT_WITH_ELIMINATIONS_AND_ROUNDS_WINNER_GETS_07,
LOW_POINT_LEAGUE_OVERALL
LOW_POINT_LEAGUE_OVERALL, HIGH_POINT_MATCH_RACING
}
@@ -1,5 +1,7 @@
package com.sap.sailing.domain.igtimiadapter;
import java.net.InetSocketAddress;
public interface LiveDataConnection {
/**
* Disconnects this connection. Afterwards, the connection will no longer feed live data to its listener(s).
@@ -18,4 +20,6 @@ public interface LiveDataConnection {
void addListener(BulkFixReceiver listener);
void removeListener(BulkFixReceiver listener);
InetSocketAddress getRemoteAddress();
}
@@ -132,6 +132,10 @@ public class IgtimiConnectionFactoryImpl implements IgtimiConnectionFactory {
return new ArrayList<Account>(accountsByEmail.values());
}
public IgtimiConnection getConnectionOfAccount(Account account) {
return connectionsByAccount.get(account);
}
@Override
public IgtimiConnection connect(Account account) {
IgtimiConnection connection;
@@ -1,5 +1,7 @@
package com.sap.sailing.domain.igtimiadapter.websocket;
import java.net.InetSocketAddress;
import com.sap.sailing.domain.igtimiadapter.BulkFixReceiver;
import com.sap.sailing.domain.igtimiadapter.LiveDataConnection;
@@ -45,4 +47,9 @@ public class LiveDataConnectionWrapper implements LiveDataConnection {
LiveDataConnection getActualConnection() {
return actualConnection;
}
@Override
public InetSocketAddress getRemoteAddress() {
return actualConnection.getRemoteAddress();
}
}
@@ -1,6 +1,7 @@
package com.sap.sailing.domain.igtimiadapter.websocket;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.URI;
import java.util.ArrayList;
import java.util.List;
@@ -150,7 +151,7 @@ public class WebSocketConnectionManager extends WebSocketAdapter implements Live
public com.sap.sse.common.Util.Pair<TimePoint, TimePoint> getIgtimiServerTimePointAndWhenItWasReceived() {
return new com.sap.sse.common.Util.Pair<TimePoint, TimePoint>(igtimiServerTimepoint, localTimepointWhenServerTimepointWasReceived);
}
@Override
public void addListener(BulkFixReceiver listener) {
listeners.put(listener, listener);
@@ -250,4 +251,9 @@ public class WebSocketConnectionManager extends WebSocketAdapter implements Live
throw lastException;
}
}
@Override
public InetSocketAddress getRemoteAddress() {
return getSession().getRemoteAddress();
}
}
@@ -510,6 +510,34 @@ public class LeaderboardScoringAndRankingTest extends AbstractLeaderboardTest {
}
}
@Test
public void testHighPointMatchRacingScoringScheme() throws NoWindException {
List<Competitor> competitors = createCompetitors(2);
Competitor c1 = competitors.get(0);
Competitor c2 = competitors.get(1);
Regatta regatta = createSimpleRegatta(3, "Match Racing Test",
DomainFactory.INSTANCE.getOrCreateBoatClass("ESS40", /* typicallyStartsUpwind */false),
DomainFactory.INSTANCE.createScoringScheme(ScoringSchemeType.HIGH_POINT_MATCH_RACING));
Leaderboard leaderboard = createLeaderboard(regatta, /* discarding thresholds */ new int[0]);
TimePoint now = MillisecondsTimePoint.now();
TimePoint later = new MillisecondsTimePoint(now.asMillis()+1000);
RaceColumn r1Column = series.get(0).getRaceColumnByName("R1");
TrackedRace r1 = new MockedTrackedRaceWithStartTimeAndRanks(now, competitors);
r1Column.setTrackedRace(r1Column.getFleetByName("Default"), r1);
assertEquals(1, r1Column.getTrackedRace(c1).getRank(c1, later));
assertEquals(1, leaderboard.getTrackedRank(c1, r1Column, later));
assertEquals(1, leaderboard.getTotalPoints(c1, r1Column, later), 0.00000001);
assertEquals(2, r1Column.getTrackedRace(c2).getRank(c2, later));
assertEquals(2, leaderboard.getTrackedRank(c2, r1Column, later));
assertEquals(0, leaderboard.getTotalPoints(c2, r1Column, later), 0.00000001);
List<Competitor> rankedCompetitors = leaderboard.getCompetitorsFromBestToWorst(later);
assertSame(c1, rankedCompetitors.get(0));
assertSame(c2, rankedCompetitors.get(1));
}
@Test
public void testDistributionAcrossFinalFleetsWithDifferentScores() throws NoWindException {
List<Competitor> competitors = createCompetitors(10);
@@ -1814,6 +1842,25 @@ public class LeaderboardScoringAndRankingTest extends AbstractLeaderboardTest {
return result;
}
private Regatta createSimpleRegatta(final int numberOfRaces, final String regattaName, BoatClass boatClass, ScoringScheme scoringScheme) {
series = new ArrayList<Series>();
List<Fleet> fleets = new ArrayList<Fleet>();
fleets.add(new FleetImpl("Default"));
List<String> raceColumnNames = new ArrayList<String>();
for (int i = 1; i <= numberOfRaces; i++) {
raceColumnNames.add("R" + i);
}
Series defaultSeries = new SeriesImpl("Default", /* isMedal */false, /* isFleetsCanRunInParallel */true,
fleets, raceColumnNames, /* trackedRegattaRegistry */null);
series.add(defaultSeries);
Regatta regatta = new RegattaImpl(RegattaImpl.getDefaultName(regattaName, boatClass.getName()), boatClass,
/* startDate */null, /* endDate */null, series, /* persistent */false, scoringScheme, "123", null,
OneDesignRankingMetric::new);
return regatta;
}
private Regatta createRegatta(final int numberOfQualifyingRaces, String[] qualifyingFleetNames, final int numberOfFinalRaces,
String[] finalFleetNames, boolean medalRaceAndSeries, final int numberOfMedalRaces, final String regattaBaseName, BoatClass boatClass, ScoringScheme scoringScheme) {
series = new ArrayList<Series>();
@@ -48,6 +48,7 @@ import com.sap.sailing.domain.leaderboard.impl.HighPointLastBreaksTie;
import com.sap.sailing.domain.leaderboard.impl.HighPointWinnerGetsEight;
import com.sap.sailing.domain.leaderboard.impl.HighPointWinnerGetsEightAndInterpolation;
import com.sap.sailing.domain.leaderboard.impl.HighPointWinnerGetsFive;
import com.sap.sailing.domain.leaderboard.impl.HighPointMatchRacing;
import com.sap.sailing.domain.leaderboard.impl.HighPointWinnerGetsSix;
import com.sap.sailing.domain.leaderboard.impl.LowPoint;
import com.sap.sailing.domain.leaderboard.impl.LowPointForLeagueOverallLeaderboard;
@@ -114,6 +115,8 @@ public class DomainFactoryImpl extends SharedDomainFactoryImpl implements Domain
return new HighPointWinnerGetsSix();
case HIGH_POINT_WINNER_GETS_EIGHT:
return new HighPointWinnerGetsEight();
case HIGH_POINT_MATCH_RACING:
return new HighPointMatchRacing();
case HIGH_POINT_WINNER_GETS_EIGHT_AND_INTERPOLATION:
return new HighPointWinnerGetsEightAndInterpolation();
case HIGH_POINT_FIRST_GETS_TEN_OR_EIGHT:
@@ -0,0 +1,32 @@
package com.sap.sailing.domain.leaderboard.impl;
import java.util.concurrent.Callable;
import com.sap.sailing.domain.base.Competitor;
import com.sap.sailing.domain.base.RaceColumn;
import com.sap.sailing.domain.common.ScoringSchemeType;
import com.sap.sailing.domain.leaderboard.Leaderboard;
import com.sap.sailing.domain.leaderboard.NumberOfCompetitorsInLeaderboardFetcher;
import com.sap.sse.common.TimePoint;
/**
* Scoring system indented to by used for match racing where the winner gets 1 points and the loser gets 0 points
*/
public class HighPointMatchRacing extends HighPoint {
private static final long serialVersionUID = 9124974081268072297L;
public HighPointMatchRacing() {
}
@Override
public ScoringSchemeType getType() {
return ScoringSchemeType.HIGH_POINT_MATCH_RACING;
}
@Override
public Double getScoreForRank(Leaderboard leaderboard, RaceColumn raceColumn, Competitor competitor, int rank,
Callable<Integer> numberOfCompetitorsInRaceFetcher, NumberOfCompetitorsInLeaderboardFetcher numberOfCompetitorsInLeaderboardFetcher, TimePoint timePoint) {
return rank == 1 ? 1.0 : 0.0;
}
}
@@ -419,6 +419,8 @@ public interface StringMessages extends com.sap.sse.gwt.client.StringMessages,
String scoringSchemeWinnerGetsFive();
String scoringSchemeWinnerGetsSix();
String scoringSchemeWinnerGetsEight();
String scoringSchemeHighPointMatchRacing();
String scoringSchemeHighPointMatchRacingDescription();
String scoringSchemeWinnerGetsEightAndInterpolation();
String scoringSchemeLowPointWithEliminationsAndRoundsWinnerGets07();
String scoringSchemeLowPointWithEliminationsAndRoundsWinnerGets07Description();
@@ -434,6 +434,8 @@ scoringSchemeLowPointWinnerGetsZero=Low Point System, Winner Gets Zero
scoringSchemeWinnerGetsFive=High Point System, Winner Gets 5 Points
scoringSchemeWinnerGetsSix=High Point System, Winner Gets 6 Points
scoringSchemeWinnerGetsEight=High Point System, Winner Gets 8 Points
scoringSchemeHighPointMatchRacing=High Point System, Match Racing
scoringSchemeHighPointMatchRacingDescription=The winner of the match race gets 1 point, the loser gets 0 points
scoringSchemeWinnerGetsEightAndInterpolation=High Point System, Winner 8 Points, Interpolated
scoringSchemeLowPointWithEliminationsAndRoundsWinnerGets07=Low Point with Eliminations and Rounds, Winner Gets 0.7 Points
scoringSchemeLowPointWithEliminationsAndRoundsWinnerGets07Description=A variant of the low-point scoring scheme, using eliminations consisting of rounds.\nEach round shall be modeled as a series in the regatta, and the fleet ordering counts backwards\nstarting with the highest number for the first round.\nIf a final and losers final take place, use 1 and 2 as their ordering. Start with 3 for the semi-final round.
@@ -434,6 +434,8 @@ scoringSchemeLowPointWinnerGetsZero=Low Point System, Gewinner erhält 0 Punkte
scoringSchemeWinnerGetsFive=High Point System, Gewinner erhält 5 Punkte
scoringSchemeWinnerGetsSix=High Point System, Gewinner erhält 6 Punkte
scoringSchemeWinnerGetsEight=High Point System, Gewinner erhält 8 Punkte
scoringSchemeHighPointMatchRacing=High Point System, Match Racing
scoringSchemeHighPointMatchRacingDescription=Der Gewinner erhält 1 Punkt, der Verlierer 0 Punkte
scoringSchemeWinnerGetsEightAndInterpolation=High Point System, Gewinner erhält 8 Punkte, interpoliert
scoringSchemeLowPointWithEliminationsAndRoundsWinnerGets07=Low Point System mit K.O.-Runden, Gewinner erhält 0,7 Punkte
scoringSchemeLowPointWithEliminationsAndRoundsWinnerGets07Description=Eine Variante des Low Point Systems mit mehreren K.O.-Wertungen.\nJede Runde einer Wertung wird als "Serie" in der Regatta modelliert, und die Gruppen-Ordnung wird rückwärts zählend verwendet, mit der größten Zahl für die erste Runde.\nWenn die Final-Runde in großes und kleines Finale unterteilt ist, soll das große Finale mit Ordnungszahl 1 und das kleine mit Ordnungszahl 2 modelliert werden. Das Halbfinale verwendet dann 3, usw.
@@ -432,6 +432,8 @@ scoringSchemeLowPointWinnerGetsZero=低得点方式、1 位が 0 点
scoringSchemeWinnerGetsFive=高得点方式、1 位が 5 点
scoringSchemeWinnerGetsSix=高得点方式、1 位が 6 点
scoringSchemeWinnerGetsEight=高得点方式、1 位が 8 点
scoringSchemeHighPointMatchRacing=High Point System, Match Racing
scoringSchemeHighPointMatchRacingDescription=The winner of the match race gets 1 point, the loser gets 0 points
scoringSchemeWinnerGetsEightAndInterpolation=高得点方式、1 位が 8 点、補間
scoringSchemeLowPointWithEliminationsAndRoundsWinnerGets07=低得点方式、予選およびラウンドあり、1 位が 0.7 点
scoringSchemeLowPointWithEliminationsAndRoundsWinnerGets07Description=ラウンドから構成される予選を用いた低得点方式のバリエーションです。\n各ラウンドがレガッタ内のシリーズとして形成されることになり、フリート順序は\n最初のラウンドで最も大きい数から開始してカウントダウンします。\n決勝や最下位決定戦が行われる場合は、その順序として 1 および 2 を使用します。準決勝ラウンドは 3 から始めます。
@@ -432,6 +432,8 @@ scoringSchemeLowPointWinnerGetsZero=Система низких баллов, п
scoringSchemeWinnerGetsFive=Система высоких баллов, победитель получает 5 баллов
scoringSchemeWinnerGetsSix=Система высоких баллов, победитель получает 6 баллов
scoringSchemeWinnerGetsEight=Система высоких баллов, победитель получает 8 баллов
scoringSchemeHighPointMatchRacing=High Point System, Match Racing
scoringSchemeHighPointMatchRacingDescription=The winner of the match race gets 1 point, the loser gets 0 points
scoringSchemeWinnerGetsEightAndInterpolation=Система высоких баллов, победитель 8 баллов, интерполяция
scoringSchemeLowPointWithEliminationsAndRoundsWinnerGets07=Низкий балл с турами на выбывание, победитель получает 0,7 балла
scoringSchemeLowPointWithEliminationsAndRoundsWinnerGets07Description=Вариант схемы оценки с низкими баллами, использующий туры на выбывание.\nКаждый тур моделируется как серия в регате, и суда ранжируются в обратном порядке,\nначиная с наибольшего числа за первый раунд.\nВ финале и при определении 3-го места используйте ранги 1 и 2. Для полуфинального тура начните с 3.
@@ -432,6 +432,8 @@ scoringSchemeLowPointWinnerGetsZero=低分系统,获胜者得零分
scoringSchemeWinnerGetsFive=高分系统,获胜者得 5 分
scoringSchemeWinnerGetsSix=高分系统,获胜者得 6 分
scoringSchemeWinnerGetsEight=高分系统,获胜者得 8 分
scoringSchemeHighPointMatchRacing=High Point System, Match Racing
scoringSchemeHighPointMatchRacingDescription=The winner of the match race gets 1 point, the loser gets 0 points
scoringSchemeWinnerGetsEightAndInterpolation=高分系统,获胜者 8 分,内插
scoringSchemeLowPointWithEliminationsAndRoundsWinnerGets07=采用多轮淘汰制的低分系统,获胜者得 0.7 分
scoringSchemeLowPointWithEliminationsAndRoundsWinnerGets07Description=低分记分系统的一种,采用多轮淘汰制。\n每一轮应作为比赛系列,船队顺序\n从第一轮的最高数向后计。\n如果有最终一支舰队和最终败者,则使用 1 和 2 排序。 半决赛从第 3 位开始。
@@ -432,6 +432,8 @@ scoringSchemeLowPointWinnerGetsZero=低分系统,获胜者得零分
scoringSchemeWinnerGetsFive=高分系统,获胜者得 5 分
scoringSchemeWinnerGetsSix=高分系统,获胜者得 6 分
scoringSchemeWinnerGetsEight=高分系统,获胜者得 8 分
scoringSchemeHighPointMatchRacing=High Point System, Match Racing
scoringSchemeHighPointMatchRacingDescription=The winner of the match race gets 1 point, the loser gets 0 points
scoringSchemeWinnerGetsEightAndInterpolation=高分系统,获胜者 8 分,内插
scoringSchemeLowPointWithEliminationsAndRoundsWinnerGets07=采用多轮淘汰制的低分系统,获胜者得 0.7 分
scoringSchemeLowPointWithEliminationsAndRoundsWinnerGets07Description=低分记分系统的一种,采用多轮淘汰制。\n每一轮应作为比赛系列,船队顺序\n从第一轮的最高数向后计。\n如果有最终一支舰队和最终败者,则使用 1 和 2 排序。 半决赛从第 3 位开始。
@@ -28,6 +28,8 @@ public class ScoringSchemeTypeFormatter {
return stringMessages.scoringSchemeWinnerGetsSix();
case HIGH_POINT_WINNER_GETS_EIGHT:
return stringMessages.scoringSchemeWinnerGetsEight();
case HIGH_POINT_MATCH_RACING:
return stringMessages.scoringSchemeHighPointMatchRacing();
case HIGH_POINT_WINNER_GETS_EIGHT_AND_INTERPOLATION:
return stringMessages.scoringSchemeWinnerGetsEightAndInterpolation();
case HIGH_POINT_FIRST_GETS_TEN_OR_EIGHT:
@@ -56,6 +58,8 @@ public class ScoringSchemeTypeFormatter {
return stringMessages.scoringSchemeLowPointWithEliminationsAndRoundsWinnerGets07Description();
case LOW_POINT_LEAGUE_OVERALL:
return stringMessages.scoringSchemeLowPointForLeagueOverallLeaderboardDescription();
case HIGH_POINT_MATCH_RACING:
return stringMessages.scoringSchemeHighPointMatchRacingDescription();
default:
return format(scoringSchemeType, stringMessages);
}
@@ -8,6 +8,7 @@ import java.util.Deque;
import java.util.Iterator;
import java.util.List;
import java.util.ListIterator;
import java.util.Map;
import java.util.Map.Entry;
import javax.servlet.ServletException;
@@ -16,6 +17,7 @@ import javax.servlet.http.HttpServletResponse;
import com.sap.sailing.domain.igtimiadapter.BulkFixReceiver;
import com.sap.sailing.domain.igtimiadapter.IgtimiWindListener;
import com.sap.sailing.domain.igtimiadapter.LiveDataConnection;
import com.sap.sse.common.TimePoint;
/**
@@ -43,6 +45,18 @@ public class WindStatusHtmlServlet extends WindStatusServlet implements IgtimiWi
out.println("<body>");
out.println("<p>Reload wind connectors with parameter <a href=\"/sailingserver/windStatus?reloadWindReceiver=true\">reloadWindReceiver=true</a>. This will force a connection reset and a reloading of the wind receivers.</p>");
out.println("<h3>Igtimi Wind Status ("+getIgtimiMessagesRawCount()+" raw messages received)</h3>");
Map<LiveDataConnection, IgtimiConnectionInfo> igtimiConnections = getIgtimiConnections();
if (!igtimiConnections.isEmpty()) {
out.println("<h4>Igtimi accounts used</h4>");
for (Map.Entry<LiveDataConnection, IgtimiConnectionInfo> entry: igtimiConnections.entrySet()) {
IgtimiConnectionInfo igtimiConnectionInfo = entry.getValue();
int deviceCount = igtimiConnectionInfo.deviceIDs.size();
out.println("<b>Account " + igtimiConnectionInfo.accountName + "</b><br/>");
out.println(deviceCount + " devices " + igtimiConnectionInfo.deviceIDs.toString() + "<br/>");
out.println("Connection used is " + igtimiConnectionInfo.remoteAddress.toString() + "<br/><br/>");
}
out.println("<br/>");
}
if (getLastIgtimiMessages() != null && !getLastIgtimiMessages().isEmpty()) {
for(Entry<String, Deque<IgtimiMessageInfo>> deviceAndMessagesList: getLastIgtimiMessages().entrySet()) {
final Deque<IgtimiMessageInfo> copyOfLastIgtimiMessages;
@@ -1,7 +1,6 @@
package com.sap.sailing.server.gateway.impl;
import java.io.IOException;
import java.io.PrintWriter;
import java.net.InetSocketAddress;
import java.net.SocketException;
import java.text.DateFormat;
import java.text.DecimalFormat;
@@ -10,15 +9,9 @@ import java.util.ArrayList;
import java.util.Date;
import java.util.Deque;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.ListIterator;
import java.util.Map;
import java.util.Map.Entry;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.osgi.util.tracker.ServiceTracker;
@@ -37,7 +30,7 @@ import com.sap.sailing.expeditionconnector.ExpeditionMessage;
import com.sap.sailing.expeditionconnector.ExpeditionWindTrackerFactory;
import com.sap.sailing.expeditionconnector.UDPExpeditionReceiver;
import com.sap.sailing.server.gateway.SailingServerHttpServlet;
import com.sap.sse.common.TimePoint;
import com.sap.sse.common.Util;
/**
* Shows the state of wind receivers regardless of them being attached to a race. Currently Expedition and Igtimi are supported.
@@ -45,7 +38,7 @@ import com.sap.sse.common.TimePoint;
* @author Simon Marcel Pamies
*
*/
public class WindStatusServlet extends SailingServerHttpServlet implements IgtimiWindListener, BulkFixReceiver {
public abstract class WindStatusServlet extends SailingServerHttpServlet implements IgtimiWindListener, BulkFixReceiver {
private static final long serialVersionUID = -6791613843435003810L;
protected static final String PARAM_RELOAD_WIND_RECEIVER="reloadWindReceiver";
@@ -64,8 +57,8 @@ public class WindStatusServlet extends SailingServerHttpServlet implements Igtim
private static int igtimiRawMessageCount;
private static Map<String, Deque<IgtimiMessageInfo>> lastIgtimiMessages;
private static IgtimiWindReceiver igtimiWindReceiver;
private static LiveDataConnection liveDataConnection;
private static Map<LiveDataConnection, IgtimiConnectionInfo> igtimiConnections;
private static boolean isExpeditionListenerRegistered;
private static boolean isIgtimiListenerRegistered;
@@ -73,6 +66,7 @@ public class WindStatusServlet extends SailingServerHttpServlet implements Igtim
super();
isExpeditionListenerRegistered = false;
isIgtimiListenerRegistered = false;
igtimiConnections = new LinkedHashMap<>();
}
protected int getIgtimiMessagesRawCount() {
@@ -97,14 +91,21 @@ public class WindStatusServlet extends SailingServerHttpServlet implements Igtim
synchronized (lock) {
if (!isIgtimiListenerRegistered || reinitialize) {
if (reinitialize) {
try {
if (liveDataConnection != null) {
liveDataConnection.stop();
liveDataConnection.removeListener(igtimiWindReceiver);
liveDataConnection.removeListener(this);
if (!igtimiConnections.isEmpty()) {
for (Map.Entry<LiveDataConnection, IgtimiConnectionInfo> entry: igtimiConnections.entrySet()) {
LiveDataConnection igtimiConnection = entry.getKey();
try {
if (igtimiConnection != null) {
igtimiConnection.stop();
igtimiConnection.removeListener(igtimiWindReceiver);
igtimiConnection.removeListener(this);
}
} catch (Exception e) {
e.printStackTrace();
}
}
} catch (Exception e) {
e.printStackTrace();
igtimiConnections.clear();
}
}
isIgtimiListenerRegistered = registerIgtimiListener();
@@ -114,77 +115,6 @@ public class WindStatusServlet extends SailingServerHttpServlet implements Igtim
}
}
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String reinitializeWindReceiverParameter = req.getParameter(PARAM_RELOAD_WIND_RECEIVER);
initializeWindReceiver(reinitializeWindReceiverParameter != null && reinitializeWindReceiverParameter.equalsIgnoreCase("true"));
resp.setContentType("text/html");
PrintWriter out = resp.getWriter();
out.println("<html>");
out.println("<head>");
out.println("<title>Wind Status</title>");
out.println("<meta http-equiv=refresh content='10; url="+req.getRequestURI()+"'>");
out.println("</head>");
out.println("<body>");
out.println("<p>Reload wind connectors with parameter <a href=\"/sailingserver/windStatus?reloadWindReceiver=true\">reloadWindReceiver=true</a>. This will force a connection reset and a reloading of the wind receivers.</p>");
out.println("<h3>Igtimi Wind Status ("+igtimiRawMessageCount+" raw messages received)</h3>");
if (lastIgtimiMessages != null && !lastIgtimiMessages.isEmpty()) {
for(Entry<String, Deque<IgtimiMessageInfo>> deviceAndMessagesList: lastIgtimiMessages.entrySet()) {
final Deque<IgtimiMessageInfo> copyOfLastIgtimiMessages;
synchronized (deviceAndMessagesList.getValue()) {
copyOfLastIgtimiMessages = new ArrayDeque<>(deviceAndMessagesList.getValue());
}
out.println("Windbot: <b>" + deviceAndMessagesList.getKey() + "</b>");
if(copyOfLastIgtimiMessages.size() > 0) {
TimePoint latestTimePoint = copyOfLastIgtimiMessages.peek().wind.getTimePoint();
long lastFixDiffInMs = System.currentTimeMillis() - latestTimePoint.asMillis();
out.println("&nbsp;&nbsp;&nbsp;&nbsp;Last fix:");
if(lastFixDiffInMs / 1000 < 60) {
out.println(lastFixDiffInMs / 1000 +"s ago");
} else {
out.println("<span style=\"color:red;\">" + lastFixDiffInMs / 1000 +"min ago</span>");
}
}
out.println("<br/>");
Iterator<IgtimiMessageInfo> messageIt = copyOfLastIgtimiMessages.iterator();
while (messageIt.hasNext()){
IgtimiMessageInfo message = messageIt.next();
out.println(message);
out.println("<br/>");
}
out.println("<br/>");
}
} else {
if (igtimiRawMessageCount == 0) {
out.println("<i>No Igtimi messages received so far!</i>");
} else {
out.println("<i>"+igtimiRawMessageCount+" Igtimi message bunch has been received but not enough messages to generate wind information.</i>");
}
}
out.println("<h3>Expedition Wind Status</h3>");
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>");
}
out.println("</body>");
out.println("</html>");
out.close();
}
private boolean registerIgtimiListener() {
boolean result = false;
ServiceTracker<IgtimiConnectionFactory, IgtimiConnectionFactory> igtimiServiceTracker = new ServiceTracker<IgtimiConnectionFactory, IgtimiConnectionFactory>(getContext(), IgtimiConnectionFactory.class, null);
@@ -196,9 +126,16 @@ public class WindStatusServlet extends SailingServerHttpServlet implements Igtim
if (account.getUser() != null) {
IgtimiConnection igtimiConnection = igtimiConnectionFactory.connect(account);
try {
liveDataConnection = igtimiConnection.getOrCreateLiveConnection(igtimiConnection.getWindDevices());
liveDataConnection.addListener(igtimiWindReceiver);
liveDataConnection.addListener(this);
LiveDataConnection newIgtimiConnection = igtimiConnection.getOrCreateLiveConnection(igtimiConnection.getWindDevices());
newIgtimiConnection.addListener(igtimiWindReceiver);
newIgtimiConnection.addListener(this);
IgtimiConnectionInfo newIgtimiConnectionInfo = new IgtimiConnectionInfo();
newIgtimiConnectionInfo.remoteAddress = newIgtimiConnection.getRemoteAddress();
newIgtimiConnectionInfo.accountName = account.getUser().getEmail();
Util.addAll(igtimiConnection.getWindDevices(), newIgtimiConnectionInfo.deviceIDs);
igtimiConnections.put(newIgtimiConnection, newIgtimiConnectionInfo);
result = true;
} catch (Exception e) {
e.printStackTrace();
@@ -236,7 +173,13 @@ public class WindStatusServlet extends SailingServerHttpServlet implements Igtim
}
return result;
}
protected class IgtimiConnectionInfo {
InetSocketAddress remoteAddress;
String accountName;
List<String> deviceIDs = new ArrayList<>();
}
protected class ExpeditionMessageInfo {
Integer boatID;
ExpeditionMessage message;
@@ -296,20 +239,24 @@ public class WindStatusServlet extends SailingServerHttpServlet implements Igtim
@Override
public void destroy() {
if (liveDataConnection != null) {
for (Map.Entry<LiveDataConnection, IgtimiConnectionInfo> entry: igtimiConnections.entrySet()) {
LiveDataConnection igtimiConnection = entry.getKey();
try {
liveDataConnection.stop();
igtimiConnection.stop();
} catch (Exception e) {
e.printStackTrace();
} finally {
liveDataConnection = null;
isIgtimiListenerRegistered = false;
}
}
igtimiConnections.clear();
isIgtimiListenerRegistered = false;
}
@Override
public void received(Iterable<Fix> fixes) {
igtimiRawMessageCount += 1;
}
public static Map<LiveDataConnection, IgtimiConnectionInfo> getIgtimiConnections() {
return igtimiConnections;
}
}