mirror of
https://github.com/eclipse-sailing-analytics/sailing-analytics.git
synced 2026-10-10 22:30:56 +00:00
refactored wind tracker creation, starting, stopping, registration, unregistration
Preparing for the possibility of other wind receivers, trying to keep the services and their APIs independent of the receiving path leading via Expedition, UDP and such. Introduced the new bundle/system property expedition.udp.port which is now used to determine the port on which the expedition receivers listen for inbound wind data
This commit is contained in:
1 parent
638fdcbd06
commit
b635cd4fa4
18 files changed
+264
-96
No files matched your search
Binary file not shown.
+14
@@ -0,0 +1,14 @@
|
||||
package com.sap.sailing.domain.tracking;
|
||||
|
||||
/**
|
||||
* Receives wind information and forwards it to a {@link TrackedRace}'s {@link TrackedRace#getWindTrack(WindSource) wind
|
||||
* track}.
|
||||
*
|
||||
* @author Axel Uhl (D043530)
|
||||
*
|
||||
*/
|
||||
public interface WindTracker {
|
||||
|
||||
void stop();
|
||||
|
||||
}
|
||||
+16
@@ -0,0 +1,16 @@
|
||||
package com.sap.sailing.domain.tracking;
|
||||
|
||||
import java.net.SocketException;
|
||||
|
||||
import com.sap.sailing.domain.base.RaceDefinition;
|
||||
|
||||
/**
|
||||
* Constructs wind trackers that link some wind data receiving facility to a {@link TrackedRace}.
|
||||
*
|
||||
* @author Axel Uhl (D043530)
|
||||
*
|
||||
*/
|
||||
public interface WindTrackerFactory {
|
||||
WindTracker createWindTracker(DynamicTrackedEvent trackedEvent, RaceDefinition race, boolean correctByDeclination)
|
||||
throws SocketException;
|
||||
}
|
||||
+4
-2
@@ -36,8 +36,9 @@ import com.sap.sailing.domain.tracking.GPSFix;
|
||||
import com.sap.sailing.domain.tracking.Wind;
|
||||
import com.sap.sailing.expeditionconnector.ExpeditionListener;
|
||||
import com.sap.sailing.expeditionconnector.ExpeditionMessage;
|
||||
import com.sap.sailing.expeditionconnector.ExpeditionWindTracker;
|
||||
import com.sap.sailing.expeditionconnector.ExpeditionWindTrackerFactory;
|
||||
import com.sap.sailing.expeditionconnector.UDPExpeditionReceiver;
|
||||
import com.sap.sailing.expeditionconnector.WindTracker;
|
||||
import com.sap.sailing.util.Util;
|
||||
|
||||
public class UDPExpeditionReceiverTest {
|
||||
@@ -226,7 +227,8 @@ public class UDPExpeditionReceiverTest {
|
||||
public void testWindTrackerWithDeclination() throws IOException, InterruptedException, ClassNotFoundException, ParseException {
|
||||
MockedTrackedRace race = new MockedTrackedRace();
|
||||
DeclinationService declinationService = DeclinationService.INSTANCE;
|
||||
WindTracker windTracker = new WindTracker(race, declinationService);
|
||||
ExpeditionWindTracker windTracker = new ExpeditionWindTracker(race, declinationService, receiver,
|
||||
(ExpeditionWindTrackerFactory) ExpeditionWindTrackerFactory.getInstance());
|
||||
receiver.addListener(listener, /* validMessagesOnly */ true);
|
||||
receiver.addListener(windTracker, /* validMessagesOnly */ true);
|
||||
String[] lines = new String[validLines.length+1];
|
||||
|
||||
@@ -7,5 +7,6 @@ Bundle-Vendor: SAP
|
||||
Bundle-RequiredExecutionEnvironment: JavaSE-1.6
|
||||
Export-Package: com.sap.sailing.expeditionconnector
|
||||
Require-Bundle: com.sap.sailing.domain,
|
||||
com.sap.sailing.declination
|
||||
com.sap.sailing.declination,
|
||||
org.eclipse.osgi;visibility:=reexport
|
||||
Bundle-ActivationPolicy: lazy
|
||||
+37
-7
@@ -12,6 +12,7 @@ import com.sap.sailing.domain.base.impl.KnotSpeedWithBearingImpl;
|
||||
import com.sap.sailing.domain.tracking.DynamicTrackedRace;
|
||||
import com.sap.sailing.domain.tracking.Wind;
|
||||
import com.sap.sailing.domain.tracking.WindSource;
|
||||
import com.sap.sailing.domain.tracking.WindTracker;
|
||||
import com.sap.sailing.domain.tracking.impl.WindImpl;
|
||||
|
||||
/**
|
||||
@@ -21,25 +22,54 @@ import com.sap.sailing.domain.tracking.impl.WindImpl;
|
||||
* @author Axel Uhl (d043530)
|
||||
*
|
||||
*/
|
||||
public class WindTracker implements ExpeditionListener {
|
||||
private static final Logger logger = Logger.getLogger(WindTracker.class.getName());
|
||||
public class ExpeditionWindTracker implements ExpeditionListener, WindTracker {
|
||||
private static final Logger logger = Logger.getLogger(ExpeditionWindTracker.class.getName());
|
||||
|
||||
private final DynamicTrackedRace race;
|
||||
|
||||
private final DeclinationService declinationService;
|
||||
|
||||
private Position lastKnownPosition;
|
||||
|
||||
private final UDPExpeditionReceiver receiver;
|
||||
|
||||
private final ExpeditionWindTrackerFactory factory;
|
||||
|
||||
/**
|
||||
* @param declinationService
|
||||
* An optional service to convert the Expedition-provided wind bearings (which Expedition
|
||||
* believes to be true bearings) from magnetic to true bearings. Can be <code>null</code>
|
||||
* in which case the Expedition true bearings are used as true bearings.
|
||||
* An optional service to convert the Expedition-provided wind bearings (which Expedition believes to be
|
||||
* true bearings) from magnetic to true bearings. Can be <code>null</code> in which case the Expedition
|
||||
* true bearings are used as true bearings.
|
||||
* @param receiver
|
||||
* receive wind data from this receiver by adding the new object as a listener to the receiver; when
|
||||
* calling {@link #stop}, this subscription will be removed again.
|
||||
* @param factory TODO
|
||||
*/
|
||||
public WindTracker(DynamicTrackedRace race, DeclinationService declinationService) {
|
||||
public ExpeditionWindTracker(DynamicTrackedRace race, DeclinationService declinationService,
|
||||
UDPExpeditionReceiver receiver, ExpeditionWindTrackerFactory factory) {
|
||||
super();
|
||||
this.race = race;
|
||||
this.declinationService = declinationService;
|
||||
this.receiver = receiver;
|
||||
this.factory = factory;
|
||||
receiver.addListener(this, /* validMessagesOnly */ true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void stop() {
|
||||
synchronized (factory) {
|
||||
receiver.removeListener(this);
|
||||
factory.windTrackerStopped(race.getRace(), this);
|
||||
}
|
||||
}
|
||||
|
||||
UDPExpeditionReceiver getReceiver() {
|
||||
return receiver;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return getClass().getSimpleName()+" on UDP port "+getReceiver().getPort();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -70,7 +100,7 @@ public class WindTracker implements ExpeditionListener {
|
||||
logger.log(Level.INFO,
|
||||
"Unable to correct wind bearing by declination. Exception while computing declination: "
|
||||
+ e.getMessage());
|
||||
logger.throwing(WindTracker.class.getName(), "received", e);
|
||||
logger.throwing(ExpeditionWindTracker.class.getName(), "received", e);
|
||||
windSpeed = null;
|
||||
}
|
||||
} else {
|
||||
+104
@@ -0,0 +1,104 @@
|
||||
package com.sap.sailing.expeditionconnector;
|
||||
|
||||
import java.net.SocketException;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import org.osgi.framework.BundleActivator;
|
||||
import org.osgi.framework.BundleContext;
|
||||
|
||||
import com.sap.sailing.declination.DeclinationService;
|
||||
import com.sap.sailing.domain.base.RaceDefinition;
|
||||
import com.sap.sailing.domain.tracking.DynamicTrackedEvent;
|
||||
import com.sap.sailing.domain.tracking.DynamicTrackedRace;
|
||||
import com.sap.sailing.domain.tracking.WindTracker;
|
||||
import com.sap.sailing.domain.tracking.WindTrackerFactory;
|
||||
|
||||
public class ExpeditionWindTrackerFactory implements WindTrackerFactory, BundleActivator {
|
||||
private static Logger logger = Logger.getLogger(ExpeditionWindTrackerFactory.class.getName());
|
||||
|
||||
private static WindTrackerFactory defaultInstance;
|
||||
|
||||
private static final String EXPEDITION_UDP_PORT_PROPERTY_NAME = "expedition.udp.port";
|
||||
/**
|
||||
* Remembers the wind tracker and the port on which the UDP receiver with which the wind tracker is
|
||||
* registers is listening for incoming Expedition messages.
|
||||
*/
|
||||
private final Map<RaceDefinition, WindTracker> windTrackers;
|
||||
|
||||
private final Map<Integer, UDPExpeditionReceiver> windReceivers;
|
||||
|
||||
private final int defaultPort;
|
||||
|
||||
public ExpeditionWindTrackerFactory() {
|
||||
this.windTrackers = new HashMap<RaceDefinition, WindTracker>();
|
||||
windReceivers = new HashMap<Integer, UDPExpeditionReceiver>();
|
||||
defaultPort = Integer.valueOf(System.getProperty(EXPEDITION_UDP_PORT_PROPERTY_NAME, "2013"));
|
||||
logger.info("Created "+getClass().getName()+" with default UDP port "+defaultPort);
|
||||
}
|
||||
|
||||
public static WindTrackerFactory getInstance() {
|
||||
if (defaultInstance == null) {
|
||||
defaultInstance = new ExpeditionWindTrackerFactory();
|
||||
}
|
||||
return defaultInstance;
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized WindTracker createWindTracker(DynamicTrackedEvent trackedEvent, RaceDefinition race,
|
||||
boolean correctByDeclination) throws SocketException {
|
||||
WindTracker result = windTrackers.get(race);
|
||||
if (result == null) {
|
||||
DynamicTrackedRace trackedRace = trackedEvent.getTrackedRace(race);
|
||||
UDPExpeditionReceiver receiver = getOrCreateWindReceiverForPort(defaultPort);
|
||||
result = new ExpeditionWindTracker(trackedRace,
|
||||
correctByDeclination ? DeclinationService.INSTANCE : null, receiver, this);
|
||||
windTrackers.put(race, result);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private synchronized UDPExpeditionReceiver getOrCreateWindReceiverForPort(int port) throws SocketException {
|
||||
UDPExpeditionReceiver receiver = windReceivers.get(port);
|
||||
if (receiver == null) {
|
||||
receiver = new UDPExpeditionReceiver(port);
|
||||
windReceivers.put(port, receiver);
|
||||
new Thread(receiver, "Expedition Wind Receiver on port "+port).start();
|
||||
}
|
||||
return receiver;
|
||||
}
|
||||
|
||||
/**
|
||||
* Notifies the factory that the wind tracker has stopped tracking wind for <code>race</code>. This
|
||||
* will remove the tracker from the respective caches.
|
||||
*/
|
||||
synchronized void windTrackerStopped(RaceDefinition race, ExpeditionWindTracker windTracker) {
|
||||
if (windTrackers.get(race) != windTracker) {
|
||||
throw new IllegalArgumentException("Intenral error: expected to remove wind tracker "+windTracker+
|
||||
", but another wind tracker "+windTrackers.get(race)+" was registered.");
|
||||
}
|
||||
windTrackers.remove(race);
|
||||
if (windTracker.getReceiver().isStopped()) {
|
||||
UDPExpeditionReceiver receiver = windReceivers.get(windTracker.getReceiver().getPort());
|
||||
if (receiver != windTracker.getReceiver()) {
|
||||
throw new IllegalArgumentException("Internal error: expected to remove wind receiver "+
|
||||
windTracker.getReceiver()+" but found receiver "+receiver);
|
||||
}
|
||||
windReceivers.remove(windTracker.getReceiver().getPort());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void start(BundleContext context) throws Exception {
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void stop(BundleContext context) throws Exception {
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
+23
-2
@@ -81,6 +81,23 @@ public class UDPExpeditionReceiver implements Runnable {
|
||||
udpSocket.close();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* If there are currently no listeners subscribed (see {@link #addListener(ExpeditionListener, boolean)} and
|
||||
* {@link #removeListener(ExpeditionListener)}), this receiver is {@link #stop() stopped} and <code>true</code>
|
||||
* is returned; otherwise, <code>false</code> is returned.
|
||||
*/
|
||||
public synchronized boolean stopIfNoListeners() throws SocketException, IOException {
|
||||
boolean result = listeners.isEmpty();
|
||||
if (result) {
|
||||
stop();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public boolean isStopped() {
|
||||
return stopped;
|
||||
}
|
||||
|
||||
public void run() {
|
||||
byte[] buf = new byte[MAX_PACKET_SIZE];
|
||||
@@ -161,12 +178,16 @@ public class UDPExpeditionReceiver implements Runnable {
|
||||
return b == checksum;
|
||||
}
|
||||
|
||||
public void addListener(ExpeditionListener listener, boolean validMessagesOnly) {
|
||||
public synchronized void addListener(ExpeditionListener listener, boolean validMessagesOnly) {
|
||||
listeners.put(listener, validMessagesOnly);
|
||||
}
|
||||
|
||||
public void removeListener(ExpeditionListener listener) {
|
||||
public synchronized void removeListener(ExpeditionListener listener) {
|
||||
listeners.remove(listener);
|
||||
}
|
||||
|
||||
public int getPort() {
|
||||
return listeningOnPort;
|
||||
}
|
||||
|
||||
}
|
||||
+14
-4
@@ -20,6 +20,7 @@ import com.google.gwt.user.cellview.client.ColumnSortEvent.ListHandler;
|
||||
import com.google.gwt.user.cellview.client.TextColumn;
|
||||
import com.google.gwt.user.client.rpc.AsyncCallback;
|
||||
import com.google.gwt.user.client.ui.Button;
|
||||
import com.google.gwt.user.client.ui.CheckBox;
|
||||
import com.google.gwt.user.client.ui.FormPanel;
|
||||
import com.google.gwt.user.client.ui.Grid;
|
||||
import com.google.gwt.user.client.ui.HasVerticalAlignment;
|
||||
@@ -226,12 +227,21 @@ public class EventManagementPanel extends FormPanel {
|
||||
Handler columnSortHandler = getRaceTableColumnSortHandler(raceList.getList(), raceNameColumn, raceStartTrackingColumn);
|
||||
raceTable.addColumnSortHandler(columnSortHandler);
|
||||
|
||||
VerticalPanel trackPanel = new VerticalPanel();
|
||||
grid.setWidget(6, 1, trackPanel);
|
||||
final CheckBox trackWindCheckbox = new CheckBox("Track Wind");
|
||||
trackWindCheckbox.setValue(true);
|
||||
trackPanel.add(trackWindCheckbox);
|
||||
final CheckBox declinationCheckbox = new CheckBox("Correct Wind Bearing by Declination");
|
||||
declinationCheckbox.setValue(true);
|
||||
trackPanel.add(declinationCheckbox);
|
||||
|
||||
Button btnTrack = new Button("Track");
|
||||
grid.setWidget(6, 1, btnTrack);
|
||||
trackPanel.add(btnTrack);
|
||||
btnTrack.addClickHandler(new ClickHandler() {
|
||||
@Override
|
||||
public void onClick(ClickEvent event) {
|
||||
trackSelectedRaces();
|
||||
trackSelectedRaces(trackWindCheckbox.getValue(), declinationCheckbox.getValue());
|
||||
}
|
||||
});
|
||||
grid.getCellFormatter().setVerticalAlignment(6, 1, HasVerticalAlignment.ALIGN_TOP);
|
||||
@@ -435,12 +445,12 @@ public class EventManagementPanel extends FormPanel {
|
||||
});
|
||||
}
|
||||
|
||||
private void trackSelectedRaces() {
|
||||
private void trackSelectedRaces(boolean trackWind, boolean correctWindByDeclination) {
|
||||
String liveURI = liveURIBox.getValue();
|
||||
String storedURI = storedURIBox.getValue();
|
||||
for (final RaceRecordDAO rr : raceList.getList()) {
|
||||
if (raceTable.getSelectionModel().isSelected(rr)) {
|
||||
sailingService.track(rr, liveURI, storedURI, new AsyncCallback<Void>() {
|
||||
sailingService.track(rr, liveURI, storedURI, trackWind, correctWindByDeclination, new AsyncCallback<Void>() {
|
||||
@Override
|
||||
public void onFailure(Throwable caught) {
|
||||
errorReporter.reportError("Error trying to register race " + rr.name + " for tracking: "
|
||||
|
||||
@@ -19,13 +19,11 @@ public interface SailingService extends RemoteService {
|
||||
|
||||
List<RaceRecordDAO> listRacesInEvent(String eventJsonURL) throws Exception;
|
||||
|
||||
void track(RaceRecordDAO rr, String liveURI, String storedURI) throws Exception;
|
||||
void track(RaceRecordDAO rr, String liveURI, String storedURI, boolean trackWind, boolean correctWindByDeclination) throws Exception;
|
||||
|
||||
void storeTracTracConfiguration(String name, String jsonURL, String liveDataURI, String storedDataURI) throws Exception;
|
||||
|
||||
void stopTrackingEvent(String eventName) throws Exception;
|
||||
|
||||
void stopTrackingRace(String eventName, String raceName) throws Exception;
|
||||
|
||||
void startTrackingWind(String eventName, String raceName, int port, boolean correctByDeclination) throws Exception;
|
||||
}
|
||||
+2
-3
@@ -15,7 +15,8 @@ public interface SailingServiceAsync {
|
||||
|
||||
void listRacesInEvent(String eventJsonURL, AsyncCallback<List<RaceRecordDAO>> callback);
|
||||
|
||||
void track(RaceRecordDAO rr, String liveURI, String storedURI, AsyncCallback<Void> callback);
|
||||
void track(RaceRecordDAO rr, String liveURI, String storedURI, boolean trackWind, boolean correctWindByDeclination,
|
||||
AsyncCallback<Void> callback);
|
||||
|
||||
void getPreviousConfigurations(AsyncCallback<List<TracTracConfigurationDAO>> callback);
|
||||
|
||||
@@ -26,6 +27,4 @@ public interface SailingServiceAsync {
|
||||
|
||||
void stopTrackingRace(String eventName, String raceName, AsyncCallback<Void> asyncCallback);
|
||||
|
||||
void startTrackingWind(String eventName, String raceName, int port, boolean correctDeclination,
|
||||
AsyncCallback<Void> callback);
|
||||
}
|
||||
+6
-6
@@ -16,7 +16,6 @@ import org.osgi.framework.BundleContext;
|
||||
import org.osgi.util.tracker.ServiceTracker;
|
||||
|
||||
import com.google.gwt.user.server.rpc.RemoteServiceServlet;
|
||||
import com.sap.sailing.declination.DeclinationService;
|
||||
import com.sap.sailing.domain.base.BoatClass;
|
||||
import com.sap.sailing.domain.base.Competitor;
|
||||
import com.sap.sailing.domain.base.Event;
|
||||
@@ -122,9 +121,12 @@ public class SailingServiceImpl extends RemoteServiceServlet implements SailingS
|
||||
}
|
||||
|
||||
@Override
|
||||
public void track(RaceRecordDAO rr, String liveURI, String storedURI) throws Exception {
|
||||
public void track(RaceRecordDAO rr, String liveURI, String storedURI, boolean trackWind, boolean correctWindByDeclination) throws Exception {
|
||||
service.addRace(new URL(rr.paramURL), new URI(liveURI), new URI(storedURI),
|
||||
MongoWindStoreFactory.INSTANCE.getMongoWindStore(MongoObjectFactory.INSTANCE));
|
||||
if (trackWind) {
|
||||
startTrackingWind(rr.eventName, rr.name, correctWindByDeclination);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -170,12 +172,10 @@ public class SailingServiceImpl extends RemoteServiceServlet implements SailingS
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void startTrackingWind(String eventName, String raceName, int port, boolean correctByDeclination) throws Exception {
|
||||
private void startTrackingWind(String eventName, String raceName, boolean correctByDeclination) throws Exception {
|
||||
Event event = service.getEventByName(eventName);
|
||||
RaceDefinition race = getRaceByName(event, raceName);
|
||||
service.startTrackingWind(event, race, port,
|
||||
correctByDeclination ? DeclinationService.INSTANCE : null);
|
||||
service.startTrackingWind(event, race, correctByDeclination);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -41,7 +41,7 @@ public class Activator implements BundleActivator, ServiceListener {
|
||||
racingEventServiceTracker.open();
|
||||
// grab the service
|
||||
RacingEventService service = (RacingEventService) racingEventServiceTracker.getService();
|
||||
for (Triple<Event, RaceDefinition, Integer> windTracker : service.getWindTrackedRaces()) {
|
||||
for (Triple<Event, RaceDefinition, String> windTracker : service.getWindTrackedRaces()) {
|
||||
service.stopTrackingWind(windTracker.getA(), windTracker.getB());
|
||||
}
|
||||
for (Event event : service.getAllEvents()) {
|
||||
|
||||
@@ -19,7 +19,6 @@ import org.json.simple.JSONArray;
|
||||
import org.json.simple.JSONObject;
|
||||
|
||||
import com.mongodb.MongoException;
|
||||
import com.sap.sailing.declination.DeclinationService;
|
||||
import com.sap.sailing.domain.base.Bearing;
|
||||
import com.sap.sailing.domain.base.Distance;
|
||||
import com.sap.sailing.domain.base.Event;
|
||||
@@ -421,11 +420,11 @@ public class AdminApp extends Servlet {
|
||||
|
||||
private void listWindTrackers(HttpServletRequest req, HttpServletResponse resp) throws IOException {
|
||||
JSONArray windTrackers = new JSONArray();
|
||||
for (Triple<Event, RaceDefinition, Integer> eventAndRaceAndPort : getService().getWindTrackedRaces()) {
|
||||
for (Triple<Event, RaceDefinition, String> eventAndRaceAndPort : getService().getWindTrackedRaces()) {
|
||||
JSONObject windTracker = new JSONObject();
|
||||
windTracker.put("eventname", eventAndRaceAndPort.getA().getName());
|
||||
windTracker.put("racename", eventAndRaceAndPort.getB().getName());
|
||||
windTracker.put("port", eventAndRaceAndPort.getC());
|
||||
windTracker.put("windtrackerinfo", eventAndRaceAndPort.getC());
|
||||
windTrackers.add(windTracker);
|
||||
}
|
||||
windTrackers.writeJSONString(resp.getWriter());
|
||||
@@ -458,11 +457,9 @@ public class AdminApp extends Servlet {
|
||||
if (portParam == null) {
|
||||
resp.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, "No port parameter provided");
|
||||
} else {
|
||||
int port = Integer.valueOf(portParam);
|
||||
String correctByDeclination = req
|
||||
.getParameter(PARAM_NAME_CORRECT_EXPEDITION_WIND_BEARING_BY_DECLINATION);
|
||||
getService().startTrackingWind(event, race, port,
|
||||
Boolean.valueOf(correctByDeclination) ? DeclinationService.INSTANCE : null);
|
||||
getService().startTrackingWind(event, race, Boolean.valueOf(correctByDeclination));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,7 +10,6 @@ import java.net.URL;
|
||||
import java.text.ParseException;
|
||||
import java.util.List;
|
||||
|
||||
import com.sap.sailing.declination.DeclinationService;
|
||||
import com.sap.sailing.domain.base.Event;
|
||||
import com.sap.sailing.domain.base.RaceDefinition;
|
||||
import com.sap.sailing.domain.tracking.TrackedEvent;
|
||||
@@ -93,25 +92,30 @@ public interface RacingEventService {
|
||||
|
||||
/**
|
||||
* Stops tracking a single race. Other races of the same event that are currently tracked will continue to be
|
||||
* tracked.
|
||||
* tracked. If wind tracking for the race is currently running, it will be stopped (see also
|
||||
* {@link #stopTrackingWind(Event, RaceDefinition)}).
|
||||
*/
|
||||
void stopTracking(Event event, RaceDefinition race) throws MalformedURLException, IOException, InterruptedException;
|
||||
|
||||
/**
|
||||
* @param port
|
||||
* the UDP port on which to listen for incoming messages from Expedition clients
|
||||
* @param declinationService
|
||||
* An optional service to convert the Expedition-provided wind bearings (which Expedition
|
||||
* believes to be true bearings) from magnetic to true bearings. Can be <code>null</code>
|
||||
* in which case the Expedition true bearings are used as true bearings.
|
||||
* @param correctByDeclination
|
||||
* An optional service to convert the wind bearings (which the receiver may
|
||||
* believe to be true bearings) from magnetic to true bearings.
|
||||
* @throws SocketException
|
||||
* thrown, e.g., in case there is already another listener on the port requested
|
||||
*/
|
||||
void startTrackingWind(Event event, RaceDefinition race, int port, DeclinationService declinationService) throws SocketException;
|
||||
void startTrackingWind(Event event, RaceDefinition race, boolean correctByDeclination) throws SocketException;
|
||||
|
||||
void stopTrackingWind(Event event, RaceDefinition race) throws SocketException, IOException;
|
||||
|
||||
Iterable<Triple<Event, RaceDefinition, Integer>> getWindTrackedRaces();
|
||||
/**
|
||||
* The {@link Triple#getC() third component} of the triples returned is a wind tracker-specific
|
||||
* comment where a wind tracker may provide information such as its type name or, if applicable,
|
||||
* connectivity information such as the network port on which it receives wind information.
|
||||
*/
|
||||
Iterable<Triple<Event, RaceDefinition, String>> getWindTrackedRaces();
|
||||
|
||||
/**
|
||||
* For the JSON URL of an account / event, lists the paramURLs that can be used for {@link #addRace(URL, URI, URI, WindStore)}
|
||||
|
||||
+18
-49
@@ -18,20 +18,17 @@ import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import com.sap.sailing.declination.DeclinationService;
|
||||
import com.sap.sailing.domain.base.Event;
|
||||
import com.sap.sailing.domain.base.RaceDefinition;
|
||||
import com.sap.sailing.domain.tracking.DynamicTrackedEvent;
|
||||
import com.sap.sailing.domain.tracking.DynamicTrackedRace;
|
||||
import com.sap.sailing.domain.tracking.WindStore;
|
||||
import com.sap.sailing.domain.tracking.WindTracker;
|
||||
import com.sap.sailing.domain.tracking.WindTrackerFactory;
|
||||
import com.sap.sailing.domain.tractracadapter.DomainFactory;
|
||||
import com.sap.sailing.domain.tractracadapter.JSONService;
|
||||
import com.sap.sailing.domain.tractracadapter.RaceHandle;
|
||||
import com.sap.sailing.domain.tractracadapter.RaceRecord;
|
||||
import com.sap.sailing.domain.tractracadapter.RaceTracker;
|
||||
import com.sap.sailing.expeditionconnector.UDPExpeditionReceiver;
|
||||
import com.sap.sailing.expeditionconnector.WindTracker;
|
||||
import com.sap.sailing.util.Util.Pair;
|
||||
import com.sap.sailing.expeditionconnector.ExpeditionWindTrackerFactory;
|
||||
import com.sap.sailing.util.Util.Triple;
|
||||
|
||||
public class RacingEventServiceImpl implements RacingEventService {
|
||||
@@ -39,6 +36,8 @@ public class RacingEventServiceImpl implements RacingEventService {
|
||||
|
||||
private final DomainFactory domainFactory;
|
||||
|
||||
private final WindTrackerFactory windTrackerFactory;
|
||||
|
||||
private final Map<String, Event> eventsByName;
|
||||
|
||||
private final Map<Event, Set<RaceTracker>> raceTrackersByEvent;
|
||||
@@ -47,22 +46,20 @@ public class RacingEventServiceImpl implements RacingEventService {
|
||||
* Remembers the wind tracker and the port on which the UDP receiver with which the wind tracker is
|
||||
* registers is listening for incoming Expedition messages.
|
||||
*/
|
||||
private final Map<RaceDefinition, Pair<WindTracker, Integer>> windTrackers;
|
||||
private final Map<RaceDefinition, WindTracker> windTrackers;
|
||||
|
||||
/**
|
||||
* Remembers the trackers by paramURL/liveURI/storedURI to avoid duplication
|
||||
*/
|
||||
private final Map<Triple<URL, URI, URI>, RaceTracker> raceTrackersByURLs;
|
||||
|
||||
private final Map<Integer, UDPExpeditionReceiver> windReceivers;
|
||||
|
||||
public RacingEventServiceImpl() {
|
||||
domainFactory = DomainFactory.INSTANCE;
|
||||
windTrackerFactory = ExpeditionWindTrackerFactory.getInstance();
|
||||
eventsByName = new HashMap<String, Event>();
|
||||
raceTrackersByEvent = new HashMap<Event, Set<RaceTracker>>();
|
||||
windTrackers = new HashMap<RaceDefinition, Pair<WindTracker, Integer>>();
|
||||
windTrackers = new HashMap<RaceDefinition, WindTracker>();
|
||||
raceTrackersByURLs = new HashMap<Triple<URL, URI, URI>, RaceTracker>();
|
||||
windReceivers = new HashMap<Integer, UDPExpeditionReceiver>();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -180,6 +177,7 @@ public class RacingEventServiceImpl implements RacingEventService {
|
||||
} else {
|
||||
logger.warning("Didn't find any trackers for event "+event);
|
||||
}
|
||||
stopTrackingWind(event, race);
|
||||
// if the last tracked race was removed, remove the entire event
|
||||
if (raceTrackersByEvent.get(event).isEmpty()) {
|
||||
stopTracking(event);
|
||||
@@ -187,56 +185,27 @@ public class RacingEventServiceImpl implements RacingEventService {
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void startTrackingWind(Event event, RaceDefinition race, int port,
|
||||
DeclinationService declinationService) throws SocketException {
|
||||
if (!windTrackers.containsKey(race)) {
|
||||
DynamicTrackedEvent trackedEvent = getDomainFactory().getOrCreateTrackedEvent(event);
|
||||
DynamicTrackedRace trackedRace = trackedEvent.getTrackedRace(race);
|
||||
WindTracker windTracker = new WindTracker(trackedRace, declinationService);
|
||||
UDPExpeditionReceiver receiver = getOrCreateWindReceiverForPort(port);
|
||||
windTrackers.put(race, new Pair<WindTracker, Integer>(windTracker, port));
|
||||
receiver.addListener(windTracker, /* validMessagesOnly */ true);
|
||||
}
|
||||
}
|
||||
|
||||
private synchronized UDPExpeditionReceiver getOrCreateWindReceiverForPort(int port) throws SocketException {
|
||||
UDPExpeditionReceiver receiver = windReceivers.get(port);
|
||||
if (receiver == null) {
|
||||
receiver = new UDPExpeditionReceiver(port);
|
||||
windReceivers.put(port, receiver);
|
||||
new Thread(receiver, "Expedition Wind Receiver on port "+port).start();
|
||||
}
|
||||
return receiver;
|
||||
public synchronized void startTrackingWind(Event event, RaceDefinition race,
|
||||
boolean correctByDeclination) throws SocketException {
|
||||
windTrackerFactory.createWindTracker(getDomainFactory().getOrCreateTrackedEvent(event), race, correctByDeclination);
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void stopTrackingWind(Event event, RaceDefinition race) throws SocketException, IOException {
|
||||
Pair<WindTracker, Integer> windTrackerPair = windTrackers.get(race);
|
||||
if (windTrackerPair != null) {
|
||||
WindTracker windTracker = windTrackerPair.getA();
|
||||
if (windTracker != null) {
|
||||
for (UDPExpeditionReceiver receiver : windReceivers.values()) {
|
||||
receiver.removeListener(windTracker);
|
||||
}
|
||||
}
|
||||
WindTracker windTracker = windTrackers.get(race);
|
||||
if (windTracker != null) {
|
||||
windTracker.stop();
|
||||
windTrackers.remove(race);
|
||||
// if there is no more tracker we can also stop and remove the receiver(s) we created
|
||||
if (windTrackers.isEmpty()) {
|
||||
for (UDPExpeditionReceiver receiver : windReceivers.values()) {
|
||||
receiver.stop();
|
||||
}
|
||||
windReceivers.clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized Iterable<Triple<Event, RaceDefinition, Integer>> getWindTrackedRaces() {
|
||||
List<Triple<Event, RaceDefinition, Integer>> result = new ArrayList<Triple<Event, RaceDefinition, Integer>>();
|
||||
public synchronized Iterable<Triple<Event, RaceDefinition, String>> getWindTrackedRaces() {
|
||||
List<Triple<Event, RaceDefinition, String>> result = new ArrayList<Triple<Event, RaceDefinition, String>>();
|
||||
for (Event event : eventsByName.values()) {
|
||||
for (RaceDefinition race : event.getAllRaces()) {
|
||||
if (windTrackers.containsKey(race)) {
|
||||
result.add(new Triple<Event, RaceDefinition, Integer>(event, race, windTrackers.get(race).getB()));
|
||||
result.add(new Triple<Event, RaceDefinition, String>(event, race, windTrackers.get(race).toString()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,3 +5,4 @@ eclipse.ignoreApp=true
|
||||
osgi.noShutdown=true
|
||||
org.osgi.service.http.port=8886
|
||||
mongo.port=10200
|
||||
expedition.udp.port=2010
|
||||
Reference in new issue
Block a user