new RaceLogTracking tab in AdminConsole

This commit is contained in:
Fredrik Teschke committed 2014-02-26 17:55:39 +01:00
1 parent ba0587d979
commit ef1f72b72b
28 files changed
+1014 -491

No files matched your search

@@ -31,7 +31,8 @@ public abstract class AbstractLeaderboardDTO implements Serializable {
public String defaultCourseAreaName;
public ScoringSchemeType scoringScheme;
public LeaderboardType type;
public boolean raceLogTrackedRacesCouldBeAdded = false;
public boolean isDenotedForRaceLogTracking = false;
public boolean raceLogTrackersCanBeAdded = false;
private Long delayToLiveInMillisForLatestRace;
@@ -8,9 +8,9 @@ public class FleetDTO extends NamedDTO {
private Color color;
private int orderNo;
public boolean raceLogTrackedRaceCouldBeAdded;
public boolean raceLogTrackerCanBeAdded;
public RaceLogTrackingState raceLogTrackingState;
public boolean raceLogTrackerForRaceExists;
public boolean raceLogTrackerExists;
public FleetDTO() {}
@@ -116,7 +116,7 @@ public class CreateAndTrackWithRaceLogTest {
RaceLog raceLog = column.getRaceLog(fleet);
//before denoting, it is not listed as loadable
Map<RaceColumn, Collection<Fleet>> loadable = adapter.listRacesThatCanBeAdded(service, leaderboard);
Map<RaceColumn, Collection<Fleet>> loadable = adapter.listRaceLogTrackersThatCanBeAdded(service, leaderboard);
assertEquals(0, loadable.size());
//can denote racelog for tracking
@@ -132,7 +132,7 @@ public class CreateAndTrackWithRaceLogTest {
gpsFixStore.storeFix(dev1, new GPSFixMovingImpl(new DegreePosition(0, 0), new MillisecondsTimePoint(15), new KnotSpeedWithBearingImpl(10, new DegreeBearingImpl(5))));
//then listed as loadable
loadable = adapter.listRacesThatCanBeAdded(service, leaderboard);
loadable = adapter.listRaceLogTrackersThatCanBeAdded(service, leaderboard);
assertEquals(1, loadable.size());
assertEquals(1, loadable.get(column).size());
@@ -12,6 +12,7 @@ import com.sap.sailing.domain.common.RegattaIdentifier;
import com.sap.sailing.domain.common.racelog.tracking.NotDenotableForTrackingException;
import com.sap.sailing.domain.common.racelog.tracking.RaceLogTrackingState;
import com.sap.sailing.domain.leaderboard.Leaderboard;
import com.sap.sailing.domain.leaderboard.RegattaLeaderboard;
import com.sap.sailing.domain.racelog.RaceLog;
import com.sap.sailing.domain.racelog.tracking.impl.RaceLogRaceTracker;
import com.sap.sailing.domain.tracking.RacesHandle;
@@ -19,40 +20,52 @@ import com.sap.sailing.domain.tracking.TrackedRace;
import com.sap.sailing.server.RacingEventService;
public interface RaceLogTrackingAdapter {
/**
* Can be called either to track a new race, or optionally to load a race
* that is already in the {@link RaceLogTrackingState#TRACKING} state, but
* was closed.
*/
RacesHandle addRace(RacingEventService service,
RegattaIdentifier regattaToAddTo, Leaderboard leaderboard,
RaceColumn raceColumn, Fleet fleet, long timeoutInMilliseconds)
throws MalformedURLException, FileNotFoundException,
URISyntaxException, Exception;
/**
* Can be called either to track a new race, or optionally to load a race that is already in the
* {@link RaceLogTrackingState#TRACKING} state, but was closed.
*/
RacesHandle addRace(RacingEventService service, RegattaIdentifier regattaToAddTo, Leaderboard leaderboard,
RaceColumn raceColumn, Fleet fleet, long timeoutInMilliseconds) throws MalformedURLException,
FileNotFoundException, URISyntaxException, Exception;
/**
* Lists all races for this leaderboards according to the rules in
* {@link #canRaceBeAdded(RacingEventService, Leaderboard, RaceColumn, Fleet)}.
*/
Map<RaceColumn, Collection<Fleet>> listRacesThatCanBeAdded(RacingEventService service,
Leaderboard leaderboard);
/**
* Lists all races for this leaderboards according to the rules in
* {@link #canRaceBeAdded(RacingEventService, Leaderboard, RaceColumn, Fleet)}.
*/
Map<RaceColumn, Collection<Fleet>> listRaceLogTrackersThatCanBeAdded(RacingEventService service, Leaderboard leaderboard);
/**
* Returns {@code true}, if a {@link DenoteForTrackingEvent} exists within the {@link RaceLog},
* and if it does not not already have an attached {@link TrackedRace},
* and if there is no {@link RaceLogRaceTracker} registered for it already.
*/
boolean canRaceBeAdded(RacingEventService service, RaceColumn raceColumn, Fleet fleet);
/**
* Returns {@code true}, if a {@link DenoteForTrackingEvent} exists within the {@link RaceLog}, and if it does not
* not already have an attached {@link TrackedRace}, and if there is no {@link RaceLogRaceTracker} registered for it
* already.
*/
boolean isDenotedForRaceLogTracking(RacingEventService service, RaceColumn raceColumn, Fleet fleet);
/**
* Denotes the {@link RaceLog} for racelog-tracking, by inserting a
* {@link DenoteForTrackingEvent}.
*
* @throws NotDenotableForTrackingException
* Fails, if no {@link RaceLog}, or a non-empty {@link RaceLog}, or one with attached
* {@link TrackedRace} is found already in place.
*/
void denoteForRaceLogTracking(RacingEventService service, Leaderboard leaderboard,
RaceColumn raceColumn, Fleet fleet, String raceName)
throws NotDenotableForTrackingException;
/**
* Returns {@code true}, if a {@link DenoteForTrackingEvent} exists within the {@link RaceLog}, and if it does not
* not already have an attached {@link TrackedRace}, and if there is no {@link RaceLogRaceTracker} registered for it
* already.
*/
boolean canRaceLogTrackerBeAdded(RacingEventService service, RaceColumn raceColumn, Fleet fleet);
/**
* Denotes the {@link RaceLog} for racelog-tracking, by inserting a {@link DenoteForTrackingEvent}.
*
* @throws NotDenotableForTrackingException
* Fails, if no {@link RaceLog}, or a non-empty {@link RaceLog}, or one with attached
* {@link TrackedRace} is found already in place.
* Also fails, if the {@code leaderboard} is not a {@link RegattaLeaderboard}.
*/
void denoteForRaceLogTracking(RacingEventService service, Leaderboard leaderboard, RaceColumn raceColumn,
Fleet fleet, String raceName) throws NotDenotableForTrackingException;
/**
* Denotes the entire {@link Leaderboard} for racelog-tracking, by calling the
* {@link #denoteForRaceLogTracking(RacingEventService, Leaderboard, RaceColumn, Fleet, String)} method for each
* {@link RaceLog}.
*
* Also, a listener is registered, that denotes every {@link RaceLog} that is added at a later time as well.
*/
void denoteForRaceLogTracking(RacingEventService service, Leaderboard leaderboard)
throws NotDenotableForTrackingException;
}
@@ -9,23 +9,22 @@ import com.sap.sailing.server.gateway.serialization.JsonSerializer;
import com.sap.sailing.server.gateway.serialization.racelog.tracking.GPSFixJsonHandler;
public class GPSFixJsonHandlerImpl<T extends GPSFix> implements GPSFixJsonHandler {
private final JsonDeserializer<T> deserializer;
private final JsonSerializer<T> serializer;
private final JsonDeserializer<T> deserializer;
private final JsonSerializer<T> serializer;
public GPSFixJsonHandlerImpl(JsonDeserializer<T> deserializer,
JsonSerializer<T> serializer) {
this.deserializer = deserializer;
this.serializer = serializer;
}
public GPSFixJsonHandlerImpl(JsonDeserializer<T> deserializer, JsonSerializer<T> serializer) {
this.deserializer = deserializer;
this.serializer = serializer;
}
@SuppressWarnings("unchecked")
@Override
public JSONObject transformForth(GPSFix fix) throws IllegalArgumentException {
return serializer.serialize((T) fix);
}
@SuppressWarnings("unchecked")
@Override
public JSONObject transformForth(GPSFix fix) throws IllegalArgumentException {
return serializer.serialize((T) fix);
}
@Override
public GPSFix transformBack(JSONObject json) throws JsonDeserializationException {
return deserializer.deserialize(json);
}
@Override
public GPSFix transformBack(JSONObject json) throws JsonDeserializationException {
return deserializer.deserialize(json);
}
}
@@ -20,46 +20,47 @@ import com.sap.sailing.domain.tracking.WindStore;
import com.sap.sailing.server.RacingEventService;
public class RaceLogConnectivityParams implements RaceTrackingConnectivityParameters {
private final RacingEventService service;
private final RacingEventService service;
private final RaceColumn raceColumn;
private final Fleet fleet;
private final Leaderboard leaderboard;
private final long delayToLiveInMillis;
private final Regatta regatta;
public RaceLogConnectivityParams(RacingEventService service, Regatta regatta, RaceColumn raceColumn, Fleet fleet, Leaderboard leaderboard, long delayToLiveInMillis)
throws RaceNotCreatedException {
this.service = service;
this.regatta = regatta;
public RaceLogConnectivityParams(RacingEventService service, Regatta regatta, RaceColumn raceColumn, Fleet fleet,
Leaderboard leaderboard, long delayToLiveInMillis) throws RaceNotCreatedException {
this.service = service;
this.regatta = regatta;
this.raceColumn = raceColumn;
this.fleet = fleet;
this.leaderboard = leaderboard;
this.delayToLiveInMillis = delayToLiveInMillis;
if (! new RaceLogTrackingStateAnalyzer(getRaceLog()).analyze().isForTracking()) {
throw new RaceNotCreatedException(String.format("Racelog (%s) is not denoted for tracking", getRaceLog()));
if (!new RaceLogTrackingStateAnalyzer(getRaceLog()).analyze().isForTracking()) {
throw new RaceNotCreatedException(String.format("Racelog (%s) is not denoted for tracking", getRaceLog()));
}
}
@Override
public RaceTracker createRaceTracker(
TrackedRegattaRegistry trackedRegattaRegistry, WindStore windStore, GPSFixStore gpsFixStore) {
return createRaceTracker(regatta, trackedRegattaRegistry, windStore, gpsFixStore);
}
@Override
public RaceTracker createRaceTracker(TrackedRegattaRegistry trackedRegattaRegistry, WindStore windStore,
GPSFixStore gpsFixStore) {
return createRaceTracker(regatta, trackedRegattaRegistry, windStore, gpsFixStore);
}
@Override
public RaceTracker createRaceTracker(Regatta regatta,
TrackedRegattaRegistry trackedRegattaRegistry, WindStore windStore, GPSFixStore gpsFixStore) {
if (regatta == null) {
BoatClass boatClass = new RaceInformationFinder(getRaceLog()).analyze().getB();
regatta = service.getOrCreateDefaultRegatta("RaceLog-tracking default Regatta", boatClass.getName(), UUID.randomUUID());
}
if (regatta == null) {
throw new RaceNotCreatedException("No regatta for race-log tracked race");
}
DynamicTrackedRegatta trackedRegatta = trackedRegattaRegistry.getOrCreateTrackedRegatta(regatta);
return new RaceLogRaceTracker(trackedRegatta, this, windStore, gpsFixStore);
}
@Override
public RaceTracker createRaceTracker(Regatta regatta, TrackedRegattaRegistry trackedRegattaRegistry,
WindStore windStore, GPSFixStore gpsFixStore) {
if (regatta == null) {
BoatClass boatClass = new RaceInformationFinder(getRaceLog()).analyze().getB();
regatta = service.getOrCreateDefaultRegatta("RaceLog-tracking default Regatta", boatClass.getName(),
UUID.randomUUID());
}
if (regatta == null) {
throw new RaceNotCreatedException("No regatta for race-log tracked race");
}
DynamicTrackedRegatta trackedRegatta = trackedRegattaRegistry.getOrCreateTrackedRegatta(regatta);
return new RaceLogRaceTracker(trackedRegatta, this, windStore, gpsFixStore);
}
@Override
public Object getTrackerID() {
@@ -86,8 +87,8 @@ public class RaceLogConnectivityParams implements RaceTrackingConnectivityParame
public Leaderboard getLeaderboard() {
return leaderboard;
}
public RacingEventService getService() {
return service;
return service;
}
}
@@ -57,23 +57,24 @@ import com.sap.sailing.domain.tracking.WindTrack;
import com.sap.sailing.domain.tracking.impl.TrackedRaceStatusImpl;
/**
* Track a race using the data defined in the {@link RaceLog}. If the events suggest that the race is already
* in the {@link RaceLogTrackingState#TRACKING} state, tracking commences immediately and
* existing fixes are loaded immediately from the database.
* Track a race using the data defined in the {@link RaceLog}. If the events suggest that the race is already in the
* {@link RaceLogTrackingState#TRACKING} state, tracking commences immediately and existing fixes are loaded immediately
* from the database.
*
* Otherwise, the tracker waits until a {@link StartTrackingEvent} is received to perform these tasks.
*
* @author Fredrik Teschke
*
*
*/
public class RaceLogRaceTracker extends BaseRaceLogEventVisitor implements RaceTracker, GPSFixReceivedListener {
private final RaceLogConnectivityParams params;
private final WindStore windStore;
private final GPSFixStore gpsFixStore;
private final DynamicTrackedRegatta regatta;
private Map<Competitor, List<DeviceMapping<Competitor>>> competitorMappings = new HashMap<>();
private Map<Mark, List<DeviceMapping<Mark>>> markMappings = new HashMap<>();
private Map<DeviceIdentifier, List<DeviceMapping<Mark>>> markMappingsByDevices = new HashMap<>();
private Map<DeviceIdentifier, List<DeviceMapping<Competitor>>> competitorMappingsByDevices = new HashMap<>();
@@ -81,20 +82,20 @@ public class RaceLogRaceTracker extends BaseRaceLogEventVisitor implements RaceT
private static final Logger logger = Logger.getLogger(RaceLogRaceTracker.class.getName());
public RaceLogRaceTracker(DynamicTrackedRegatta regatta, RaceLogConnectivityParams params,
WindStore windStore, GPSFixStore gpsFixStore) {
public RaceLogRaceTracker(DynamicTrackedRegatta regatta, RaceLogConnectivityParams params, WindStore windStore,
GPSFixStore gpsFixStore) {
this.params = params;
this.windStore = windStore;
this.gpsFixStore = gpsFixStore;
this.regatta = regatta;
//add a listener on the racelog, to be informed about relevant events
// add a listener on the racelog, to be informed about relevant events
params.getRaceLog().addListener(this);
logger.info(String.format("Created race-log tracker for: %s %s %s",
params.getLeaderboard(), params.getRaceColumn(), params.getFleet()));
//load race for which tracking already started
logger.info(String.format("Created race-log tracker for: %s %s %s", params.getLeaderboard(),
params.getRaceColumn(), params.getFleet()));
// load race for which tracking already started
if (new RaceLogTrackingStateAnalyzer(params.getRaceLog()).analyze() == RaceLogTrackingState.TRACKING) {
startTracking(null);
}
@@ -102,16 +103,16 @@ public class RaceLogRaceTracker extends BaseRaceLogEventVisitor implements RaceT
@Override
public void stop() {
trackedRace.setStatus(new TrackedRaceStatusImpl(TrackedRaceStatusEnum.FINISHED, 100));
//remove listener on racelog
params.getRaceLog().removeListener(this);
//remove listener for fixes
gpsFixStore.removeListener(this);
trackedRace.setStatus(new TrackedRaceStatusImpl(TrackedRaceStatusEnum.FINISHED, 100));
logger.info(String.format("Stopped tracking race-log race %s %s %s", params.getLeaderboard(), params.getRaceColumn(),
params.getFleet()));
// remove listener on racelog
params.getRaceLog().removeListener(this);
// remove listener for fixes
gpsFixStore.removeListener(this);
logger.info(String.format("Stopped tracking race-log race %s %s %s", params.getLeaderboard(),
params.getRaceColumn(), params.getFleet()));
}
@Override
@@ -153,192 +154,194 @@ public class RaceLogRaceTracker extends BaseRaceLogEventVisitor implements RaceT
public Object getID() {
return params.getRaceLog().getId();
}
private Map<Competitor, List<DeviceMapping<Competitor>>> getNewCompetitorMappings() {
return new DeviceCompetitorMappingFinder(params.getRaceLog()).analyze();
return new DeviceCompetitorMappingFinder(params.getRaceLog()).analyze();
}
private Map<Mark, List<DeviceMapping<Mark>>> getNewMarkMappings() {
return new DeviceMarkMappingFinder(params.getRaceLog()).analyze();
return new DeviceMarkMappingFinder(params.getRaceLog()).analyze();
}
/**
* Find the earliest device mapping, set this as start of tracking timepoint
*/
private void updateStartOfTracking() {
TimePoint earliestMapping = new MillisecondsTimePoint(Long.MAX_VALUE);
synchronized(competitorMappings) {
for (List<? extends DeviceMapping<?>> list : competitorMappings.values()) {
for (DeviceMapping<?> mapping : list) {
if (mapping.getTimeRange().from().before(earliestMapping)) {
earliestMapping = mapping.getTimeRange().from();
}
}
}
}
synchronized(markMappings) {
for (List<? extends DeviceMapping<?>> list : markMappings.values()) {
for (DeviceMapping<?> mapping : list) {
if (mapping.getTimeRange().from().before(earliestMapping)) {
earliestMapping = mapping.getTimeRange().from();
}
}
}
}
trackedRace.setStartOfTrackingReceived(earliestMapping);
TimePoint earliestMapping = new MillisecondsTimePoint(Long.MAX_VALUE);
synchronized (competitorMappings) {
for (List<? extends DeviceMapping<?>> list : competitorMappings.values()) {
for (DeviceMapping<?> mapping : list) {
if (mapping.getTimeRange().from().before(earliestMapping)) {
earliestMapping = mapping.getTimeRange().from();
}
}
}
}
synchronized (markMappings) {
for (List<? extends DeviceMapping<?>> list : markMappings.values()) {
for (DeviceMapping<?> mapping : list) {
if (mapping.getTimeRange().from().before(earliestMapping)) {
earliestMapping = mapping.getTimeRange().from();
}
}
}
}
trackedRace.setStartOfTrackingReceived(earliestMapping);
}
private <ItemT extends WithID, FixT extends GPSFix> boolean hasMappingAlreadyBeenLoaded(
DeviceMapping<ItemT> newMapping, List<DeviceMapping<ItemT>> oldMappings) {
for (DeviceMapping<ItemT> oldMapping : oldMappings) {
if (newMapping.getDevice() == oldMapping.getDevice() &&
newMapping.getTimeRange().liesWithin(oldMapping.getTimeRange())) {
return true;
}
}
return false;
DeviceMapping<ItemT> newMapping, List<DeviceMapping<ItemT>> oldMappings) {
for (DeviceMapping<ItemT> oldMapping : oldMappings) {
if (newMapping.getDevice() == oldMapping.getDevice()
&& newMapping.getTimeRange().liesWithin(oldMapping.getTimeRange())) {
return true;
}
}
return false;
}
private <ItemT extends WithID, FixT extends GPSFix>
Map<DeviceIdentifier, List<DeviceMapping<ItemT>>>
transformToMappingsByDevice(Map<ItemT, List<DeviceMapping<ItemT>>> mappings) {
Map<DeviceIdentifier, List<DeviceMapping<ItemT>>> result = new HashMap<>();
for (ItemT item : mappings.keySet()) {
for (DeviceMapping<ItemT> mapping : mappings.get(item)) {
List<DeviceMapping<ItemT>> list = result.get(mapping.getDevice());
if (list == null) {
list = new ArrayList<>();
result.put(mapping.getDevice(), list);
}
list.add(mapping);
}
}
return result;
private <ItemT extends WithID, FixT extends GPSFix> Map<DeviceIdentifier, List<DeviceMapping<ItemT>>> transformToMappingsByDevice(
Map<ItemT, List<DeviceMapping<ItemT>>> mappings) {
Map<DeviceIdentifier, List<DeviceMapping<ItemT>>> result = new HashMap<>();
for (ItemT item : mappings.keySet()) {
for (DeviceMapping<ItemT> mapping : mappings.get(item)) {
List<DeviceMapping<ItemT>> list = result.get(mapping.getDevice());
if (list == null) {
list = new ArrayList<>();
result.put(mapping.getDevice(), list);
}
list.add(mapping);
}
}
return result;
}
private void updateMarkMappings(boolean loadIfNotCovered) {
//TODO remove fixes, if mappings have been removed
synchronized(markMappings) {
//check if there are new time ranges not covered so far
Map<Mark, List<DeviceMapping<Mark>>> newMappings = getNewMarkMappings();
if (loadIfNotCovered) {
for (Mark mark : newMappings.keySet()) {
DynamicGPSFixTrack<Mark, GPSFix> track = trackedRace.getOrCreateTrack(mark);
List<DeviceMapping<Mark>> oldMappings = markMappings.get(mark);
for (DeviceMapping<Mark> newMapping : newMappings.get(mark)) {
if (! hasMappingAlreadyBeenLoaded(newMapping, oldMappings)) {
gpsFixStore.loadMarkTrack(track, newMapping);
}
}
}
}
markMappings.clear();
markMappings.putAll(newMappings);
markMappingsByDevices.clear();
markMappingsByDevices.putAll(transformToMappingsByDevice(markMappings));
}
updateStartOfTracking();
// TODO remove fixes, if mappings have been removed
synchronized (markMappings) {
// check if there are new time ranges not covered so far
Map<Mark, List<DeviceMapping<Mark>>> newMappings = getNewMarkMappings();
if (loadIfNotCovered) {
for (Mark mark : newMappings.keySet()) {
DynamicGPSFixTrack<Mark, GPSFix> track = trackedRace.getOrCreateTrack(mark);
List<DeviceMapping<Mark>> oldMappings = markMappings.get(mark);
for (DeviceMapping<Mark> newMapping : newMappings.get(mark)) {
if (!hasMappingAlreadyBeenLoaded(newMapping, oldMappings)) {
gpsFixStore.loadMarkTrack(track, newMapping);
}
}
}
}
markMappings.clear();
markMappings.putAll(newMappings);
markMappingsByDevices.clear();
markMappingsByDevices.putAll(transformToMappingsByDevice(markMappings));
}
updateStartOfTracking();
}
@Override
public void visit(DeviceMarkMappingEvent event) {
if (trackedRace != null) updateMarkMappings(true);
if (trackedRace != null)
updateMarkMappings(true);
}
private void updateCompetitorMappings(boolean loadIfNotCovered) {
//TODO remove fixes, if mappings have been removed
synchronized(competitorMappings) {
//check if there are new time ranges not covered so far
Map<Competitor, List<DeviceMapping<Competitor>>> newMappings = getNewCompetitorMappings();
if (loadIfNotCovered) {
for (Competitor competitor : newMappings.keySet()) {
DynamicGPSFixTrack<Competitor, GPSFixMoving> track = trackedRace.getTrack(competitor);
List<DeviceMapping<Competitor>> oldMappings = competitorMappings.get(competitor);
for (DeviceMapping<Competitor> newMapping : newMappings.get(competitor)) {
if (! hasMappingAlreadyBeenLoaded(newMapping, oldMappings)) {
gpsFixStore.loadCompetitorTrack(track, newMapping);
}
}
}
}
competitorMappings.clear();
competitorMappings.putAll(newMappings);
competitorMappingsByDevices.clear();
competitorMappingsByDevices.putAll(transformToMappingsByDevice(competitorMappings));
}
updateStartOfTracking();
private void updateCompetitorMappings(boolean loadIfNotCovered) {
// TODO remove fixes, if mappings have been removed
synchronized (competitorMappings) {
// check if there are new time ranges not covered so far
Map<Competitor, List<DeviceMapping<Competitor>>> newMappings = getNewCompetitorMappings();
if (loadIfNotCovered) {
for (Competitor competitor : newMappings.keySet()) {
DynamicGPSFixTrack<Competitor, GPSFixMoving> track = trackedRace.getTrack(competitor);
List<DeviceMapping<Competitor>> oldMappings = competitorMappings.get(competitor);
for (DeviceMapping<Competitor> newMapping : newMappings.get(competitor)) {
if (!hasMappingAlreadyBeenLoaded(newMapping, oldMappings)) {
gpsFixStore.loadCompetitorTrack(track, newMapping);
}
}
}
}
competitorMappings.clear();
competitorMappings.putAll(newMappings);
competitorMappingsByDevices.clear();
competitorMappingsByDevices.putAll(transformToMappingsByDevice(competitorMappings));
}
updateStartOfTracking();
}
@Override
public void visit(DeviceCompetitorMappingEvent event) {
if (trackedRace != null) updateCompetitorMappings(true);
if (trackedRace != null)
updateCompetitorMappings(true);
}
@Override
public void visit(StartTrackingEvent event) {
if (trackedRace == null) startTracking(event);
if (trackedRace == null)
startTracking(event);
}
private void startTracking(StartTrackingEvent event) {
RaceLog raceLog = params.getRaceLog();
RaceColumn raceColumn = params.getRaceColumn();
Fleet fleet = params.getFleet();
Pair<String, BoatClass> raceInfo = new RaceInformationFinder(raceLog).analyze();
BoatClass boatClass = raceInfo.getB();
CourseBase courseBase = new LastPublishedCourseDesignFinder(raceLog).analyze();
if (courseBase == null) {
if (event != null) {
raceLog.add(RaceLogEventFactory.INSTANCE.createRevokeEvent(MillisecondsTimePoint.now(),
params.getService().getServerAuthor(), raceLog.getCurrentPassId(), event.getId()));
}
if (event != null) {
raceLog.add(RaceLogEventFactory.INSTANCE.createRevokeEvent(MillisecondsTimePoint.now(), params
.getService().getServerAuthor(), raceLog.getCurrentPassId(), event.getId()));
}
throw new RaceNotCreatedException(String.format("Course definition for racelog (%s) missing", raceLog));
}
Course course = new CourseImpl(raceInfo.getA() + " course", courseBase.getWaypoints());
if (raceColumn.getTrackedRace(fleet) != null) {
throw new RaceNotCreatedException(String.format("Race for racelog (%s) has already been created", raceLog));
}
Iterable<Competitor> competitors = new RegisteredCompetitorsAnalyzer(raceLog).analyze();
final RaceDefinition raceDef = new RaceDefinitionImpl(raceInfo.getA(), course, boatClass, competitors);
Iterable<Sideline> sidelines = Collections.<Sideline>emptyList();
//set race definition, so race is linked to leaderboard automatically
Iterable<Sideline> sidelines = Collections.<Sideline> emptyList();
// set race definition, so race is linked to leaderboard automatically
regatta.getRegatta().addRace(raceDef);
raceColumn.setRaceIdentifier(fleet, regatta.getRegatta().getRaceIdentifier(raceDef));
trackedRace = regatta.createTrackedRace(raceDef, sidelines, windStore, gpsFixStore, params.getDelayToLiveInMillis(),
WindTrack.DEFAULT_MILLISECONDS_OVER_WHICH_TO_AVERAGE_WIND, boatClass.getApproximateManeuverDurationInMilliseconds(),
null);
trackedRace.setStatus(new TrackedRaceStatusImpl(TrackedRaceStatusEnum.TRACKING, 0));
updateStartOfTracking();
//update the device mappings (without loading the fixes, as the TrackedRace does this itself on startup)
updateCompetitorMappings(false);
updateMarkMappings(false);
//add a listener, so new fixes will also be forwarded to the race
trackedRace = regatta.createTrackedRace(raceDef, sidelines, windStore, gpsFixStore,
params.getDelayToLiveInMillis(), WindTrack.DEFAULT_MILLISECONDS_OVER_WHICH_TO_AVERAGE_WIND,
boatClass.getApproximateManeuverDurationInMilliseconds(), null);
trackedRace.setStatus(new TrackedRaceStatusImpl(TrackedRaceStatusEnum.TRACKING, 0));
updateStartOfTracking();
// update the device mappings (without loading the fixes, as the TrackedRace does this itself on startup)
updateCompetitorMappings(false);
updateMarkMappings(false);
// add a listener, so new fixes will also be forwarded to the race
gpsFixStore.addListener(this);
logger.info(String.format("Started tracking race-log race (%s)", raceLog));
@@ -351,32 +354,32 @@ public class RaceLogRaceTracker extends BaseRaceLogEventVisitor implements RaceT
public RaceLogConnectivityParams getParams() {
return params;
}
@Override
public void fixReceived(DeviceIdentifier device, GPSFix fix) {
TimePoint timePoint = fix.getTimePoint();
if (markMappingsByDevices.get(device) != null) {
for (DeviceMapping<Mark> mapping : markMappingsByDevices.get(device)) {
Mark mark = mapping.getMappedTo();
if (mapping.getTimeRange().includes(timePoint)) {
trackedRace.recordFix(mark, fix);
}
}
}
if (competitorMappingsByDevices.get(device) != null) {
for (DeviceMapping<Competitor> mapping : competitorMappingsByDevices.get(device)) {
Competitor comp = mapping.getMappedTo();
if (mapping.getTimeRange().includes(timePoint)) {
if (fix instanceof GPSFixMoving) {
trackedRace.recordFix(comp, (GPSFixMoving) fix);
} else {
logger.log(Level.WARNING,
String.format("Could not add fix for competitor (%s) in race (%s), as it is no GPSFixMoving",
comp, params.getRaceLog()));
}
}
}
}
}
@Override
public void fixReceived(DeviceIdentifier device, GPSFix fix) {
TimePoint timePoint = fix.getTimePoint();
if (markMappingsByDevices.get(device) != null) {
for (DeviceMapping<Mark> mapping : markMappingsByDevices.get(device)) {
Mark mark = mapping.getMappedTo();
if (mapping.getTimeRange().includes(timePoint)) {
trackedRace.recordFix(mark, fix);
}
}
}
if (competitorMappingsByDevices.get(device) != null) {
for (DeviceMapping<Competitor> mapping : competitorMappingsByDevices.get(device)) {
Competitor comp = mapping.getMappedTo();
if (mapping.getTimeRange().includes(timePoint)) {
if (fix instanceof GPSFixMoving) {
trackedRace.recordFix(comp, (GPSFixMoving) fix);
} else {
logger.log(Level.WARNING, String.format(
"Could not add fix for competitor (%s) in race (%s), as it is no GPSFixMoving", comp,
params.getRaceLog()));
}
}
}
}
}
}
@@ -5,15 +5,15 @@ import com.sap.sailing.domain.racelog.tracking.RaceLogTrackingAdapter;
import com.sap.sailing.domain.racelog.tracking.RaceLogTrackingAdapterFactory;
public enum RaceLogTrackingAdapterFactoryImpl implements RaceLogTrackingAdapterFactory {
INSTANCE;
private RaceLogTrackingAdapter adapter;
INSTANCE;
private RaceLogTrackingAdapter adapter;
@Override
public RaceLogTrackingAdapter getAdapter(DomainFactory baseDomainFactory) {
if (adapter == null) {
adapter = new RaceLogTrackingAdapterImpl(baseDomainFactory);
}
return adapter;
}
@Override
public RaceLogTrackingAdapter getAdapter(DomainFactory baseDomainFactory) {
if (adapter == null) {
adapter = new RaceLogTrackingAdapterImpl(baseDomainFactory);
}
return adapter;
}
}
@@ -11,9 +11,11 @@ import java.util.logging.Level;
import java.util.logging.Logger;
import com.sap.sailing.domain.base.BoatClass;
import com.sap.sailing.domain.base.Competitor;
import com.sap.sailing.domain.base.DomainFactory;
import com.sap.sailing.domain.base.Fleet;
import com.sap.sailing.domain.base.RaceColumn;
import com.sap.sailing.domain.base.RaceColumnListener;
import com.sap.sailing.domain.base.Regatta;
import com.sap.sailing.domain.common.RegattaIdentifier;
import com.sap.sailing.domain.common.impl.Function;
@@ -23,12 +25,13 @@ import com.sap.sailing.domain.common.impl.Util.Pair;
import com.sap.sailing.domain.common.racelog.tracking.NotDenotableForTrackingException;
import com.sap.sailing.domain.common.racelog.tracking.RaceLogTrackingState;
import com.sap.sailing.domain.common.racelog.tracking.RaceNotCreatedException;
import com.sap.sailing.domain.leaderboard.FlexibleLeaderboard;
import com.sap.sailing.domain.leaderboard.Leaderboard;
import com.sap.sailing.domain.leaderboard.RegattaLeaderboard;
import com.sap.sailing.domain.leaderboard.ResultDiscardingRule;
import com.sap.sailing.domain.racelog.RaceLog;
import com.sap.sailing.domain.racelog.RaceLogEvent;
import com.sap.sailing.domain.racelog.RaceLogEventFactory;
import com.sap.sailing.domain.racelog.RaceLogIdentifier;
import com.sap.sailing.domain.racelog.tracking.RaceLogTrackingAdapter;
import com.sap.sailing.domain.racelog.tracking.analyzing.impl.RaceLogTrackingStateAnalyzer;
import com.sap.sailing.domain.tracking.RacesHandle;
@@ -36,92 +39,169 @@ import com.sap.sailing.domain.tracking.TrackedRace;
import com.sap.sailing.server.RacingEventService;
public class RaceLogTrackingAdapterImpl implements RaceLogTrackingAdapter {
private static final Logger logger = Logger.getLogger(RaceLogTrackingAdapterImpl.class.getName());
private final DomainFactory domainFactory;
private final long delayToLiveInMillis;
private static final Logger logger = Logger.getLogger(RaceLogTrackingAdapterImpl.class.getName());
public RaceLogTrackingAdapterImpl(DomainFactory domainFactory) {
this.domainFactory = domainFactory;
this.delayToLiveInMillis = TrackedRace.DEFAULT_LIVE_DELAY_IN_MILLISECONDS;
}
// private final DomainFactory domainFactory;
private final long delayToLiveInMillis;
public RaceLogTrackingAdapterImpl(DomainFactory domainFactory) {
// this.domainFactory = domainFactory;
this.delayToLiveInMillis = TrackedRace.DEFAULT_LIVE_DELAY_IN_MILLISECONDS;
}
@Override
public RacesHandle addRace(RacingEventService service, RegattaIdentifier regattaToAddTo, Leaderboard leaderboard,
RaceColumn raceColumn, Fleet fleet, long timeoutInMilliseconds) throws MalformedURLException,
FileNotFoundException, URISyntaxException, RaceNotCreatedException, Exception, RaceNotCreatedException {
Regatta regatta = regattaToAddTo == null ? null : service.getRegatta(regattaToAddTo);
RaceLogConnectivityParams params = new RaceLogConnectivityParams(service, regatta, raceColumn, fleet,
leaderboard, delayToLiveInMillis);
return service.addRace(regattaToAddTo, params, timeoutInMilliseconds);
}
@Override
public RacesHandle addRace(RacingEventService service, RegattaIdentifier regattaToAddTo, Leaderboard leaderboard,
RaceColumn raceColumn, Fleet fleet, long timeoutInMilliseconds)
throws MalformedURLException, FileNotFoundException, URISyntaxException, RaceNotCreatedException, Exception,
RaceNotCreatedException {
Regatta regatta = regattaToAddTo == null ? null : service.getRegatta(regattaToAddTo);
RaceLogConnectivityParams params = new RaceLogConnectivityParams(service, regatta,
raceColumn, fleet, leaderboard, delayToLiveInMillis);
return service.addRace(regattaToAddTo, params, timeoutInMilliseconds);
}
private Map<RaceColumn, Collection<Fleet>> findInLeaderboard(Leaderboard leaderboard,
Function<Pair<RaceColumn, Fleet>, Boolean> includeInResult) {
Function<Pair<RaceColumn, Fleet>, Boolean> includeInResult) {
Map<RaceColumn, Collection<Fleet>> result = new HashMap<>();
for (RaceColumn raceColumn : leaderboard.getRaceColumns()) {
for (Fleet fleet : raceColumn.getFleets()) {
if (includeInResult.perform(new Pair<>(raceColumn, fleet))) {
Collection<Fleet> coll = result.get(raceColumn);
if (includeInResult.perform(new Pair<>(raceColumn, fleet))) {
Collection<Fleet> coll = result.get(raceColumn);
if (coll == null) {
coll = new ArrayList<>();
result.put(raceColumn, coll);
}
coll.add(fleet);
}
}
}
}
return result;
}
@Override
public Map<RaceColumn, Collection<Fleet>> listRacesThatCanBeAdded(final RacingEventService service,
Leaderboard leaderboard) {
return findInLeaderboard(leaderboard, new Function<Util.Pair<RaceColumn,Fleet>, Boolean>() {
@Override
public Boolean perform(Pair<RaceColumn, Fleet> in) {
return canRaceBeAdded(service, in.getA(), in.getB());
}
});
public Map<RaceColumn, Collection<Fleet>> listRaceLogTrackersThatCanBeAdded(final RacingEventService service,
Leaderboard leaderboard) {
return findInLeaderboard(leaderboard, new Function<Util.Pair<RaceColumn, Fleet>, Boolean>() {
@Override
public Boolean perform(Pair<RaceColumn, Fleet> in) {
return canRaceLogTrackerBeAdded(service, in.getA(), in.getB());
}
});
}
@Override
public void denoteForRaceLogTracking(RacingEventService service, Leaderboard leaderboard, RaceColumn raceColumn, Fleet fleet,
String raceName)
throws NotDenotableForTrackingException {
BoatClass boatClass = null;
if (leaderboard instanceof RegattaLeaderboard) {
RegattaLeaderboard rLeaderboard = (RegattaLeaderboard) leaderboard;
boatClass = rLeaderboard.getRegatta().getBoatClass();
} else if (leaderboard instanceof FlexibleLeaderboard) {
logger.log(Level.INFO, "Choosing 49er as default boat class for racelog-tracked race in FlexibleLeaderboard");
boatClass = domainFactory.getOrCreateBoatClass("49er");
}
if (raceName == null) {
raceName = leaderboard.getName() + " " + raceColumn.getName() + " " + fleet.getName();
}
RaceLog raceLog = raceColumn.getRaceLog(fleet);
assert raceLog != null : new NotDenotableForTrackingException("No RaceLog found in place");
assert raceLog.isEmpty() : new NotDenotableForTrackingException("RaceLog is not empty");
RaceLogEvent event = RaceLogEventFactory.INSTANCE.createDenoteForTrackingEvent(
MillisecondsTimePoint.now(), service.getServerAuthor(), raceLog.getCurrentPassId(), raceName, boatClass);
raceLog.add(event);
}
@Override
public void denoteForRaceLogTracking(RacingEventService service, Leaderboard leaderboard, RaceColumn raceColumn,
Fleet fleet, String raceName) throws NotDenotableForTrackingException {
@Override
public boolean canRaceBeAdded(RacingEventService service, RaceColumn raceColumn, Fleet fleet) {
if (raceColumn.getTrackedRace(fleet) == null) {
RaceLog raceLog = raceColumn.getRaceLog(fleet);
if (service.getRaceTrackerById(raceLog.getId()) == null) {
RaceLogTrackingState state = new RaceLogTrackingStateAnalyzer(raceLog).analyze();
return state.isForTracking();
}
}
return false;
}
BoatClass boatClass = null;
if (leaderboard instanceof RegattaLeaderboard) {
RegattaLeaderboard rLeaderboard = (RegattaLeaderboard) leaderboard;
boatClass = rLeaderboard.getRegatta().getBoatClass();
} else {
throw new NotDenotableForTrackingException("Can only denote RegattaLeaderboards for RaceLog-tracking");
}
if (raceName == null) {
raceName = leaderboard.getName() + " " + raceColumn.getName() + " " + fleet.getName();
}
RaceLog raceLog = raceColumn.getRaceLog(fleet);
assert raceLog != null : new NotDenotableForTrackingException("No RaceLog found in place");
assert raceLog.isEmpty() : new NotDenotableForTrackingException("RaceLog is not empty");
RaceLogEvent event = RaceLogEventFactory.INSTANCE.createDenoteForTrackingEvent(MillisecondsTimePoint.now(),
service.getServerAuthor(), raceLog.getCurrentPassId(), raceName, boatClass);
raceLog.add(event);
}
@Override
public void denoteForRaceLogTracking(final RacingEventService service, final Leaderboard leaderboard)
throws NotDenotableForTrackingException {
for (RaceColumn column : leaderboard.getRaceColumns()) {
for (Fleet fleet : column.getFleets()) {
denoteForRaceLogTracking(service, leaderboard, column, fleet, null);
}
}
// add listener, that also denotes all newly added RaceLogs for tracking
leaderboard.addRaceColumnListener(new RaceColumnListener() {
private static final long serialVersionUID = 3229728745966607941L;
@Override
public void trackedRaceUnlinked(RaceColumn raceColumn, Fleet fleet, TrackedRace trackedRace) {}
@Override
public void trackedRaceLinked(RaceColumn raceColumn, Fleet fleet, TrackedRace trackedRace) {}
@Override
public void resultDiscardingRuleChanged(ResultDiscardingRule oldDiscardingRule,
ResultDiscardingRule newDiscardingRule) {}
@Override
public void raceLogEventAdded(RaceColumn raceColumn, RaceLogIdentifier raceLogIdentifier, RaceLogEvent event) {}
@Override
public void raceColumnRemovedFromContainer(RaceColumn raceColumn) {}
@Override
public void raceColumnMoved(RaceColumn raceColumn, int newIndex) {}
@Override
public void raceColumnAddedToContainer(RaceColumn raceColumn) {
for (Fleet fleet : raceColumn.getFleets()) {
try {
denoteForRaceLogTracking(service, leaderboard, raceColumn, fleet, null);
} catch (NotDenotableForTrackingException e) {
logger.log(Level.WARNING, "Listener could not denote newly added RaceLog for racelog-tracking");
e.printStackTrace();
}
}
}
@Override
public boolean isTransient() {
return true;
}
@Override
public void isStartsWithZeroScoreChanged(RaceColumn raceColumn, boolean newIsStartsWithZeroScore) { }
@Override
public void isMedalRaceChanged(RaceColumn raceColumn, boolean newIsMedalRace) {}
@Override
public void isFirstColumnIsNonDiscardableCarryForwardChanged(RaceColumn raceColumn,
boolean firstColumnIsNonDiscardableCarryForward) {}
@Override
public void hasSplitFleetContiguousScoringChanged(RaceColumn raceColumn, boolean hasSplitFleetContiguousScoring) {}
@Override
public void factorChanged(RaceColumn raceColumn, Double oldFactor, Double newFactor) {}
@Override
public void competitorDisplayNameChanged(Competitor competitor, String oldDisplayName, String displayName) {}
@Override
public boolean canAddRaceColumnToContainer(RaceColumn raceColumn) {
return true;
}
});
}
@Override
public boolean canRaceLogTrackerBeAdded(RacingEventService service, RaceColumn raceColumn, Fleet fleet) {
if (raceColumn.getTrackedRace(fleet) == null) {
RaceLog raceLog = raceColumn.getRaceLog(fleet);
if (service.getRaceTrackerById(raceLog.getId()) == null) {
RaceLogTrackingState state = new RaceLogTrackingStateAnalyzer(raceLog).analyze();
return state.isForTracking();
}
}
return false;
}
@Override
public boolean isDenotedForRaceLogTracking(RacingEventService service, RaceColumn raceColumn, Fleet fleet) {
return new RaceLogTrackingStateAnalyzer(raceColumn.getRaceLog(fleet)).analyze().isForTracking();
}
}
@@ -7,8 +7,8 @@ import com.sap.sailing.domain.racelog.tracking.SmartphoneImeiIdentifier;
public class SmartphoneImeiMongoHandlerImpl implements DeviceIdentifierMongoHandler {
private SmartphoneImeiIdentifier castIdentifier(DeviceIdentifier identifier) throws TransformationException {
if (! (identifier instanceof SmartphoneImeiIdentifier))
throw new TransformationException("Expected a SmartphoneImeiIdentifier, got instead: " + identifier);
if (!(identifier instanceof SmartphoneImeiIdentifier))
throw new TransformationException("Expected a SmartphoneImeiIdentifier, got instead: " + identifier);
return (SmartphoneImeiIdentifier) identifier;
}
@@ -19,17 +19,18 @@ import com.sap.sailing.server.gateway.serialization.JsonSerializer;
import com.sap.sailing.server.gateway.serialization.racelog.tracking.DeviceIdentifierJsonHandler;
import com.sap.sailing.server.gateway.serialization.racelog.tracking.GPSFixJsonHandler;
public class RecordFixesPostServlet extends AbstractJsonPostServlet<Triple<DeviceIdentifier, Serializable, List<GPSFix>>, Void> {
public class RecordFixesPostServlet extends
AbstractJsonPostServlet<Triple<DeviceIdentifier, Serializable, List<GPSFix>>, Void> {
private static final long serialVersionUID = 2778739335260621119L;
private DeviceAndSessionIdentifierWithGPSFixesDeserializer deserializer;
@Override
public void init(ServletConfig config) throws ServletException {
super.init(config);
TypeBasedServiceFinder<GPSFixJsonHandler> fixServiceFinder =
getServiceFinderFactory().createServiceFinder(GPSFixJsonHandler.class);
TypeBasedServiceFinder<DeviceIdentifierJsonHandler> deviceServiceFinder =
getServiceFinderFactory().createServiceFinder(DeviceIdentifierJsonHandler.class);
public void init(ServletConfig config) throws ServletException {
super.init(config);
TypeBasedServiceFinder<GPSFixJsonHandler> fixServiceFinder = getServiceFinderFactory().createServiceFinder(
GPSFixJsonHandler.class);
TypeBasedServiceFinder<DeviceIdentifierJsonHandler> deviceServiceFinder = getServiceFinderFactory()
.createServiceFinder(DeviceIdentifierJsonHandler.class);
deserializer = new DeviceAndSessionIdentifierWithGPSFixesDeserializer(fixServiceFinder, deviceServiceFinder);
}
@@ -47,14 +48,14 @@ public class RecordFixesPostServlet extends AbstractJsonPostServlet<Triple<Devic
public Void process(Map<String, String> parameterValues,
Triple<DeviceIdentifier, Serializable, List<GPSFix>> domainObject) throws HttpExceptionWithMessage {
DeviceIdentifier device = domainObject.getA();
//might use the session id in the future
// Serializable sessionId = domainObject.getB();
// might use the session id in the future
// Serializable sessionId = domainObject.getB();
List<GPSFix> fixes = domainObject.getC();
for (GPSFix fix : fixes) {
getService().getGPSFixStore().storeFix(device, fix);
getService().getGPSFixStore().storeFix(device, fix);
}
return null;
return null;
}
}
@@ -19,7 +19,6 @@ public class RaceLogTrackingStateAnalyzer extends RaceLogAnalyzer<RaceLogTrackin
if (event instanceof StartTrackingEvent) {
return RaceLogTrackingState.TRACKING;
} else if (event instanceof DenoteForTrackingEvent) {
System.out.println(RaceLogTrackingState.AWAITING_RACE_DEFINITION);
return RaceLogTrackingState.AWAITING_RACE_DEFINITION;
}
}
@@ -97,6 +97,12 @@ public class AdminConsoleEntryPoint extends AbstractEntryPoint implements Regatt
createSwissTimingRacePanel.setSize("90%", "90%");
addScrollableTab(tabPanel, createSwissTimingRacePanel, stringMessages.createSwissTimingRace());
final RaceLogTrackingEventManagementPanel raceLogTrackingEventManagementPanel = new RaceLogTrackingEventManagementPanel(
sailingService, this, this, stringMessages);
raceLogTrackingEventManagementPanel.setSize("90%", "90%");
addScrollableTab(tabPanel, raceLogTrackingEventManagementPanel, stringMessages.raceLogTracking());
regattaDisplayers.add(raceLogTrackingEventManagementPanel);
IgtimiAccountsPanel igtimiAccountsPanel = new IgtimiAccountsPanel(sailingService, this, stringMessages);
igtimiAccountsPanel.ensureDebugId("IgtimiAccounts");
igtimiAccountsPanel.setSize("90%", "90%");
@@ -178,6 +184,9 @@ public class AdminConsoleEntryPoint extends AbstractEntryPoint implements Regatt
if (competitorPanel.isVisible()) {
competitorPanel.refreshCompetitorList();
}
if (raceLogTrackingEventManagementPanel.isVisible()) {
raceLogTrackingEventManagementPanel.loadLeaderboards();
}
}
});
fillRegattas();
@@ -1,6 +1,6 @@
package com.sap.sailing.gwt.ui.adminconsole;
import java.util.Arrays;
import java.util.ArrayList;
import com.google.gwt.core.client.GWT;
import com.google.gwt.text.shared.SafeHtmlRenderer;
@@ -14,7 +14,6 @@ public class LeaderboardConfigImagesBarCell extends ImagesBarCell {
public static final String ACTION_EDIT = "ACTION_EDIT";
public static final String ACTION_CONFIGURE_URL = "ACTION_CONFIGURE_URL";
public static final String ACTION_EXPORT_XML = "ACTION_EXPORT_XML";
public static final String ACTION_ADD_RACELOG_TRACKER = "ACTION_ADD_RACELOG_TRACKER";
private static AdminConsoleResources resources = GWT.create(AdminConsoleResources.class);
private final StringMessages stringMessages;
@@ -30,12 +29,13 @@ public class LeaderboardConfigImagesBarCell extends ImagesBarCell {
@Override
protected Iterable<ImageSpec> getImageSpecs() {
return Arrays.asList(new ImageSpec(ACTION_EDIT, stringMessages.actionEdit(), makeImagePrototype(resources.editIcon())),
new ImageSpec(ACTION_EDIT_SCORES, stringMessages.actionEditScores(), makeImagePrototype(resources.scoresIcon())),
new ImageSpec(ACTION_EDIT_COMPETITORS, stringMessages.actionEditCompetitors(), makeImagePrototype(resources.competitorsIcon())),
new ImageSpec(ACTION_CONFIGURE_URL, stringMessages.actionConfigureUrl(), makeImagePrototype(resources.settingsActionIcon())),
new ImageSpec(ACTION_REMOVE, stringMessages.actionRemove(), makeImagePrototype(resources.removeIcon())),
new ImageSpec(ACTION_EXPORT_XML, stringMessages.actionExportXML(), makeImagePrototype(resources.exportXMLIcon())),
new ImageSpec(ACTION_ADD_RACELOG_TRACKER, stringMessages.addRaceLogTracker(), makeImagePrototype(resources.addRaceLogTracker())));
ArrayList<ImageSpec> result = new ArrayList<ImageSpec>();
result.add(new ImageSpec(ACTION_EDIT, stringMessages.actionEdit(), makeImagePrototype(resources.editIcon())));
result.add(new ImageSpec(ACTION_EDIT_SCORES, stringMessages.actionEditScores(), makeImagePrototype(resources.scoresIcon())));
result.add(new ImageSpec(ACTION_EDIT_COMPETITORS, stringMessages.actionEditCompetitors(), makeImagePrototype(resources.competitorsIcon())));
result.add(new ImageSpec(ACTION_CONFIGURE_URL, stringMessages.actionConfigureUrl(), makeImagePrototype(resources.settingsActionIcon())));
result.add(new ImageSpec(ACTION_REMOVE, stringMessages.actionRemove(), makeImagePrototype(resources.removeIcon())));
result.add(new ImageSpec(ACTION_EXPORT_XML, stringMessages.actionExportXML(), makeImagePrototype(resources.exportXMLIcon())));
return result;
}
}
@@ -50,7 +50,6 @@ import com.sap.sailing.domain.common.dto.NamedDTO;
import com.sap.sailing.domain.common.dto.RaceColumnDTO;
import com.sap.sailing.domain.common.impl.Util;
import com.sap.sailing.domain.common.impl.Util.Pair;
import com.sap.sailing.domain.common.racelog.tracking.RaceLogTrackingState;
import com.sap.sailing.gwt.ui.adminconsole.DisablableCheckboxCell.IsEnabled;
import com.sap.sailing.gwt.ui.adminconsole.RaceColumnInLeaderboardDialog.RaceColumnDescriptor;
import com.sap.sailing.gwt.ui.client.ErrorReporter;
@@ -76,7 +75,7 @@ import com.sap.sailing.gwt.ui.shared.StrippedLeaderboardDTO;
import com.sap.sse.gwt.ui.DataEntryDialog.DialogCallback;
public class LeaderboardConfigPanel extends FormPanel implements SelectedLeaderboardProvider, RegattaDisplayer, RaceSelectionChangeListener,
TrackedRaceChangedListener {
TrackedRaceChangedListener {
private final TrackedRacesListComposite trackedRacesListComposite;
@@ -132,7 +131,7 @@ public class LeaderboardConfigPanel extends FormPanel implements SelectedLeaderb
private static AnchorTemplates ANCHORTEMPLATE = GWT.create(AnchorTemplates.class);
private static class RaceColumnDTOAndFleetDTOWithNameBasedEquality extends Pair<RaceColumnDTO, FleetDTO> {
public static class RaceColumnDTOAndFleetDTOWithNameBasedEquality extends Pair<RaceColumnDTO, FleetDTO> {
private static final long serialVersionUID = -8742476113296862662L;
public RaceColumnDTOAndFleetDTOWithNameBasedEquality(RaceColumnDTO a, FleetDTO b) {
@@ -250,7 +249,7 @@ public class LeaderboardConfigPanel extends FormPanel implements SelectedLeaderb
int val = -1;
val = (o1 != null && o2 != null && ascending) ? (o1.name.compareTo(o2.name)) : -(o2.name
.compareTo(o1.name));
return val;
}
@@ -362,13 +361,11 @@ public class LeaderboardConfigPanel extends FormPanel implements SelectedLeaderb
}
});
editCompetitorsDialog.show();
} else if (LeaderboardConfigImagesBarCell.ACTION_CONFIGURE_URL.equals(value)) {
openLeaderboardUrlConfigDialog(leaderboardDTO, stringMessages);
} else if (LeaderboardConfigImagesBarCell.ACTION_EXPORT_XML.equals(value)) {
Window.open("/export/xml?domain=leaderboard&name=" + leaderboardDTO.name, "", null);
} else if (LeaderboardConfigImagesBarCell.ACTION_ADD_RACELOG_TRACKER.equals(value)) {
addRaceLogTracker(leaderboardDTO);
}
}
});
@@ -497,7 +494,7 @@ public class LeaderboardConfigPanel extends FormPanel implements SelectedLeaderb
@Override
public boolean isEnabled() {
return getSelectedLeaderboard() != null && !getSelectedLeaderboard().type.isRegattaLeaderboard();
}
})) {
@Override
@@ -521,22 +518,6 @@ public class LeaderboardConfigPanel extends FormPanel implements SelectedLeaderb
}
};
TextColumn<RaceColumnDTOAndFleetDTOWithNameBasedEquality> raceLogTrackerExistsColumn = new TextColumn<RaceColumnDTOAndFleetDTOWithNameBasedEquality>() {
@Override
public String getValue(RaceColumnDTOAndFleetDTOWithNameBasedEquality raceColumnAndFleetName) {
boolean trackerExists = raceColumnAndFleetName.getB().raceLogTrackerForRaceExists;
return trackerExists ? "X" : "";
}
};
TextColumn<RaceColumnDTOAndFleetDTOWithNameBasedEquality> raceLogTrackingStateColumn = new TextColumn<RaceColumnDTOAndFleetDTOWithNameBasedEquality>() {
@Override
public String getValue(RaceColumnDTOAndFleetDTOWithNameBasedEquality raceColumnAndFleetName) {
RaceLogTrackingState state = raceColumnAndFleetName.getB().raceLogTrackingState;
return state.isForTracking() ? state.name() : "";
}
};
ImagesBarColumn<RaceColumnDTOAndFleetDTOWithNameBasedEquality, LeaderboardRaceConfigImagesBarCell> raceActionColumn =
new ImagesBarColumn<RaceColumnDTOAndFleetDTOWithNameBasedEquality, LeaderboardRaceConfigImagesBarCell>(
new LeaderboardRaceConfigImagesBarCell(this, stringMessages));
@@ -557,10 +538,6 @@ public class LeaderboardConfigPanel extends FormPanel implements SelectedLeaderb
setStartTime(object.getA(), object.getB());
} else if(LeaderboardRaceConfigImagesBarCell.ACTION_SHOW_RACELOG.equals(value)) {
showRaceLog(object.getA(), object.getB());
} else if (LeaderboardRaceConfigImagesBarCell.ACTION_ADD_RACELOG_TRACKER.equals(value)) {
addRaceLogTracker(object.getA(), object.getB());
} else if (LeaderboardRaceConfigImagesBarCell.ACTION_DENOTE_FOR_RACELOG_TRACKING.equals(value)) {
denoteForRaceLogTracking(object.getA(), object.getB());
}
}
});
@@ -573,8 +550,6 @@ public class LeaderboardConfigPanel extends FormPanel implements SelectedLeaderb
raceColumnTable.addColumn(isMedalRaceCheckboxColumn, stringMessages.medalRace());
raceColumnTable.addColumn(isLinkedRaceColumn, stringMessages.islinked());
raceColumnTable.addColumn(explicitFactorColumn, stringMessages.factor());
raceColumnTable.addColumn(raceLogTrackerExistsColumn, stringMessages.raceLogTrackerExists());
raceColumnTable.addColumn(raceLogTrackingStateColumn, stringMessages.raceLogTrackingState());
raceColumnTable.addColumn(raceActionColumn, stringMessages.actions());
raceColumnAndFleetList.addDataDisplay(raceColumnTable);
raceColumnTable.setWidth("500px");
@@ -794,7 +769,7 @@ public class LeaderboardConfigPanel extends FormPanel implements SelectedLeaderb
}
});
}
private void openRaceLogDialog(RaceLogDTO raceLogDTO) {
RaceLogDialog dialog = new RaceLogDialog(raceLogDTO, stringMessages, new DialogCallback<RaceLogDTO>() {
@Override
@@ -927,12 +902,12 @@ public class LeaderboardConfigPanel extends FormPanel implements SelectedLeaderb
+ selectedRaceColumnName + " in leaderboard " + selectedLeaderboardName + ": "
+ t.getMessage());
}
@Override
public void onSuccess(Map<String, RegattaAndRaceIdentifier> regattaAndRaceNamesPerFleet) {
if (regattaAndRaceNamesPerFleet != null && !regattaAndRaceNamesPerFleet.isEmpty()) {
RegattaAndRaceIdentifier raceIdentifier = regattaAndRaceNamesPerFleet
.get(selectedFleetName);
RegattaAndRaceIdentifier raceIdentifier = regattaAndRaceNamesPerFleet
.get(selectedFleetName);
if (raceIdentifier != null) {
selectRaceInList(raceIdentifier.getRegattaName(), raceIdentifier.getRaceName());
} else {
@@ -1028,7 +1003,7 @@ public class LeaderboardConfigPanel extends FormPanel implements SelectedLeaderb
public void onFailure(Throwable caught) {
errorReporter.reportError(stringMessages.errorUpdatingIsMedalRace(caught.getMessage()));
}
@Override
public void onSuccess(Void result) {
getSelectedLeaderboard().setIsMedalRace(raceInLeaderboard.getRaceColumnName(), isMedalRace);
@@ -1047,7 +1022,7 @@ public class LeaderboardConfigPanel extends FormPanel implements SelectedLeaderb
@Override
public void cancel() {
}
@Override
public void ok(final List<RaceColumnDTO> result) {
updateRaceColumnsOfLeaderboard(leaderboardName, existingRaceColumns, result);
@@ -1163,7 +1138,7 @@ public class LeaderboardConfigPanel extends FormPanel implements SelectedLeaderb
@Override
public void cancel() {
}
@Override
public void ok(final LeaderboardDescriptor newLeaderboard) {
sailingService.createFlexibleLeaderboard(newLeaderboard.getName(), newLeaderboard.getDisplayName(), newLeaderboard.getDiscardThresholds(),
@@ -1174,7 +1149,7 @@ public class LeaderboardConfigPanel extends FormPanel implements SelectedLeaderb
errorReporter.reportError("Error trying to create the new flexible leaderboard " + newLeaderboard.getName()
+ ": " + t.getMessage());
}
@Override
public void handleSuccess(StrippedLeaderboardDTO result) {
addLeaderboard(result);
@@ -1203,7 +1178,7 @@ public class LeaderboardConfigPanel extends FormPanel implements SelectedLeaderb
errorReporter.reportError("Error trying to create the new regatta leaderboard " + newLeaderboard.getName()
+ ": " + t.getMessage());
}
@Override
public void onSuccess(StrippedLeaderboardDTO result) {
addLeaderboard(result);
@@ -1229,7 +1204,7 @@ public class LeaderboardConfigPanel extends FormPanel implements SelectedLeaderb
errorReporter.reportError("Error trying to update leaderboard " + oldLeaderboardName + ": "
+ t.getMessage());
}
@Override
public void onSuccess(StrippedLeaderboardDTO updatedLeaderboard) {
int indexOfLeaderboard = 0;
@@ -1257,7 +1232,7 @@ public class LeaderboardConfigPanel extends FormPanel implements SelectedLeaderb
@Override
public void onFailure(Throwable caught) {
errorReporter.reportError("Error trying to remove the leaderboards:" + caught.getMessage());
}
@@ -1335,58 +1310,4 @@ public class LeaderboardConfigPanel extends FormPanel implements SelectedLeaderb
public StrippedLeaderboardDTO getSelectedLeaderboard() {
return leaderboardSelectionModel.getSelectedSet().isEmpty() ? null : leaderboardSelectionModel.getSelectedSet().iterator().next();
}
private void addRaceLogTracker(final StrippedLeaderboardDTO leaderboard) {
final RaceColumnDTOAndFleetDTOWithNameBasedEquality selectedRCFleet = getSelectedRaceColumnWithFleet();
if (leaderboard.raceLogTrackedRacesCouldBeAdded) {
sailingService.addRaceLogTrackers(leaderboard.name, new AsyncCallback<Void>() {
@Override
public void onSuccess(Void result) {
loadAndRefreshLeaderboard(leaderboard.name, selectedRCFleet.getA().getName());
}
@Override
public void onFailure(Throwable caught) {
errorReporter.reportError("Failed to add RaceLog tracker: " + caught.getMessage());
}
});
} else {
errorReporter.reportError("No RaceLogTracker can be added for any of the RaceLogs in this leaderboard");
}
}
private void addRaceLogTracker(final RaceColumnDTO raceColumn, FleetDTO fleet) {
if (fleet.raceLogTrackedRaceCouldBeAdded) {
final StrippedLeaderboardDTO leaderboard = getSelectedLeaderboard();
sailingService.addRaceLogTracker(leaderboard.name, raceColumn.getName(), fleet.getName(), new AsyncCallback<Void>() {
@Override
public void onSuccess(Void result) {
loadAndRefreshLeaderboard(leaderboard.name, raceColumn.getName());
}
@Override
public void onFailure(Throwable caught) {
errorReporter.reportError("Failed to add RaceLog trackers: " + caught.getMessage());
}
});
} else {
errorReporter.reportError("No RaceLogTracker can be added for the RaceLog of this fleet");
}
}
private void denoteForRaceLogTracking(final RaceColumnDTO raceColumn, final FleetDTO fleet) {
final StrippedLeaderboardDTO leaderboard = getSelectedLeaderboard();
sailingService.denoteForRaceLogTracking(leaderboard.name, raceColumn.getName(), fleet.getName(), new AsyncCallback<Void>() {
@Override
public void onSuccess(Void result) {
loadAndRefreshLeaderboard(leaderboard.name, raceColumn.getName());
refreshRaceLog(raceColumn, fleet, true);
}
@Override
public void onFailure(Throwable caught) {
errorReporter.reportError("Could not denote for RaceLog tracking: " + caught.getMessage());
}
});
}
}
@@ -16,8 +16,6 @@ public class LeaderboardRaceConfigImagesBarCell extends ImagesBarCell {
public final static String ACTION_REFRESH_RACELOG = "ACTION_REFRESH_RACE_LOG";
public final static String ACTION_SET_STARTTIME = "ACTION_SET_STARTTIME";
public final static String ACTION_SHOW_RACELOG = "ACTION_SHOW_RACELOG";
public final static String ACTION_ADD_RACELOG_TRACKER = "ACTION_ADD_RACELOG_TRACKER";
public final static String ACTION_DENOTE_FOR_RACELOG_TRACKING = "ACTION_DENOTE_FOR_RACELOG_TRACKING";
private final StringMessages stringMessages;
private final SelectedLeaderboardProvider selectedLeaderboardProvider;
@@ -42,8 +40,6 @@ public class LeaderboardRaceConfigImagesBarCell extends ImagesBarCell {
result.add(new ImageSpec(ACTION_REFRESH_RACELOG, stringMessages.refreshRaceLog(), makeImagePrototype(resources.reloadIcon())));
result.add(new ImageSpec(ACTION_SET_STARTTIME, stringMessages.setStartTime(), makeImagePrototype(resources.clockIcon())));
result.add(new ImageSpec(ACTION_SHOW_RACELOG, stringMessages.raceLog(), makeImagePrototype(resources.flagIcon())));
result.add(new ImageSpec(ACTION_ADD_RACELOG_TRACKER, stringMessages.addRaceLogTracker(), makeImagePrototype(resources.addRaceLogTracker())));
result.add(new ImageSpec(ACTION_DENOTE_FOR_RACELOG_TRACKING, stringMessages.denoteForRaceLogTracking(), makeImagePrototype(resources.denoteForRaceLogTracking())));
return result;
}
}
@@ -0,0 +1,41 @@
package com.sap.sailing.gwt.ui.adminconsole;
import java.util.ArrayList;
import com.google.gwt.core.client.GWT;
import com.google.gwt.text.shared.SafeHtmlRenderer;
import com.sap.sailing.gwt.ui.client.StringMessages;
import com.sap.sailing.gwt.ui.client.shared.components.ImagesBarCell;
import com.sap.sailing.gwt.ui.shared.StrippedLeaderboardDTO;
public class RaceLogTrackingEventManagementImagesBarCell extends ImagesBarCell {
public static final String ACTION_DENOTE_FOR_RACELOG_TRACKING = "ACTION_DENOTE_FOR_RACELOG_TRACKING";
public static final String ACTION_ADD_RACELOG_TRACKERS = "ACTION_ADD_RACELOG_TRACKERS";
private static AdminConsoleResources resources = GWT.create(AdminConsoleResources.class);
private final StringMessages stringMessages;
public RaceLogTrackingEventManagementImagesBarCell(StringMessages stringMessages) {
super();
this.stringMessages = stringMessages;
}
public RaceLogTrackingEventManagementImagesBarCell(SafeHtmlRenderer<String> renderer, StringMessages stringConstants) {
super();
this.stringMessages = stringConstants;
}
@Override
protected Iterable<ImageSpec> getImageSpecs() {
ArrayList<ImageSpec> result = new ArrayList<ImageSpec>();
StrippedLeaderboardDTO leaderboard = (StrippedLeaderboardDTO) getContext().getKey();
if (! leaderboard.isDenotedForRaceLogTracking) {
result.add(new ImageSpec(ACTION_DENOTE_FOR_RACELOG_TRACKING, stringMessages.denoteForRaceLogTracking(), makeImagePrototype(resources.denoteForRaceLogTracking())));
}
if (leaderboard.raceLogTrackersCanBeAdded) {
result.add(new ImageSpec(ACTION_ADD_RACELOG_TRACKERS, stringMessages.addRaceLogTrackers(), makeImagePrototype(resources.addRaceLogTracker())));
}
return result;
}
}
@@ -0,0 +1,401 @@
package com.sap.sailing.gwt.ui.adminconsole;
import java.util.ArrayList;
import java.util.List;
import com.google.gwt.cell.client.FieldUpdater;
import com.google.gwt.core.client.GWT;
import com.google.gwt.user.cellview.client.CellTable;
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.CaptionPanel;
import com.google.gwt.user.client.ui.Grid;
import com.google.gwt.user.client.ui.HorizontalPanel;
import com.google.gwt.user.client.ui.Label;
import com.google.gwt.user.client.ui.VerticalPanel;
import com.google.gwt.view.client.ListDataProvider;
import com.google.gwt.view.client.MultiSelectionModel;
import com.google.gwt.view.client.SelectionChangeEvent;
import com.google.gwt.view.client.SingleSelectionModel;
import com.sap.sailing.domain.common.LeaderboardType;
import com.sap.sailing.domain.common.dto.FleetDTO;
import com.sap.sailing.domain.common.dto.RaceColumnDTO;
import com.sap.sailing.domain.common.racelog.tracking.RaceLogTrackingState;
import com.sap.sailing.gwt.ui.adminconsole.LeaderboardConfigPanel.RaceColumnDTOAndFleetDTOWithNameBasedEquality;
import com.sap.sailing.gwt.ui.client.ErrorReporter;
import com.sap.sailing.gwt.ui.client.RaceSelectionModel;
import com.sap.sailing.gwt.ui.client.RegattaRefresher;
import com.sap.sailing.gwt.ui.client.SailingServiceAsync;
import com.sap.sailing.gwt.ui.client.StringMessages;
import com.sap.sailing.gwt.ui.client.shared.panels.LabeledAbstractFilterablePanel;
import com.sap.sailing.gwt.ui.shared.StrippedLeaderboardDTO;
/**
* Allows the user to start and stop tracking of races using the RaceLog-tracking connector.
*/
public class RaceLogTrackingEventManagementPanel extends AbstractEventManagementPanel {
private final ListDataProvider<StrippedLeaderboardDTO> leaderboardList;
private final ListDataProvider<RaceColumnDTOAndFleetDTOWithNameBasedEquality> raceColumnAndFleetList;
private final CellTable<StrippedLeaderboardDTO> leaderboardTable;
private final CellTable<RaceColumnDTOAndFleetDTOWithNameBasedEquality> raceColumnTable;
private final CaptionPanel selectedLeaderBoardPanel;
private final CaptionPanel trackedRacesCaptionPanel;
private LabeledAbstractFilterablePanel<StrippedLeaderboardDTO> filterLeaderboardPanel;
final SingleSelectionModel<RaceColumnDTOAndFleetDTOWithNameBasedEquality> raceColumnTableSelectionModel;
private List<StrippedLeaderboardDTO> availableLeaderboardList;
private final MultiSelectionModel<StrippedLeaderboardDTO> leaderboardSelectionModel;
public RaceLogTrackingEventManagementPanel(SailingServiceAsync sailingService, RegattaRefresher regattaRefresher,
ErrorReporter errorReporter, StringMessages stringMessages) {
super(sailingService, regattaRefresher, errorReporter, new RaceSelectionModel(), stringMessages);
leaderboardList = new ListDataProvider<StrippedLeaderboardDTO>();
raceColumnAndFleetList = new ListDataProvider<RaceColumnDTOAndFleetDTOWithNameBasedEquality>();
this.errorReporter = errorReporter;
this.availableLeaderboardList = new ArrayList<StrippedLeaderboardDTO>();
VerticalPanel mainPanel = new VerticalPanel();
mainPanel.setWidth("100%");
this.setWidget(mainPanel);
//Create leaderboards list and functionality
CaptionPanel leaderboardsCaptionPanel = new CaptionPanel(stringMessages.leaderboards());
leaderboardsCaptionPanel.setStyleName("bold");
leaderboardsCaptionPanel.setWidth("75%");
mainPanel.add(leaderboardsCaptionPanel);
VerticalPanel leaderboardsPanel = new VerticalPanel();
leaderboardsCaptionPanel.add(leaderboardsPanel);
HorizontalPanel leaderboardConfigControlsPanel = new HorizontalPanel();
Label lblFilterEvents = new Label(stringMessages.filterLeaderboardsByName() + ": ");
leaderboardConfigControlsPanel.setSpacing(5);
AdminConsoleTableResources tableRes = GWT.create(AdminConsoleTableResources.class);
leaderboardTable = new CellTable<StrippedLeaderboardDTO>(/* pageSize */10000, tableRes);
filterLeaderboardPanel = new LabeledAbstractFilterablePanel<StrippedLeaderboardDTO>(lblFilterEvents, availableLeaderboardList, leaderboardTable, leaderboardList) {
@Override
public List<String> getSearchableStrings(StrippedLeaderboardDTO t) {
List<String> strings = new ArrayList<String>();
strings.add(t.name);
strings.add(t.displayName);
return strings;
}
};
leaderboardConfigControlsPanel.add(filterLeaderboardPanel);
leaderboardsPanel.add(leaderboardConfigControlsPanel);
ListHandler<StrippedLeaderboardDTO> leaderboardColumnListHandler = new ListHandler<StrippedLeaderboardDTO>(
leaderboardList.getList());
TextColumn<StrippedLeaderboardDTO> leaderboardNameColumn = new TextColumn<StrippedLeaderboardDTO>() {
@Override
public String getValue(StrippedLeaderboardDTO leaderboard) {
return leaderboard.name;
}
};
TextColumn<StrippedLeaderboardDTO> leaderboardDisplayNameColumn = new TextColumn<StrippedLeaderboardDTO>() {
@Override
public String getValue(StrippedLeaderboardDTO leaderboard) {
return leaderboard.getDisplayName() != null ? leaderboard.getDisplayName() : "";
}
};
ImagesBarColumn<StrippedLeaderboardDTO, RaceLogTrackingEventManagementImagesBarCell> leaderboardActionColumn =
new ImagesBarColumn<StrippedLeaderboardDTO, RaceLogTrackingEventManagementImagesBarCell>(
new RaceLogTrackingEventManagementImagesBarCell(stringMessages));
leaderboardActionColumn.setFieldUpdater(new FieldUpdater<StrippedLeaderboardDTO, String>() {
@Override
public void update(int index, StrippedLeaderboardDTO leaderboardDTO, String value) {
if (RaceLogTrackingEventManagementImagesBarCell.ACTION_ADD_RACELOG_TRACKERS.equals(value)) {
addRaceLogTrackers(leaderboardDTO);
} else if (RaceLogTrackingEventManagementImagesBarCell.ACTION_DENOTE_FOR_RACELOG_TRACKING.equals(value)) {
denoteForRaceLogTracking(leaderboardDTO);
}
}
});
leaderboardTable.addColumn(leaderboardNameColumn, stringMessages.name());
leaderboardTable.addColumn(leaderboardDisplayNameColumn, stringMessages.displayName());
leaderboardTable.addColumn(leaderboardActionColumn, stringMessages.actions());
leaderboardTable.addColumnSortHandler(leaderboardColumnListHandler);
leaderboardTable.setWidth("100%");
leaderboardSelectionModel = new MultiSelectionModel<StrippedLeaderboardDTO>();
leaderboardTable.setSelectionModel(leaderboardSelectionModel);
leaderboardSelectionModel.addSelectionChangeHandler(new SelectionChangeEvent.Handler() {
public void onSelectionChange(SelectionChangeEvent event) {
leaderboardSelectionChanged();
}
});
leaderboardList.addDataDisplay(leaderboardTable);
leaderboardsPanel.add(leaderboardTable);
HorizontalPanel leaderboardButtonPanel = new HorizontalPanel();
leaderboardButtonPanel.setSpacing(5);
leaderboardsPanel.add(leaderboardButtonPanel);
mainPanel.add(new Grid(1, 1));
// caption panels for the selected leaderboard and tracked races
HorizontalPanel splitPanel = new HorizontalPanel();
mainPanel.add(splitPanel);
selectedLeaderBoardPanel = new CaptionPanel(stringMessages.leaderboard());
selectedLeaderBoardPanel.setWidth("50%");
splitPanel.add(selectedLeaderBoardPanel);
VerticalPanel vPanel = new VerticalPanel();
vPanel.setWidth("100%");
selectedLeaderBoardPanel.setContentWidget(vPanel);
trackedRacesCaptionPanel = new CaptionPanel(stringMessages.trackedRaces());
trackedRacesCaptionPanel.setWidth("50%");
splitPanel.add(trackedRacesCaptionPanel);
VerticalPanel trackedRacesPanel = new VerticalPanel();
trackedRacesPanel.setWidth("100%");
trackedRacesCaptionPanel.setContentWidget(trackedRacesPanel);
trackedRacesCaptionPanel.setStyleName("bold");
// ------------ races of the selected leaderboard ----------------
TextColumn<RaceColumnDTOAndFleetDTOWithNameBasedEquality> raceNameColumn = new TextColumn<RaceColumnDTOAndFleetDTOWithNameBasedEquality>() {
@Override
public String getValue(RaceColumnDTOAndFleetDTOWithNameBasedEquality object) {
return object.getA().getName();
}
};
TextColumn<RaceColumnDTOAndFleetDTOWithNameBasedEquality> fleetNameColumn = new TextColumn<RaceColumnDTOAndFleetDTOWithNameBasedEquality>() {
@Override
public String getValue(RaceColumnDTOAndFleetDTOWithNameBasedEquality object) {
return object.getB().getName();
}
};
TextColumn<RaceColumnDTOAndFleetDTOWithNameBasedEquality> raceLogTrackingStateColumn = new TextColumn<RaceColumnDTOAndFleetDTOWithNameBasedEquality>() {
@Override
public String getValue(RaceColumnDTOAndFleetDTOWithNameBasedEquality raceColumnAndFleetName) {
RaceLogTrackingState state = raceColumnAndFleetName.getB().raceLogTrackingState;
if (raceColumnAndFleetName.getB().raceLogTrackerExists) {
if (state == RaceLogTrackingState.TRACKING) {
return "Tracking";
} else {
return "Tracker is listening";
}
} else if (raceColumnAndFleetName.getB().raceLogTrackingState.isForTracking()) {
return "Denoted";
} else {
return "Not denoted";
}
}
};
ImagesBarColumn<RaceColumnDTOAndFleetDTOWithNameBasedEquality, RaceLogTrackingEventManagementRaceImagesBarCell> raceActionColumn =
new ImagesBarColumn<RaceColumnDTOAndFleetDTOWithNameBasedEquality, RaceLogTrackingEventManagementRaceImagesBarCell>(
new RaceLogTrackingEventManagementRaceImagesBarCell(stringMessages));
raceActionColumn.setFieldUpdater(new FieldUpdater<RaceColumnDTOAndFleetDTOWithNameBasedEquality, String>() {
@Override
public void update(int index, RaceColumnDTOAndFleetDTOWithNameBasedEquality object, String value) {
if (RaceLogTrackingEventManagementRaceImagesBarCell.ACTION_ADD_RACELOG_TRACKER.equals(value)) {
addRaceLogTracker(object.getA(), object.getB());
} else if (RaceLogTrackingEventManagementRaceImagesBarCell.ACTION_DENOTE_FOR_RACELOG_TRACKING.equals(value)) {
denoteForRaceLogTracking(object.getA(), object.getB());
}
}
});
Label lblRaceNamesIn = new Label(stringMessages.races());
vPanel.add(lblRaceNamesIn);
raceColumnTable = new CellTable<RaceColumnDTOAndFleetDTOWithNameBasedEquality>(/* pageSize */200, tableRes);
raceColumnTable.ensureDebugId("RaceColumnTable");
raceColumnTable.addColumn(raceNameColumn, stringMessages.race());
raceColumnTable.addColumn(fleetNameColumn, stringMessages.fleet());
raceColumnTable.addColumn(raceLogTrackingStateColumn, stringMessages.status());
raceColumnTable.addColumn(raceActionColumn, stringMessages.actions());
raceColumnAndFleetList.addDataDisplay(raceColumnTable);
raceColumnTable.setWidth("500px");
raceColumnTableSelectionModel = new SingleSelectionModel<RaceColumnDTOAndFleetDTOWithNameBasedEquality>();
raceColumnTable.setSelectionModel(raceColumnTableSelectionModel);
vPanel.add(raceColumnTable);
HorizontalPanel selectedLeaderboardRaceButtonPanel = new HorizontalPanel();
selectedLeaderboardRaceButtonPanel.setSpacing(5);
vPanel.add(selectedLeaderboardRaceButtonPanel);
loadLeaderboards();
}
public void loadLeaderboards() {
sailingService.getLeaderboards(new AsyncCallback<List<StrippedLeaderboardDTO>>() {
@Override
public void onSuccess(List<StrippedLeaderboardDTO> leaderboards) {
leaderboardList.getList().clear();
availableLeaderboardList.clear();
for (StrippedLeaderboardDTO leaderboard : leaderboards) {
if (leaderboard.type == LeaderboardType.RegattaLeaderboard) {
leaderboardList.getList().add(leaderboard);
availableLeaderboardList.add(leaderboard);
}
}
filterLeaderboardPanel.updateAll(availableLeaderboardList);
leaderboardSelectionChanged();
}
@Override
public void onFailure(Throwable t) {
RaceLogTrackingEventManagementPanel.this.errorReporter.reportError("Error trying to obtain list of leaderboards: "
+ t.getMessage());
}
});
}
/**
* @param nameOfRaceColumnToSelect
* if not <code>null</code>, selects the first race column name with this name found in the leaderboard
* after the refresh has successfully completed. See {@link #selectRaceColumn(String)}.
*/
public void loadAndRefreshLeaderboard(final String leaderboardName, final String nameOfRaceColumnToSelect) {
sailingService.getLeaderboard(leaderboardName, new AsyncCallback<StrippedLeaderboardDTO>() {
@Override
public void onSuccess(StrippedLeaderboardDTO leaderboard) {
for (StrippedLeaderboardDTO leaderboardDTO : leaderboardSelectionModel.getSelectedSet()) {
if (leaderboardDTO.name.equals(leaderboardName)) {
leaderboardSelectionModel.setSelected(leaderboardDTO, false);
break;
}
}
replaceLeaderboardInList(leaderboardList.getList(), leaderboardName, leaderboard);
replaceLeaderboardInList(availableLeaderboardList, leaderboardName, leaderboard);
leaderboardSelectionModel.setSelected(leaderboard, true);
if (nameOfRaceColumnToSelect != null) {
selectRaceColumn(nameOfRaceColumnToSelect);
}
leaderboardSelectionChanged();
}
@Override
public void onFailure(Throwable t) {
RaceLogTrackingEventManagementPanel.this.errorReporter.reportError("Error trying to update leaderboard with name " + leaderboardName + " : "
+ t.getMessage());
}
});
}
private void replaceLeaderboardInList(List<StrippedLeaderboardDTO> leaderboardList, String leaderboardToReplace, StrippedLeaderboardDTO newLeaderboard) {
int index = -1;
for (StrippedLeaderboardDTO existingLeaderboard : leaderboardList) {
index++;
if (existingLeaderboard.name.equals(leaderboardToReplace)) {
break;
}
}
if (index >= 0) {
leaderboardList.set(index, newLeaderboard);
}
}
private void selectRaceColumn(String raceCoumnName) {
List<RaceColumnDTOAndFleetDTOWithNameBasedEquality> list = raceColumnAndFleetList.getList();
for (RaceColumnDTOAndFleetDTOWithNameBasedEquality pair : list) {
if (pair.getA().getName().equals(raceCoumnName)) {
raceColumnTableSelectionModel.setSelected(pair, true);
break;
}
}
}
private RaceColumnDTOAndFleetDTOWithNameBasedEquality getSelectedRaceColumnWithFleet() {
RaceColumnDTOAndFleetDTOWithNameBasedEquality raceInLeaderboardAndFleetName = raceColumnTableSelectionModel.getSelectedObject();
return raceInLeaderboardAndFleetName;
}
private void leaderboardSelectionChanged() {
StrippedLeaderboardDTO selectedLeaderboard = getSelectedLeaderboard();
if (leaderboardSelectionModel.getSelectedSet().size() == 1 && selectedLeaderboard != null) {
raceColumnAndFleetList.getList().clear();
for (RaceColumnDTO raceColumn : selectedLeaderboard.getRaceList()) {
for (FleetDTO fleet : raceColumn.getFleets()) {
raceColumnAndFleetList.getList().add(new RaceColumnDTOAndFleetDTOWithNameBasedEquality(raceColumn, fleet));
}
}
selectedLeaderBoardPanel.setVisible(true);
selectedLeaderBoardPanel.setCaptionText("Details of leaderboard '" + selectedLeaderboard.name + "'");
if (!selectedLeaderboard.type.isMetaLeaderboard()) {
trackedRacesCaptionPanel.setVisible(true);
}
} else {
selectedLeaderBoardPanel.setVisible(false);
trackedRacesCaptionPanel.setVisible(false);
}
}
private StrippedLeaderboardDTO getSelectedLeaderboard() {
return leaderboardSelectionModel.getSelectedSet().isEmpty() ? null : leaderboardSelectionModel.getSelectedSet().iterator().next();
}
private void denoteForRaceLogTracking(final StrippedLeaderboardDTO leaderboard) {
sailingService.denoteForRaceLogTracking(leaderboard.name, new AsyncCallback<Void>() {
@Override
public void onSuccess(Void result) {
loadAndRefreshLeaderboard(leaderboard.name, null);
}
@Override
public void onFailure(Throwable caught) {
errorReporter.reportError("Could not denote for RaceLog tracking: " + caught.getMessage());
}
});
}
private void denoteForRaceLogTracking(final RaceColumnDTO raceColumn, final FleetDTO fleet) {
final StrippedLeaderboardDTO leaderboard = getSelectedLeaderboard();
sailingService.denoteForRaceLogTracking(leaderboard.name, raceColumn.getName(), fleet.getName(), new AsyncCallback<Void>() {
@Override
public void onSuccess(Void result) {
loadAndRefreshLeaderboard(leaderboard.name, raceColumn.getName());
}
@Override
public void onFailure(Throwable caught) {
errorReporter.reportError("Could not denote for RaceLog tracking: " + caught.getMessage());
}
});
}
private void addRaceLogTrackers(final StrippedLeaderboardDTO leaderboard) {
final RaceColumnDTOAndFleetDTOWithNameBasedEquality selectedRCFleet = getSelectedRaceColumnWithFleet();
if (leaderboard.raceLogTrackersCanBeAdded) {
sailingService.addRaceLogTrackers(leaderboard.name, new AsyncCallback<Void>() {
@Override
public void onSuccess(Void result) {
loadAndRefreshLeaderboard(leaderboard.name, selectedRCFleet.getA().getName());
}
@Override
public void onFailure(Throwable caught) {
errorReporter.reportError("Failed to add RaceLog tracker: " + caught.getMessage());
}
});
} else {
errorReporter.reportError("No RaceLogTracker can be added for any of the RaceLogs in this leaderboard");
}
}
private void addRaceLogTracker(final RaceColumnDTO raceColumn, FleetDTO fleet) {
if (fleet.raceLogTrackerCanBeAdded) {
final StrippedLeaderboardDTO leaderboard = getSelectedLeaderboard();
sailingService.addRaceLogTracker(leaderboard.name, raceColumn.getName(), fleet.getName(), new AsyncCallback<Void>() {
@Override
public void onSuccess(Void result) {
loadAndRefreshLeaderboard(leaderboard.name, raceColumn.getName());
}
@Override
public void onFailure(Throwable caught) {
errorReporter.reportError("Failed to add RaceLog trackers: " + caught.getMessage());
}
});
} else {
errorReporter.reportError("No RaceLogTracker can be added for the RaceLog of this fleet");
}
}
}
@@ -0,0 +1,35 @@
package com.sap.sailing.gwt.ui.adminconsole;
import java.util.ArrayList;
import java.util.List;
import com.google.gwt.core.client.GWT;
import com.sap.sailing.gwt.ui.adminconsole.LeaderboardConfigPanel.RaceColumnDTOAndFleetDTOWithNameBasedEquality;
import com.sap.sailing.gwt.ui.client.StringMessages;
import com.sap.sailing.gwt.ui.client.shared.components.ImagesBarCell;
public class RaceLogTrackingEventManagementRaceImagesBarCell extends ImagesBarCell {
public final static String ACTION_ADD_RACELOG_TRACKER = "ACTION_ADD_RACELOG_TRACKER";
public final static String ACTION_DENOTE_FOR_RACELOG_TRACKING = "ACTION_DENOTE_FOR_RACELOG_TRACKING";
private final StringMessages stringMessages;
private static AdminConsoleResources resources = GWT.create(AdminConsoleResources.class);
public RaceLogTrackingEventManagementRaceImagesBarCell(StringMessages stringConstants) {
super();
this.stringMessages = stringConstants;
}
@Override
protected Iterable<ImageSpec> getImageSpecs() {
List<ImageSpec> result = new ArrayList<ImageSpec>();
RaceColumnDTOAndFleetDTOWithNameBasedEquality object = (RaceColumnDTOAndFleetDTOWithNameBasedEquality) getContext().getKey();
if (object.getB().raceLogTrackerCanBeAdded) {
result.add(new ImageSpec(ACTION_ADD_RACELOG_TRACKER, stringMessages.addRaceLogTracker(), makeImagePrototype(resources.addRaceLogTracker())));
}
if (! object.getB().raceLogTrackingState.isForTracking()) {
result.add(new ImageSpec(ACTION_DENOTE_FOR_RACELOG_TRACKING, stringMessages.denoteForRaceLogTracking(), makeImagePrototype(resources.denoteForRaceLogTracking())));
}
return result;
}
}
@@ -383,4 +383,6 @@ public interface SailingService extends RemoteService {
void addRaceLogTracker(String leaderboardName, String raceColumnName, String fleetName) throws Exception, RaceNotCreatedException;
void denoteForRaceLogTracking(String leaderboardName, String raceColumnName, String fleetName) throws Exception;
void denoteForRaceLogTracking(String leaderboardName) throws Exception;
}
@@ -523,5 +523,7 @@ public interface SailingServiceAsync {
void denoteForRaceLogTracking(String leaderboardName,
String raceColumnName, String fleetName,
AsyncCallback<Void> callback);
void denoteForRaceLogTracking(String leaderboardName, AsyncCallback<Void> callback);
}
@@ -960,7 +960,7 @@ public interface StringMessages extends Messages {
String hasSplitFleetContiguousScoring();
String eventOverview();
String addRaceLogTracker();
String addRaceLogTrackers();
String denoteForRaceLogTracking();
String raceLogTrackerExists();
String raceLogTrackingState();
String raceLogTracking();
}
@@ -949,6 +949,6 @@ releaseNotes=News and Release History
hasSplitFleetContiguousScoring=Split fleets scored contiguously
eventOverview=Event Overview
addRaceLogTracker=Add RaceLog Tracker
addRaceLogTrackers=Add RaceLog Trackers
denoteForRaceLogTracking=Denote for RaceLog tracking
raceLogTrackerExists=RL-Tracker exists
raceLogTrackingState=RL tracking state
raceLogTracking=RaceLog Tracking
@@ -945,6 +945,6 @@ releaseNotes=Neuigkeiten und Änderungshistorie
hasSplitFleetContiguousScoring=Gruppen durchgängig bepunkten
eventOverview=Event Übersicht
addRaceLogTracker=RaceLog Tracker hinzufügen
denoteForRaceLogTracking=Kennzeichnen für RaceLog-Tracking
raceLogTrackerExists=RL-Tracker vorhanden
raceLogTrackingState=RL Tracking Status
addRaceLogTrackers=RaceLog Tracker hinzufügen
denoteForRaceLogTracking=Für RaceLog Tracking markieren
raceLogTracking=RaceLog Tracking
@@ -31,6 +31,8 @@ public abstract class ImagesBarCell extends AbstractSafeHtmlCell<String> {
*/
private final static ImagesBarTemplates imageTemplate = GWT.create(ImagesBarTemplates.class);
private Context context;
protected class ImageSpec {
private final AbstractImagePrototype imagePrototype;
private final String actionName;
@@ -138,9 +140,15 @@ public abstract class ImagesBarCell extends AbstractSafeHtmlCell<String> {
}
protected abstract Iterable<ImageSpec> getImageSpecs();
protected Context getContext() {
return context;
}
@Override
protected void render(com.google.gwt.cell.client.Cell.Context context, SafeHtml data, SafeHtmlBuilder sb) {
this.context = context;
/*
* Always do a null check on the value. Cell widgets can pass null to
* cells if the underlying data contains a null, or if the data arrives
@@ -1973,7 +1973,8 @@ public class SailingServiceImpl extends ProxiedRemoteServiceServlet implements S
} else {
leaderboardDTO.discardThresholds = null;
}
leaderboardDTO.raceLogTrackedRacesCouldBeAdded = false;
leaderboardDTO.isDenotedForRaceLogTracking = false;
leaderboardDTO.raceLogTrackersCanBeAdded = false;
for (RaceColumn raceColumn : leaderboard.getRaceColumns()) {
for (Fleet fleet : raceColumn.getFleets()) {
RaceDTO raceDTO = null;
@@ -1992,11 +1993,15 @@ public class SailingServiceImpl extends ProxiedRemoteServiceServlet implements S
RaceLog raceLog = raceColumn.getRaceLog(fleet);
fleetDTO.raceLogTrackingState = new RaceLogTrackingStateAnalyzer(raceLog).analyze();
fleetDTO.raceLogTrackerForRaceExists = getService().getRaceTrackerById(raceLog.getId()) != null;
fleetDTO.raceLogTrackerExists = getService().getRaceTrackerById(raceLog.getId()) != null;
if (getRaceLogTrackingAdapter().canRaceBeAdded(getService(), raceColumn, fleet)) {
leaderboardDTO.raceLogTrackedRacesCouldBeAdded = true;
fleetDTO.raceLogTrackedRaceCouldBeAdded = true;
if (getRaceLogTrackingAdapter().isDenotedForRaceLogTracking(getService(), raceColumn, fleet)) {
leaderboardDTO.isDenotedForRaceLogTracking = true;
}
if (getRaceLogTrackingAdapter().canRaceLogTrackerBeAdded(getService(), raceColumn, fleet)) {
leaderboardDTO.raceLogTrackersCanBeAdded = true;
fleetDTO.raceLogTrackerCanBeAdded = true;
}
}
}
@@ -3840,7 +3845,7 @@ public class SailingServiceImpl extends ProxiedRemoteServiceServlet implements S
Leaderboard leaderboard = getService().getLeaderboardByName(leaderboardName);
RaceLogTrackingAdapter adapter = getRaceLogTrackingAdapter();
Map<RaceColumn, Collection<Fleet>> canBeLoaded = adapter.listRacesThatCanBeAdded(getService(), leaderboard);
Map<RaceColumn, Collection<Fleet>> canBeLoaded = adapter.listRaceLogTrackersThatCanBeAdded(getService(), leaderboard);
for (RaceColumn raceColumn : canBeLoaded.keySet()) {
if (canBeLoaded.get(raceColumn) != null) {
for (Fleet fleet : canBeLoaded.get(raceColumn)) {
@@ -3859,4 +3864,10 @@ public class SailingServiceImpl extends ProxiedRemoteServiceServlet implements S
getRaceLogTrackingAdapter().denoteForRaceLogTracking(getService(), leaderboard, raceColumn, fleet, null);
}
@Override
public void denoteForRaceLogTracking(String leaderboardName) throws Exception {
Leaderboard leaderboard = getService().getLeaderboardByName(leaderboardName);
getRaceLogTrackingAdapter().denoteForRaceLogTracking(getService(), leaderboard);
}
}
Binary file not shown.

Before

Width:  |  Height:  |  Size: 499 B

After

Width:  |  Height:  |  Size: 428 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.0 KiB

After

Width:  |  Height:  |  Size: 417 B