mirror of
https://github.com/eclipse-sailing-analytics/sailing-analytics.git
synced 2026-10-15 08:41:01 +00:00
Merge remote-tracking branch 'server/master' into axel-usermanagement
Conflicts: java/com.sap.sailing.gwt.ui/.settings/com.google.gwt.eclipse.core.prefs java/com.sap.sailing.server/SailingServer (No Proxy).launch java/com.sap.sailing.server/SailingServer (No Proxy, Remote Debug SAP VM).launch
This commit is contained in:
commit
8b45395fcc
21 files changed
+331
-349
No files matched your search
@@ -2,6 +2,8 @@
|
||||
|
||||
The following are the focus areas for the off-season activities until the first 2015 event, presumably the first ESS act in Singapore, early February 2015. We will tackle most of them in parallel, with separate people working on the different topics.
|
||||
|
||||
[[_TOC_]]
|
||||
|
||||
## newhome (Frank, O.I.O.)
|
||||
|
||||
- A number of bugs and issues have been recorded during and after the first events run with the newhome implementation. See [our Bugzilla Bug #1928](http://bugzilla.sapsailing.com/bugzilla/show_bug.cgi?id=1928).
|
||||
@@ -21,6 +23,15 @@ Serializable settings will also help in the context of user-specific preferences
|
||||
|
||||
See [http://wiki.sapsailing.com/wiki/planning/usermanagement](http://wiki.sapsailing.com/wiki/planning/usermanagement) for a description. Some progress has already been made, but it's going to be a lot more work to update our existing UIs, no longer using HTTP Basic Authentication, replacing this with Shiro's authentication and authorization concepts. As briefly touched above, this also has implications on the newhome design.
|
||||
|
||||
## Map Visualization Improvements (Christopher, Axel, Frank, Ubilabs)
|
||||
|
||||
The map visualization currently has two main drawbacks:
|
||||
|
||||
* the map doesn't rotate
|
||||
* boat, water and land visualization is not sufficiently appealing
|
||||
|
||||
For the rotation problem we see two possible solutions: transforming coordinates while staying on Google Maps; or replacing the map provider, probably using OpenStreetMap. For the "appeal" issue we seem to agree that the use of plugin technology is to be avoided, and so the options have to be recruited from HTML5/CSS-land. In particular, we believe that better boat visualizations are more or less a matter of a good graphics designer painting hull and sail constellations for specific boat classes. Water visualizations will have to be experimented with on the basis of HTML5 canvas technology (performance, appeal). Land visualization would require satellite imagery with precise geo-location information to fit into a map provider and may be more difficult.
|
||||
|
||||
## Volume Business (Ubilabs, Fredrik, Jan)
|
||||
|
||||
Reaching a broader audience with the SAP Sailing Analytics will mainly happen through two channels: smartphone tracking and a free-to-use race committee app. Both activities are underway with Ubilabs contributing the UI/UX design and SAP contributing additional development support. We plan to complete one major iteration of both, the smartphone tracking app for iOS and Android, and one major iteration of the race committee app until the end of this planning time frame.
|
||||
|
||||
@@ -3,8 +3,6 @@ RaceLog-tracking allows fully self-sustained tracking with the Sailing Analytics
|
||||
|
||||
The term itself should be revised at some point, and currently refers to the technical implementation on how master data related to a race (e.g. competitor registrations, course layout) is recorded and stored persistently: namely in a RaceLog.
|
||||
|
||||
This is the second iteration of implementing this idea. For previous documentation, see [[smartphone tracking|wiki/smartphone-tracking]].
|
||||
|
||||
## Server Architecture
|
||||
[[Server Architecture|wiki/racelog-tracking/server]]
|
||||
|
||||
|
||||
@@ -1,46 +0,0 @@
|
||||
# Smartphone Tracking
|
||||
|
||||
[[_TOC_]]
|
||||
|
||||
## Introduction
|
||||
On this page the decisions, architecture and API's for using smartphones as an additional input channel for Sailing Analytics are documented. Meanwhile, the architecture of this solution is designed to be flexible enough to support other types of input devices in the future, e.g. [Igtimi](http://www.igtimi.com/) trackers. A good overview of the topic is also provided by [[Jan Bross' thesis|doc/theses/20130913_Bross_Tracking_Sailing_Races_with_Mobile_Devices.pdf]].
|
||||
|
||||
## Branches
|
||||
* `race-board-admin`: manual UI based entry of mark passings for the time being, while we do not have a detection algorithm
|
||||
* `cmd-android-tracking`: client side development branch for the tracking application, which enhances the existent race committee app, server side development of using the RaceLog to create a tracking adapter for Commodity Mobile Devices (CMD) such as smartphones
|
||||
|
||||
## Further links
|
||||
* [Race Board Admin](/wiki/smartphone-tracking/race-board-admin)
|
||||
* [GPSFixStore](/wiki/smartphone-tracking/gpsfixstore)
|
||||
* [Servlets](/wiki/smartphone-tracking/servlets)
|
||||
* [Race Log Events](/wiki/smartphone-tracking/race-log-events)
|
||||
* [Server-side Architecture](/wiki/smartphone-tracking/server-side-architecture)
|
||||
* [Tracking App Architecture](/wiki/smartphone-tracking/tracking-app-architecture)
|
||||
* [To-Do](/wiki/smartphone-tracking/to-do)
|
||||
|
||||
## Communication
|
||||
|
||||
### Channels
|
||||
|
||||
1. [**Servlets:**](/wiki/smartphone-tracking/servlets) Everything that is not directly related to a specific Race (or rather RaceLog) is handled via POST and GET servlets, where the data should be described as JSON. Examples are: Creating a Race, managing Competitors. Ideally, this would on smartphone side however also benefit from the RaceLog-underlying semi-connectedness functionality. _Caveats: replication and persistence!_
|
||||
|
||||
2. [**RaceLog:**](wiki/smartphone-tracking/race-log-events) All the "master data" communication concerning one race in particular should piggyback on the existing RaceLog-mechanism, which already deals with semi-connectedness, persistence and replication. Examples for this are: adding competitors to a race, mapping tracking devices to competitors, starting a race, defining the course layout.
|
||||
|
||||
3. **Other:** The actual tracking data (perhaps also additional data: wind etc.) also has to be transferred. On client side we want to reuse the communication mechanism which the RaceLog is built on top of. Right now, this is also handed by a [servlet](/wiki/smartphone-tracking/servlets#recordFixes) on server-side, and through the `EventSendingService` on Android-side (which handles semi-connectedness).
|
||||
|
||||
### Current communication process
|
||||
1. create a flexible or regatta leaderboard in the Admin Console (and also a series with races if using a regatta leaderboard)
|
||||
2. [create a persistent competitor](/wiki/smartphone-tracking/servlets#createPersistentCompetitor)
|
||||
3. [create a race-log-tracked race](/wiki/smartphone-tracking/servlets#createRace)
|
||||
4. [register the competitors](/wiki/smartphone-tracking/race-log-events#Persistent-Competitor-Registered)
|
||||
5. [set the course](/wiki/smartphone-tracking/race-log-events#Course-Design-Changed)
|
||||
5. [start the race](/wiki/smartphone-tracking/race-log-events#Pre-Race-Phase-Ended)
|
||||
6. [set the start time](/wiki/smartphone-tracking/race-log-events#Start-Time)
|
||||
7. [ping the marks](/wiki/smartphone-tracking/servlets#pingMark)
|
||||
8. [send the competitor fixes](/wiki/smartphone-tracking/servlets#recordFixes)
|
||||
9. [set the mark rounding times](/wiki/smartphone-tracking/race-board-admin)
|
||||
10. view the race in the race viewer
|
||||
11. [after a server restart, reload the race from the MongoDB](/wiki/smartphone-tracking/gpsfixstore)
|
||||
|
||||
## Mark Passings
|
||||
Without a tracking provider that implements a mark passing algorithm, we have to identify mark passings on our own in the context of smartphone tracking, for Sailing Analytics to be able to do any analytics at all. A detection algorithm is being developed in the branch `mark-rounding-inference`. Until it is completed a UI entry option has been provided as a workaround. It can be found in the branch `race-board-admin`, in which the mark passings can be set by hand. This can be accessed by clicking the _Administer Race_ button of a race in the leaderboard detail table, which can be found in the leaderboard configuration panel of the admin console.
|
||||
@@ -1,16 +0,0 @@
|
||||
# GPSFixStore
|
||||
[[_TOC_]]
|
||||
|
||||
## Purpose
|
||||
The GPSFixStore functions similar to the WindStore. A `TrackedRaceImpl` expects such a store for instantation, and then uses this store to resolve the corresponding `Track`. On replicas, a `Empty*Store` is used, on the master instance a `Mongo*Store` is used. This tries to load existing fixes from the MongoDB, and will write any new incoming fixes to the MongoDB.
|
||||
|
||||
## Loading race-log-tracked races in the Admin Console
|
||||
After restarting the server, a tracked race can now be fully recovered from its race log, and the fixes of marks and competitors stored through the GPSFixStore.
|
||||
|
||||
To do this
|
||||
1. open the Admin Console
|
||||
2. switch to the _Leaderboard Configuration_ tab
|
||||
3. select a leaderboard
|
||||
4. click _Reload all RaceLogs_ (has to be done to reload the [Competitor Registered](/wiki/smartphone-tracking/race-log-events#Persistent-Competitor-Registered) events, which contain device identifiers for which deserializers need to be registered through the OSGi service registry -> these are not available when the `RacingEventService` initially loads all data from the database)
|
||||
|
||||
<img src="/wiki/images/load-racelog-tracked-race.png">
|
||||
@@ -1,11 +0,0 @@
|
||||
# Race Board Admin
|
||||
[[_TOC_]]
|
||||
|
||||
## Purpose
|
||||
This UI frontend can be used to administer a tracked race. At this point, this means manually setting mark passing times for competitors. It looks similar to the normal race viewer, but requires authentication (like the Admin Console).
|
||||
|
||||
## Branch
|
||||
`race-board-admin`
|
||||
|
||||
## Accessing the Race Board Admin
|
||||
<img src="/wiki/images/accessing-race-board-admin.png"/>
|
||||
@@ -1,27 +0,0 @@
|
||||
# RaceLog Events
|
||||
[[_TOC_]]
|
||||
|
||||
## Persistent Competitor Registered
|
||||
`RaceLogPersistentCompetitorRegisteredEvent`
|
||||
|
||||
Includes a `Competitor` as well a `SmartphoneIdentifier`. On the one hand, every comptitor that is thus registered will be included in the `RaceDefinition` as soon as the race is created, on the other hand the mapping between smartphone identifier (e.g. IMEI for european phones) and competitor is later used for mapping the incoming fixes to the correct competitor.
|
||||
|
||||
## Pre Race Phase Started
|
||||
`RaceLogPreRacePhaseStartedEvent`
|
||||
|
||||
This event is added to the race log automatically by the server when calling the [createRace](/wiki/smartphone-tracking/servlets#createRace) servlet, to mark this race as race-log-tracked. It also includes the race name and boat class, so that the race can be properly reloaded after a server restart.
|
||||
|
||||
## Pre Race Phase Ended
|
||||
`RaceLogPreRacePhaseEndedEvent`
|
||||
|
||||
This does not include any additional data, and merely indicates that the race can be transformed from its pre-race definition state (e.g. waiting for competitors to register, waiting for boat class, waiting for course definition) to an actual race, where no additional competitors can be added, the boat class is fixes, and tracking may begin. This event is picked up by the `RaceLogRaceTracker`, which then creates the actual tracked race from the data in the RaceLog. For successful creation, at least one competitor has to be registered, and a course must have been set through a `RaceLogCourseDefinitionChangedEvent`.
|
||||
|
||||
## Course Design Changed
|
||||
`RaceLogCourseDesignChangedEvent`
|
||||
|
||||
This existing event is used to set the course definition, and is required before the race can be started.
|
||||
|
||||
## Start Time
|
||||
`RaceLogStartTimeEvent`
|
||||
|
||||
This existing event should be used to set the start time, before attempting to view the race in the race viewer, as otherwise the time slider won't work.
|
||||
@@ -1,7 +0,0 @@
|
||||
# Server-side Architecture
|
||||
|
||||
On the server-side, the architecture of smartphone tracking is intended to be open for extension, so that different types of input devices can be used for tracking one race.
|
||||
|
||||
Generic device identifiers that are qualified through a device type are used for mapping a device to a competitor in the race log. When the race is then created, the OSGi service registry is used to find services to which the appropriate device mappings in the race log are provided, e.g., a smartphone adapter registers a `RaceLogTrackingDeviceHandler` service for the device type `smartphoneImei`, and then receives all smartphone device mappings from the race log once the race is created. The same OSGi service logic is used to find services that deal with persistently storing device identifiers, so that loading and persisting race log events can be used for all types of device identifiers.
|
||||
|
||||
The reason for using the OSGi service registry is that it enables decentralized implementation of different kinds of device adapters. E.g., implementing a new Igtimi adapter does not mean that you have to modify the object factory for device identifier objects in the persistence bundle, but simply register a new service from within your own bundle. This is more hindering than helpful in this stage of development, but - in future - means that other device adapters could be developed without having to touch the Sailing Analytics core code, so a vendor of tracking devices could recieve a current Sailing Analytics version as an SDK and implement additional bundles only.
|
||||
@@ -1,153 +0,0 @@
|
||||
# Servlets
|
||||
|
||||
[[_TOC_]]
|
||||
|
||||
## createPersistentCompetitor
|
||||
URL: `/sailingserver/racelogtracking/createPersistentCompetitor`
|
||||
Servlet: `CreatePersistentCompetitorPostServlet`
|
||||
|
||||
**Expects**
|
||||
* POST request body: Competitor-JSON with a nested Boat-JSON and Team-JSON (see `CompetitorJsonDeserializer`)
|
||||
```
|
||||
{"id": "",
|
||||
"name": "Competitor Fredrik",
|
||||
"displayColor": "#00FE3C",
|
||||
"sailID": "1234",
|
||||
"team": {
|
||||
"name": "Team Fredrik",
|
||||
"sailors": [
|
||||
{
|
||||
"name": "Fredrik",
|
||||
"description": "",
|
||||
"dateOfBirth": 2394820480284,
|
||||
"nationality": {"IOC": "GER"}
|
||||
}
|
||||
]
|
||||
},
|
||||
"boat": {
|
||||
"name": "Boat Fredrik",
|
||||
"sailID": "1234",
|
||||
"boatClass": {
|
||||
"name": "49er"
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**Returns**
|
||||
* `200` Competitor created, body: Competitor as JSON
|
||||
|
||||
**Throws**
|
||||
* `400` Invalid JSON in request
|
||||
|
||||
**Comments**
|
||||
* The server choses the id, so this field can be left blank / not supplied
|
||||
|
||||
## getPersistentCompetitors
|
||||
URL: `/sailingserver/racelogtracking/getPersistentCompetitors`
|
||||
Servlet: `PersistentCompetitorsGetServlet`
|
||||
|
||||
**Expects**
|
||||
* GET request
|
||||
|
||||
**Returns**
|
||||
* `200` body: JSON array of Competitor objects
|
||||
|
||||
|
||||
## getRaceLogsInPreRacePhase
|
||||
URL: `/sailingserver/racelogtracking/getRaceLogsInPreRacePhase`
|
||||
Servlet: `RaceLogsInPreRacePhaseGetServlet`
|
||||
|
||||
**Expects**
|
||||
* GET request
|
||||
|
||||
**Returns**
|
||||
* `200` body: JSON array of RaceGroups
|
||||
|
||||
## createRace
|
||||
URL: `/sailingserver/racelogtracking/createRace?leaderboard=<leaderboardName>&raceColumn=<raceColumnName>&fleet=<fleetName>`
|
||||
Servlet: `CreateRaceLogTrackedRacePostServlet`
|
||||
|
||||
**Expects**
|
||||
* POST request
|
||||
|
||||
**Returns**
|
||||
* `200` RaceGroup JSON, containing only the Series/Row/Cell structure for the newly created race
|
||||
|
||||
**Throws**
|
||||
* `404` Leaderboard does not exist, RaceColumn does not exist (if the leaderboard is a `RegattaLeaderboard`)
|
||||
* `409` The RaceColumn already is linked to a tracked race`
|
||||
|
||||
**Comments**
|
||||
* The behaviour of the servlet depends on the type of leaderboard with the name `leaderboardName`. If this is a `RegattaLeaderboard`, then the RaceColumn with the name `raceColumnName` has to already exist. If it is a `FlexibleLeaderboard`, the RaceColumn will be created if it does not yet exist.
|
||||
|
||||
## recordFixes
|
||||
URL: `/smartphone/recordFixes`
|
||||
Servlet: `RecordFixesPostServlet`
|
||||
|
||||
**Precondition**
|
||||
* race has already been started by sending a `RaceLogPreRacePhaseEndedEvent`
|
||||
|
||||
**Expects**
|
||||
* POST request body: DeviceIdentifierWithGPSFixMovingsDTO as JSON
|
||||
```
|
||||
{"imei": "12345678",
|
||||
"data": [
|
||||
{"unixtime": 2394820480284,
|
||||
"nmea" : "$GPRMC,123519,A,4807.038,N,01131.000,E,022.4,084.4,230394,003.1,W*6A"
|
||||
},
|
||||
{"unixtime": 2394820480285,
|
||||
"nmea" : "$GPRMC,123519,A,4807.038,N,01131.000,E,022.4,084.4,230394,003.1,W*6A"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
**Returns**
|
||||
* `200`: fixes recorded
|
||||
|
||||
**Throws**
|
||||
* `409` Device not mapped to race and competitor
|
||||
|
||||
## pingMark
|
||||
URL: `/sailingserver/racelogtracking/pingMark?leaderboard=<leaderboardName>&raceColumn=<raceColumnName>&fleet=<fleetName>`
|
||||
Servlet: `PingMarkPostServlet`
|
||||
|
||||
**Precondition**
|
||||
* race has already been started by sending a `RaceLogPreRacePhaseEndedEvent` and has not been stopped yet
|
||||
|
||||
**Expects**
|
||||
* POST request body: PingMark as JSON
|
||||
```
|
||||
{
|
||||
"markStringId": "Leeward Mark"
|
||||
"gpsFix": {
|
||||
"unixtime": 1375951388465,
|
||||
"nmea": "$GPRMC,084308,A,41.771311,N,86.933174,E,0.0,0.0,080813,0,W*4D"
|
||||
},
|
||||
}
|
||||
```
|
||||
|
||||
**Returns**
|
||||
* `200`: mark pinged
|
||||
|
||||
**Throws**
|
||||
* `404` Leaderboard, RaceColumn or Fleet not found
|
||||
* `409` Race not in tracking state
|
||||
|
||||
## currentcourse
|
||||
URL: `/sailingserver/rc/currentcourse`
|
||||
Servlet: `CourseJsonExportServlet`
|
||||
|
||||
**Precondition**
|
||||
* Race must have been started through a `RaceLogPreRacePhaseEndedEvent`
|
||||
|
||||
**Expects**
|
||||
* GET request
|
||||
* URL Parameters leaderboard, raceColumn and fleet
|
||||
|
||||
**Returns**
|
||||
* `200` body: CourseBase JSON
|
||||
|
||||
**Comments**
|
||||
* Does not use the latest `RaceLogCourseDefinitionChangedEvent`, but instead requires the presence of a `TrackedRace` for this racelog, from which the `RaceDefinition` is acquired to get the course. We could build our own servlet, but as we can only ping the marks after having created the race anyway, this isn't too much of a problem.
|
||||
@@ -1,27 +0,0 @@
|
||||
# To-Do
|
||||
[[_TOC_]]
|
||||
|
||||
## Server
|
||||
* change names of *Events, as they are not events -> also change names of abstract base classes
|
||||
* use extension serializers
|
||||
* exchange auto JSON to BSON conversion in MongoObjectFactory / DomainObjectFactory for something suited for productive use
|
||||
* editing course in the RaceBoardAdmin
|
||||
* mapping devices to marks
|
||||
* generic method for registering listener for NMEA sentence types (e.g. to then process wind) -> move servlet for receiving NMEA out of smartphoneadapter
|
||||
* accepting / removing competitors
|
||||
* for this we first need racelog replication back to all clients
|
||||
* also, not everybody should be able to do this -> see user management
|
||||
* user management (Competitors as users, credentials so not everybody can do everything)
|
||||
* -> integrate with OAuth, ISAF competitors etc.?
|
||||
* security (not everybody can start race, goes hand in hand with user management)
|
||||
* support dynamic mapping of smartphone to competitor -> so that it can change during the race
|
||||
* support other input channels (e.g. Igtimi)
|
||||
* only transfer competitor ID for registering etc. instead of whole competitor
|
||||
|
||||
## Android
|
||||
* use EventSendingService for all outgoing requests, not only race log
|
||||
* change format of sent position Data to degrees and minutes
|
||||
* reuse existing course design functionality to create RaceLogCourseDesignChangedEvent before sending RaceLogPreRacePhaseEndedEvent
|
||||
* abstract sending service, so that all POST / GET requests and not only RaceLogEvents can be sent using the semi-connectedness functionality --> just write JSONObjects/Strings directly into the file. The Servlet has to handle deserialization and the client doesn't have to know what type of object it is after having saved it (is this really the case?)
|
||||
* simplify settings
|
||||
* login/register Activity for registering the Team and Sailor the first time the App is started
|
||||
@@ -1,41 +0,0 @@
|
||||
# Tracking App Architecture
|
||||
[[_TOC_]]
|
||||
|
||||
## Activities and Fragments of the tracking app
|
||||

|
||||
|
||||
## Communication during the race
|
||||

|
||||
|
||||
## Components
|
||||
### `LocationChangedReceiver`
|
||||
This class gets notified of location changes via intents. Depending on whether the App is in local or remote broadcast mode the corresponding service is started by using intents.
|
||||
|
||||
### `LocalLocationUpdateService`
|
||||
Stores the location Information in a File by using the `FileWriterUtils` class.
|
||||
|
||||
### `NetworklocationUpdateService`
|
||||
Sends the location information to a web service.
|
||||
|
||||
### `SAP Sailor Tracker Service`
|
||||
Background process for starting, pausing and stopping tracking. Registers all receivers on a pending intent, which is send periodically.
|
||||
|
||||
### `AsyncJsonPostTask`
|
||||
Async task that handles the execution of post requests with Json content.
|
||||
|
||||
### `OnlineDataManager`
|
||||
Enables accessing of data from a `DataStore`. Loads data from Servlets using GET-Requests using a `DataLoader`. For an example how to use the `OnlineDataManager` refer to `SelectRaceFragment`, which loads the RaceLogsInPreRacePhase so that the user can select the race he wants to take part in.
|
||||
|
||||
### `DataStore`
|
||||
Interface for the `DataStore` which stores all data that is relevant for the App (managed Races, Competitors, ...)
|
||||
Implementation: `InMemoryDataStore`
|
||||
|
||||
### `DataLoader`
|
||||
`AsyncDataLoader` which does an HTTP GET to a given URL, parses the data (with a `DataParser`) and sends the data to a `DataHandler`.
|
||||
|
||||
### `AppPreferences`
|
||||
Helper Class for accessing the App Preferences specified in settings_view.xml
|
||||
|
||||
### `ListFragmentWithDataManager`
|
||||
Base Class, which provides easy access to the data manager for a Fragment, which wants to display the data in a List.
|
||||
Used for example in the `Select*Fragments`.
|
||||
@@ -176,3 +176,10 @@ Roles currently assigned to the user can be removed by pressing the red `X` butt
|
||||
These changes take effect immediately if the user that is being edited is the user currently signed in. Note that in particular if you are signed in with the `admin` role and remove this role for yourself, you will not be able to edit your roles any further but will need to ask another administrator to do so.
|
||||
|
||||
## RESTful API
|
||||
|
||||
There is a RESTful web service reachable at the URL `/security/api/restsecurity`:
|
||||
|
||||
* `/security/api/restsecurity/login`, type POST, parameters are `username` and `password`. Use, e.g., with `curl` from the command line as in `curl -D /tmp/header -d "username=admin&password=admin" http://myserver.sapsailing.com/security/api/restsecurity/login` and find the cookie identifying the session in file `/tmp/header` which should contain a line of the form<pre>
|
||||
Set-Cookie: JSESSIONID=f563a4fc-2333-45c4-8f82-3069f502680d; Path=/; HttpOnly
|
||||
</pre>
|
||||
* `/security/api/restsecurity/logout`, type GET, which terminates the current session when provided with the right cookie. Example: `curl --cookie JSESSIONID=f563a4fc-2333-45c4-8f82-3069f502680d http://myserver.sapsailing.com/security/api/restsecurity/logout`
|
||||
Reference in new issue
Block a user