From c16f2c07efd9f2157cd8a126124441f3ccfc55fc Mon Sep 17 00:00:00 2001 From: Lukas Niemeier Date: Fri, 6 Dec 2013 17:57:05 +0100 Subject: [PATCH 01/20] # removed synchronize (not needed) --- .../sailing/server/impl/RacingEventServiceImpl.java | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/java/com.sap.sailing.server/src/com/sap/sailing/server/impl/RacingEventServiceImpl.java b/java/com.sap.sailing.server/src/com/sap/sailing/server/impl/RacingEventServiceImpl.java index d8d5767c021..bf98891594a 100755 --- a/java/com.sap.sailing.server/src/com/sap/sailing/server/impl/RacingEventServiceImpl.java +++ b/java/com.sap.sailing.server/src/com/sap/sailing/server/impl/RacingEventServiceImpl.java @@ -1219,14 +1219,12 @@ public class RacingEventServiceImpl implements RacingEventService, RegattaListen RegattaConfiguration newRegattaConfiguration) { // We're not doing any renaming of the regatta itself, therefore we don't have to sync on the maps. Regatta regatta = getRegatta(regattaIdentifier); - synchronized (regatta) { - CourseArea newCourseArea = getCourseArea(newDefaultCourseAreaId); - if (newCourseArea != regatta.getDefaultCourseArea()) { - regatta.setDefaultCourseArea(newCourseArea); - } - regatta.setRegattaConfiguration(newRegattaConfiguration); - mongoObjectFactory.storeRegatta(regatta); + CourseArea newCourseArea = getCourseArea(newDefaultCourseAreaId); + if (newCourseArea != regatta.getDefaultCourseArea()) { + regatta.setDefaultCourseArea(newCourseArea); } + regatta.setRegattaConfiguration(newRegattaConfiguration); + mongoObjectFactory.storeRegatta(regatta); return regatta; } From fedaf0677108e718460fa1de4dfba2f5cccd08fe Mon Sep 17 00:00:00 2001 From: Lukas Niemeier Date: Fri, 6 Dec 2013 18:18:51 +0100 Subject: [PATCH 02/20] # comments --- .../impl/DynamicTrackedRaceLogListener.java | 18 +++++------------- .../gwt/ui/client/SailingServiceAsync.java | 8 ++++++++ .../gwt/ui/shared/RaceLogSetStartTimeDTO.java | 3 +++ .../sap/sailing/gwt/ui/AdminConsole.gwt.xml | 1 + .../sap/sailing/server/RacingEventService.java | 2 +- .../server/impl/RacingEventServiceImpl.java | 4 ++++ 6 files changed, 22 insertions(+), 14 deletions(-) diff --git a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/impl/DynamicTrackedRaceLogListener.java b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/impl/DynamicTrackedRaceLogListener.java index d36592b10cf..5c30ce5cd8f 100644 --- a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/impl/DynamicTrackedRaceLogListener.java +++ b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/impl/DynamicTrackedRaceLogListener.java @@ -7,10 +7,10 @@ import com.sap.sailing.domain.common.TimePoint; import com.sap.sailing.domain.common.WindSource; import com.sap.sailing.domain.common.WindSourceType; import com.sap.sailing.domain.common.impl.WindSourceImpl; +import com.sap.sailing.domain.common.racelog.RaceLogRaceStatus; import com.sap.sailing.domain.racelog.RaceLog; import com.sap.sailing.domain.racelog.RaceLogCourseDesignChangedEvent; import com.sap.sailing.domain.racelog.RaceLogPassChangeEvent; -import com.sap.sailing.domain.racelog.RaceLogRaceStatusEvent; import com.sap.sailing.domain.racelog.RaceLogStartTimeEvent; import com.sap.sailing.domain.racelog.RaceLogWindFixEvent; import com.sap.sailing.domain.racelog.analyzing.impl.LastPublishedCourseDesignFinder; @@ -20,6 +20,10 @@ import com.sap.sailing.domain.racelog.impl.BaseRaceLogEventVisitor; import com.sap.sailing.domain.tracking.DynamicTrackedRace; import com.sap.sailing.domain.tracking.Wind; +/** + * TODO: this class could be a good place to leverage more information about a race containing in the {@link RaceLog}. + * This includes for example the {@link RaceLogRaceStatus} indicating the current race's start. + */ public class DynamicTrackedRaceLogListener extends BaseRaceLogEventVisitor { private static final Logger logger = Logger.getLogger(DynamicTrackedRaceLogListener.class.getName()); @@ -83,16 +87,9 @@ public class DynamicTrackedRaceLogListener extends BaseRaceLogEventVisitor { } private void analyze() { - analyzeStatus(); analyzeCourseDesign(null); } - private void analyzeStatus() { - /* RaceLogRaceStatus newStatus = statusAnalyzer.analyze();*/ - - // TODO: What can we do with the status? Should we use DynamicTrackedRace.setStatus? - } - private void analyzeCourseDesign(CourseBase courseBaseProvidedByEvent) { CourseBase courseDesign = courseDesignFinder.analyze(); if (courseDesign == null) { @@ -138,11 +135,6 @@ public class DynamicTrackedRaceLogListener extends BaseRaceLogEventVisitor { analyzeStartTime(event.getStartTime()); } - @Override - public void visit(RaceLogRaceStatusEvent event) { - analyzeStatus(); - } - @Override public void visit(RaceLogCourseDesignChangedEvent event) { analyzeCourseDesign(event.getCourseDesign()); diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/SailingServiceAsync.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/SailingServiceAsync.java index 4e4917d1158..d19fab0e55c 100755 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/SailingServiceAsync.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/SailingServiceAsync.java @@ -472,8 +472,16 @@ public interface SailingServiceAsync { void removeDeviceConfiguration(DeviceConfigurationMatcherType type, List clientIds, AsyncCallback asyncCallback); + /** + * Sets the a new start time. + * @param dto {@link RaceLogSetStartTimeDTO} identifying the race to set the start time on and the new start time. + */ void setStartTime(RaceLogSetStartTimeDTO dto, AsyncCallback callback); + /** + * Gets the race's current start time and current pass identifier. If no start time is set, the pass identifier will + * still be returned, but the start time field will be null. + */ void getStartTime(String leaderboardName, String raceColumnName, String fleetName, AsyncCallback> callback); diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/RaceLogSetStartTimeDTO.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/RaceLogSetStartTimeDTO.java index 20b322ba36a..f36e0fff45f 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/RaceLogSetStartTimeDTO.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/RaceLogSetStartTimeDTO.java @@ -4,6 +4,9 @@ import java.util.Date; import com.google.gwt.user.client.rpc.IsSerializable; +/** + * DTO holding all information to set a new start time on a specific race. + */ public class RaceLogSetStartTimeDTO implements IsSerializable { public String leaderboardName; public String raceColumnName; diff --git a/java/com.sap.sailing.gwt.ui/src/main/resources/com/sap/sailing/gwt/ui/AdminConsole.gwt.xml b/java/com.sap.sailing.gwt.ui/src/main/resources/com/sap/sailing/gwt/ui/AdminConsole.gwt.xml index 26c525dceb9..e64a6c0eae0 100755 --- a/java/com.sap.sailing.gwt.ui/src/main/resources/com/sap/sailing/gwt/ui/AdminConsole.gwt.xml +++ b/java/com.sap.sailing.gwt.ui/src/main/resources/com/sap/sailing/gwt/ui/AdminConsole.gwt.xml @@ -28,6 +28,7 @@ + diff --git a/java/com.sap.sailing.server/src/com/sap/sailing/server/RacingEventService.java b/java/com.sap.sailing.server/src/com/sap/sailing/server/RacingEventService.java index a54d3083b2f..e1a97141b8f 100755 --- a/java/com.sap.sailing.server/src/com/sap/sailing/server/RacingEventService.java +++ b/java/com.sap.sailing.server/src/com/sap/sailing/server/RacingEventService.java @@ -474,7 +474,7 @@ public interface RacingEventService extends TrackedRegattaRegistry, RegattaFetch int authorPriority, int passId, TimePoint logicalTimePoint, TimePoint startTime); /** - * Gets the start time and pass identifier for the queried race. + * Gets the start time and pass identifier for the queried race. Start time might be null. */ Pair getStartTime(String leaderboardName, String raceColumnName, String fleetName); diff --git a/java/com.sap.sailing.server/src/com/sap/sailing/server/impl/RacingEventServiceImpl.java b/java/com.sap.sailing.server/src/com/sap/sailing/server/impl/RacingEventServiceImpl.java index bf98891594a..7823bc05873 100755 --- a/java/com.sap.sailing.server/src/com/sap/sailing/server/impl/RacingEventServiceImpl.java +++ b/java/com.sap.sailing.server/src/com/sap/sailing/server/impl/RacingEventServiceImpl.java @@ -218,6 +218,10 @@ public class RacingEventServiceImpl implements RacingEventService, RegattaListen private final MediaLibrary mediaLibrary; + /** + * Currently valid pairs of {@link DeviceConfigurationMatcher}s and {@link DeviceConfiguration}s. + * The contents of this map is persisted and replicated. See {@link DeviceConfigurationMapImpl}. + */ protected final DeviceConfigurationMapImpl configurationMap; private final WindStore windStore; From 266594ec30c6fdbd16a15059b45cbe8f4d376949 Mon Sep 17 00:00:00 2001 From: Lukas Niemeier Date: Fri, 6 Dec 2013 18:55:40 +0100 Subject: [PATCH 03/20] # clarified comment --- .../src/com/sap/sailing/server/RacingEventService.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/java/com.sap.sailing.server/src/com/sap/sailing/server/RacingEventService.java b/java/com.sap.sailing.server/src/com/sap/sailing/server/RacingEventService.java index e1a97141b8f..f40bad760e9 100755 --- a/java/com.sap.sailing.server/src/com/sap/sailing/server/RacingEventService.java +++ b/java/com.sap.sailing.server/src/com/sap/sailing/server/RacingEventService.java @@ -459,7 +459,7 @@ public interface RacingEventService extends TrackedRegattaRegistry, RegattaFetch Map getAllDeviceConfigurations(); /** - * Sets a new start time on the RaceLog identified by the passed parameters. + * Forces a new start time on the RaceLog identified by the passed parameters. * @param leaderboardName name of the RaceLog's leaderboard. * @param raceColumnName name of the RaceLog's column * @param fleetName name of the RaceLog's fleet From 0efcd2dec9834c63f096432cb64d81a3ba022fc7 Mon Sep 17 00:00:00 2001 From: Lukas Niemeier Date: Fri, 6 Dec 2013 23:07:03 +0100 Subject: [PATCH 04/20] better comment --- .../src/com/sap/sailing/domain/common/impl/QRCodeUtils.java | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/impl/QRCodeUtils.java b/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/impl/QRCodeUtils.java index 098537261a1..551aab07d1e 100644 --- a/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/impl/QRCodeUtils.java +++ b/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/impl/QRCodeUtils.java @@ -1,7 +1,13 @@ package com.sap.sailing.domain.common.impl; +import java.net.URLEncoder; + import com.sap.sailing.domain.common.impl.Util.Pair; +/** + * This class is used by our backend, in GWT-client code and by the Android app. Therefore we cannot use classes like + * {@link URLEncoder} to help us with the encoding. + */ public class QRCodeUtils { private static final String fragmentKey = "identifier"; From 152941ff7241451cf9c6d91a04e3762bb4deac7e Mon Sep 17 00:00:00 2001 From: Lukas Niemeier Date: Fri, 6 Dec 2013 23:10:35 +0100 Subject: [PATCH 05/20] added emulated java.util.UUID implementation to be used in gwt client code. implementation is excluded from eclipse build because package definition not compatible with eclipse. dev mode does not use this class! --- java/com.sap.sailing.gwt.ui/.classpath | 2 +- .../java/util/UUID_CustomFieldSerializer.java | 53 ++++++++++++++ .../sailing/gwt/ui/jre/java/util/UUID.java | 70 +++++++++++++++++++ 3 files changed, 124 insertions(+), 1 deletion(-) create mode 100644 java/com.sap.sailing.gwt.ui/src/main/java/com/google/gwt/user/client/rpc/core/java/util/UUID_CustomFieldSerializer.java create mode 100644 java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/jre/java/util/UUID.java diff --git a/java/com.sap.sailing.gwt.ui/.classpath b/java/com.sap.sailing.gwt.ui/.classpath index 43b189330c4..da2edd420c3 100755 --- a/java/com.sap.sailing.gwt.ui/.classpath +++ b/java/com.sap.sailing.gwt.ui/.classpath @@ -3,7 +3,7 @@ - + diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/google/gwt/user/client/rpc/core/java/util/UUID_CustomFieldSerializer.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/google/gwt/user/client/rpc/core/java/util/UUID_CustomFieldSerializer.java new file mode 100644 index 00000000000..baf58bfff0c --- /dev/null +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/google/gwt/user/client/rpc/core/java/util/UUID_CustomFieldSerializer.java @@ -0,0 +1,53 @@ +package com.google.gwt.user.client.rpc.core.java.util; + +import com.google.gwt.user.client.rpc.CustomFieldSerializer; +import com.google.gwt.user.client.rpc.SerializationException; +import com.google.gwt.user.client.rpc.SerializationStreamReader; +import com.google.gwt.user.client.rpc.SerializationStreamWriter; +import java.util.UUID; + +/** + * Serializer for emulated {@link UUID}. + */ +public class UUID_CustomFieldSerializer extends CustomFieldSerializer { + + public static void serialize(SerializationStreamWriter streamWriter, UUID instance) throws SerializationException { + streamWriter.writeString(instance.toString()); + } + + public static UUID instantiate(SerializationStreamReader streamReader) throws SerializationException { + return UUID.fromString(streamReader.readString()); + } + + + public static boolean hasCustomInstantiate() { + return true; + } + + public static void deserialize(SerializationStreamReader streamReader, UUID instance) + throws SerializationException { + // no operation + } + + @Override + public void serializeInstance(SerializationStreamWriter streamWriter, UUID instance) throws SerializationException { + serialize(streamWriter, instance); + } + + @Override + public UUID instantiateInstance(SerializationStreamReader streamReader) throws SerializationException { + return instantiate(streamReader); + } + + @Override + public boolean hasCustomInstantiateInstance() { + return hasCustomInstantiate(); + } + + @Override + public void deserializeInstance(SerializationStreamReader streamReader, UUID instance) + throws SerializationException { + deserialize(streamReader, instance); + } + +} diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/jre/java/util/UUID.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/jre/java/util/UUID.java new file mode 100644 index 00000000000..9796283cead --- /dev/null +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/jre/java/util/UUID.java @@ -0,0 +1,70 @@ +package java.util; + +import java.io.Serializable; + +/** + *

Do not use!

+ * + *

Emulated version of {@link java.util.UUID}. Use {@link java.util.UUID} instead!

+ */ +public class UUID implements Serializable, Comparable { + + private static final long serialVersionUID = -3096287568577694784L; + + public static UUID fromString(String value) { + return new UUID(value); + } + + public static UUID randomUUID() { + throw new UnsupportedOperationException("Not supported for emulation"); + } + + private String uuidAsString; + + @SuppressWarnings("unused") + private UUID() { /* gwt */ + this.uuidAsString = null; + } + + protected UUID(String value) { + this.uuidAsString = value; + } + + /** + * @throws UnsupportedOperationException + */ + public UUID(long mostSigBits, long leastSigBits) { + throw new UnsupportedOperationException("Not supported for emulation"); + } + + @Override + public int compareTo(UUID o) { + return uuidAsString.compareTo(o.uuidAsString); + } + + @Override + public int hashCode() { + return uuidAsString.hashCode(); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + UUID other = (UUID) obj; + if (uuidAsString == null) { + if (other.uuidAsString != null) + return false; + } else if (!uuidAsString.equals(other.uuidAsString)) + return false; + return true; + } + + @Override + public String toString() { + return uuidAsString; + } + +} From 009a7ce32f9ef9380d71f28faefa899858192cf7 Mon Sep 17 00:00:00 2001 From: Lukas Niemeier Date: Sat, 7 Dec 2013 00:55:26 +0100 Subject: [PATCH 06/20] # using UUID in for RegattaDTO, CourseAreaDTO, AbstractLeaderboardDTO, LeaderboardDescriptor --- .../common/dto/AbstractLeaderboardDTO.java | 3 +- .../common/dto/IncrementalLeaderboardDTO.java | 6 +- java/com.sap.sailing.gwt.ui/pom.xml | 1 + .../gwt/ui/adminconsole/EventDialog.java | 3 +- .../FlexibleLeaderboardDialog.java | 4 +- .../FlexibleLeaderboardEditDialog.java | 4 +- .../adminconsole/LeaderboardConfigPanel.java | 10 +- .../adminconsole/LeaderboardDescriptor.java | 20 +-- .../adminconsole/RegattaDetailsComposite.java | 2 +- .../ui/adminconsole/RegattaListComposite.java | 2 +- .../RegattaStructureManagementPanel.java | 2 +- .../RegattaWithSeriesAndFleetsDialog.java | 13 +- .../SailingEventManagementPanel.java | 3 +- .../sailing/gwt/ui/client/SailingService.java | 30 ++--- .../gwt/ui/client/SailingServiceAsync.java | 28 ++-- .../RegattaOverviewEntryPoint.java | 25 ++-- .../regattaoverview/RegattaOverviewPanel.java | 17 +-- .../RegattaRaceStatesComponent.java | 19 +-- .../RegattaRaceStatesSettings.java | 9 +- ...attaRaceStatesSettingsDialogComponent.java | 25 ++-- ...ttaRaceStatesSettingsJsonDeSerializer.java | 7 +- .../gwt/ui/server/SailingServiceImpl.java | 82 ++++------- .../sailing/gwt/ui/shared/CourseAreaDTO.java | 4 +- .../sap/sailing/gwt/ui/shared/EventDTO.java | 3 +- .../sap/sailing/gwt/ui/shared/RegattaDTO.java | 3 +- .../sap/sailing/gwt/ui/AdminConsole.gwt.xml | 127 +++++++++--------- .../sap/sailing/gwt/ui/EmulatedJRE.gwt.xml | 12 ++ .../sap/sailing/gwt/ui/Leaderboard.gwt.xml | 77 +++++------ .../sailing/gwt/ui/LeaderboardEditing.gwt.xml | 77 +++++------ .../sap/sailing/gwt/ui/PolarSheets.gwt.xml | 63 ++++----- .../com/sap/sailing/gwt/ui/RaceBoard.gwt.xml | 87 ++++++------ .../sailing/gwt/ui/RegattaOverview.gwt.xml | 101 +++++++------- .../com/sap/sailing/gwt/ui/Simulator.gwt.xml | 95 ++++++------- .../com/sap/sailing/gwt/ui/Spectator.gwt.xml | 71 +++++----- .../com/sap/sailing/gwt/ui/TvView.gwt.xml | 85 ++++++------ .../sap/sailing/gwt/ui/UserManagement.gwt.xml | 69 +++++----- .../com/sap/sailing/gwt/ui/VideoPopup.gwt.xml | 29 ++-- .../sap/sailing/gwt/ui/YoutubePopup.gwt.xml | 1 + 38 files changed, 620 insertions(+), 599 deletions(-) create mode 100644 java/com.sap.sailing.gwt.ui/src/main/resources/com/sap/sailing/gwt/ui/EmulatedJRE.gwt.xml diff --git a/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/dto/AbstractLeaderboardDTO.java b/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/dto/AbstractLeaderboardDTO.java index 2588dcba482..d60d94ac02b 100755 --- a/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/dto/AbstractLeaderboardDTO.java +++ b/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/dto/AbstractLeaderboardDTO.java @@ -8,6 +8,7 @@ import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; +import java.util.UUID; import com.sap.sailing.domain.common.LeaderboardType; import com.sap.sailing.domain.common.RegattaAndRaceIdentifier; @@ -26,7 +27,7 @@ public abstract class AbstractLeaderboardDTO implements Serializable { public int[] discardThresholds; public String regattaName; public String displayName; - public String defaultCourseAreaIdAsString; + public UUID defaultCourseAreaId; public String defaultCourseAreaName; public ScoringSchemeType scoringScheme; public LeaderboardType type; diff --git a/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/dto/IncrementalLeaderboardDTO.java b/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/dto/IncrementalLeaderboardDTO.java index f8b98165d90..47f9e831eea 100755 --- a/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/dto/IncrementalLeaderboardDTO.java +++ b/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/dto/IncrementalLeaderboardDTO.java @@ -338,7 +338,7 @@ public class IncrementalLeaderboardDTO extends LeaderboardDTO implements Increme this.setComment(previousVersion.getComment()); } if (this.defaultCourseAreaIdAsStringUnchanged) { - this.defaultCourseAreaIdAsString = previousVersion.defaultCourseAreaIdAsString; + this.defaultCourseAreaId = previousVersion.defaultCourseAreaId; } if (this.defaultCourseAreaNameUnchanged) { this.defaultCourseAreaName = previousVersion.defaultCourseAreaName; @@ -497,8 +497,8 @@ public class IncrementalLeaderboardDTO extends LeaderboardDTO implements Increme this.displayName = null; this.displayNameUnchanged = true; } - if (Util.equalsWithNull(this.defaultCourseAreaIdAsString, previousVersion.defaultCourseAreaIdAsString)) { - this.defaultCourseAreaIdAsString = null; + if (Util.equalsWithNull(this.defaultCourseAreaId, previousVersion.defaultCourseAreaId)) { + this.defaultCourseAreaId = null; this.defaultCourseAreaIdAsStringUnchanged = true; } if (Util.equalsWithNull(this.defaultCourseAreaName, previousVersion.defaultCourseAreaName)) { diff --git a/java/com.sap.sailing.gwt.ui/pom.xml b/java/com.sap.sailing.gwt.ui/pom.xml index 36490d9ca81..8cc591613c9 100644 --- a/java/com.sap.sailing.gwt.ui/pom.xml +++ b/java/com.sap.sailing.gwt.ui/pom.xml @@ -69,6 +69,7 @@ -Dgwt.persistentunitcache=false chrome + com.sap.sailing.gwt.ui.EmulatedJRE com.sap.sailing.gwt.ui.AdminConsole com.sap.sailing.gwt.ui.Leaderboard com.sap.sailing.gwt.ui.LeaderboardEditing diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/EventDialog.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/EventDialog.java index cc72aef090e..6ca4ed9536c 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/EventDialog.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/EventDialog.java @@ -3,6 +3,7 @@ package com.sap.sailing.gwt.ui.adminconsole; import java.util.ArrayList; import java.util.Collection; import java.util.List; +import java.util.UUID; import com.google.gwt.event.dom.client.ClickEvent; import com.google.gwt.event.dom.client.ClickHandler; @@ -25,7 +26,7 @@ public class EventDialog extends DataEntryDialog { protected TextBox venueEntryField; protected TextBox publicationUrlEntryField; protected CheckBox isPublicCheckBox; - protected String id; + protected UUID id; protected List courseAreaNameEntryFields; private EventDTO event; diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/FlexibleLeaderboardDialog.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/FlexibleLeaderboardDialog.java index f8e3610d6fc..2bcd87716fe 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/FlexibleLeaderboardDialog.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/FlexibleLeaderboardDialog.java @@ -78,9 +78,9 @@ public abstract class FlexibleLeaderboardDialog extends AbstractLeaderboardDialo private void setCourseAreaInDescriptor(LeaderboardDescriptor leaderboard) { CourseAreaDTO courseArea = getSelectedCourseArea(); if (courseArea == null) { - leaderboard.setCourseAreaIdAsString(null); + leaderboard.setCourseAreaId(null); } else { - leaderboard.setCourseAreaIdAsString(getSelectedCourseArea().uuidAsString); + leaderboard.setCourseAreaId(getSelectedCourseArea().id); } } diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/FlexibleLeaderboardEditDialog.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/FlexibleLeaderboardEditDialog.java index 58c2efd007e..995558c443a 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/FlexibleLeaderboardEditDialog.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/FlexibleLeaderboardEditDialog.java @@ -38,7 +38,7 @@ public class FlexibleLeaderboardEditDialog extends FlexibleLeaderboardDialog { sailingEventsListBox = createSailingEventListBox(); for (EventDTO event : existingEvents) { for (CourseAreaDTO courseArea : event.venue.getCourseAreas()) { - if (courseArea.uuidAsString.equals(leaderboard.getCourseAreaIdAsString())) { + if (courseArea.id.equals(leaderboard.getCourseAreaId())) { int index = existingEvents.indexOf(event) + 1; // + 1 because of the "Please select... item" sailingEventsListBox.setSelectedIndex(index); onEventSelectionChanged(); @@ -50,4 +50,4 @@ public class FlexibleLeaderboardEditDialog extends FlexibleLeaderboardDialog { } discardThresholdBoxes = new DiscardThresholdBoxes(this, leaderboard.getDiscardThresholds(), stringMessages); } -} +} \ No newline at end of file diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/LeaderboardConfigPanel.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/LeaderboardConfigPanel.java index e60bc6a6337..966b6d85d9c 100755 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/LeaderboardConfigPanel.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/LeaderboardConfigPanel.java @@ -298,7 +298,7 @@ public class LeaderboardConfigPanel extends FormPanel implements SelectedLeaderb TextColumn courseAreaColumn = new TextColumn() { @Override public String getValue(StrippedLeaderboardDTO leaderboard) { - return leaderboard.defaultCourseAreaIdAsString == null ? "" : leaderboard.defaultCourseAreaName; + return leaderboard.defaultCourseAreaId == null ? "" : leaderboard.defaultCourseAreaName; } }; @@ -323,7 +323,7 @@ public class LeaderboardConfigPanel extends FormPanel implements SelectedLeaderb LeaderboardDescriptor descriptor = new LeaderboardDescriptor(leaderboardDTO.name, leaderboardDTO.displayName, /* scoring scheme provided by regatta */ null, leaderboardDTO.discardThresholds, leaderboardDTO.regattaName, - leaderboardDTO.defaultCourseAreaIdAsString); + leaderboardDTO.defaultCourseAreaId); AbstractLeaderboardDialog dialog = new RegattaLeaderboardEditDialog(Collections .unmodifiableCollection(otherExistingLeaderboard), Collections.unmodifiableCollection(allRegattas), descriptor, stringMessages, errorReporter, @@ -339,7 +339,7 @@ public class LeaderboardConfigPanel extends FormPanel implements SelectedLeaderb }); dialog.show(); } else { - LeaderboardDescriptor descriptor = new LeaderboardDescriptor(leaderboardDTO.name, leaderboardDTO.displayName, leaderboardDTO.scoringScheme, leaderboardDTO.discardThresholds, leaderboardDTO.defaultCourseAreaIdAsString); + LeaderboardDescriptor descriptor = new LeaderboardDescriptor(leaderboardDTO.name, leaderboardDTO.displayName, leaderboardDTO.scoringScheme, leaderboardDTO.discardThresholds, leaderboardDTO.defaultCourseAreaId); openUpdateFlexibleLeaderboardDialog(leaderboardDTO, otherExistingLeaderboard, leaderboardDTO.name, descriptor); } } @@ -1091,7 +1091,7 @@ public class LeaderboardConfigPanel extends FormPanel implements SelectedLeaderb @Override public void ok(final LeaderboardDescriptor newLeaderboard) { sailingService.createFlexibleLeaderboard(newLeaderboard.getName(), newLeaderboard.getDisplayName(), newLeaderboard.getDiscardThresholds(), - newLeaderboard.getScoringScheme(), newLeaderboard.getCourseAreaIdAsString(), + newLeaderboard.getScoringScheme(), newLeaderboard.getCourseAreaId(), new MarkedAsyncCallback() { @Override public void handleFailure(Throwable t) { @@ -1147,7 +1147,7 @@ public class LeaderboardConfigPanel extends FormPanel implements SelectedLeaderb private void updateLeaderboard(final String oldLeaderboardName, final LeaderboardDescriptor leaderboardToUpdate) { sailingService.updateLeaderboard(oldLeaderboardName, leaderboardToUpdate.getName(), leaderboardToUpdate.getDisplayName(), - leaderboardToUpdate.getDiscardThresholds(), leaderboardToUpdate.getCourseAreaIdAsString(), new AsyncCallback() { + leaderboardToUpdate.getDiscardThresholds(), leaderboardToUpdate.getCourseAreaId(), new AsyncCallback() { @Override public void onFailure(Throwable t) { errorReporter.reportError("Error trying to update leaderboard " + oldLeaderboardName + ": " diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/LeaderboardDescriptor.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/LeaderboardDescriptor.java index 1acdb0ce128..55cb3c3b1bf 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/LeaderboardDescriptor.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/LeaderboardDescriptor.java @@ -1,5 +1,7 @@ package com.sap.sailing.gwt.ui.adminconsole; +import java.util.UUID; + import com.sap.sailing.domain.common.ScoringSchemeType; /** @@ -14,29 +16,29 @@ public class LeaderboardDescriptor { private ScoringSchemeType scoringScheme; private int[] discardThresholds; private String regattaName; - private String courseAreaIdAsString; + private UUID courseAreaId; public LeaderboardDescriptor() { } - public LeaderboardDescriptor(String name, String displayName, ScoringSchemeType scoringScheme, int[] discardThresholds, String regattaName, String courseAreaIdAsString) { + public LeaderboardDescriptor(String name, String displayName, ScoringSchemeType scoringScheme, int[] discardThresholds, String regattaName, UUID courseAreaId) { this.name = name; this.displayName = displayName; this.scoringScheme = scoringScheme; this.discardThresholds = discardThresholds; this.regattaName = regattaName; - this.courseAreaIdAsString = courseAreaIdAsString; + this.courseAreaId = courseAreaId; } /** * Leaves the {@link #regattaName} null, representing a flexible leaderboard, not a regatta leaderboard */ - public LeaderboardDescriptor(String name, String displayName, ScoringSchemeType scoringScheme, int[] discardThresholds, String courseAreaIdAsString) { + public LeaderboardDescriptor(String name, String displayName, ScoringSchemeType scoringScheme, int[] discardThresholds, UUID courseAreaId) { this.name = name; this.displayName = displayName; this.scoringScheme = scoringScheme; this.discardThresholds = discardThresholds; - this.courseAreaIdAsString = courseAreaIdAsString; + this.courseAreaId = courseAreaId; } public String getName() { @@ -84,11 +86,11 @@ public class LeaderboardDescriptor { this.displayName = displayName; } - public String getCourseAreaIdAsString() { - return courseAreaIdAsString; + public UUID getCourseAreaId() { + return courseAreaId; } - public void setCourseAreaIdAsString(String courseAreaId) { - this.courseAreaIdAsString = courseAreaId; + public void setCourseAreaId(UUID courseAreaId) { + this.courseAreaId = courseAreaId; } } diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/RegattaDetailsComposite.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/RegattaDetailsComposite.java index fde518c072d..f957b486e24 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/RegattaDetailsComposite.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/RegattaDetailsComposite.java @@ -318,7 +318,7 @@ public class RegattaDetailsComposite extends Composite { if (regatta != null) { regattaName.setText(regatta.getName()); boatClassName.setText(regatta.boatClass != null ? regatta.boatClass.getName() : ""); - defaultCourseArea.setText(regatta.defaultCourseAreaUuidAsString == null ? "" : regatta.defaultCourseAreaName); + defaultCourseArea.setText(regatta.defaultCourseAreaUuid == null ? "" : regatta.defaultCourseAreaName); if (regatta.configuration != null) { configuration.setText(stringMessages.configured()); } else { diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/RegattaListComposite.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/RegattaListComposite.java index 5a835a8a2b4..2bed6c7eafc 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/RegattaListComposite.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/RegattaListComposite.java @@ -221,7 +221,7 @@ public class RegattaListComposite extends Composite implements RegattaDisplayer private void commitEditedRegatta(final RegattaDTO editedRegatta) { final RegattaIdentifier regattaName = new RegattaName(editedRegatta.getName()); - sailingService.updateRegatta(regattaName, editedRegatta.defaultCourseAreaUuidAsString, + sailingService.updateRegatta(regattaName, editedRegatta.defaultCourseAreaUuid, editedRegatta.configuration, new AsyncCallback() { @Override diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/RegattaStructureManagementPanel.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/RegattaStructureManagementPanel.java index 96449b5c68a..b979a40c07a 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/RegattaStructureManagementPanel.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/RegattaStructureManagementPanel.java @@ -165,7 +165,7 @@ public class RegattaStructureManagementPanel extends SimplePanel implements Rega } sailingService.createRegatta(newRegatta.getName(), newRegatta.boatClass==null?null:newRegatta.boatClass.getName(), new RegattaCreationParametersDTO(seriesStructure), true, - newRegatta.scoringScheme, newRegatta.defaultCourseAreaUuidAsString, new AsyncCallback() { + newRegatta.scoringScheme, newRegatta.defaultCourseAreaUuid, new AsyncCallback() { @Override public void onFailure(Throwable t) { errorReporter.reportError("Error trying to create new regatta " + newRegatta.getName() + ": " + t.getMessage()); diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/RegattaWithSeriesAndFleetsDialog.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/RegattaWithSeriesAndFleetsDialog.java index fcb050e7a4e..8824d4c4d4b 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/RegattaWithSeriesAndFleetsDialog.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/RegattaWithSeriesAndFleetsDialog.java @@ -1,6 +1,7 @@ package com.sap.sailing.gwt.ui.adminconsole; import java.util.List; +import java.util.UUID; import com.google.gwt.event.dom.client.ChangeEvent; import com.google.gwt.event.dom.client.ChangeHandler; @@ -105,9 +106,9 @@ public abstract class RegattaWithSeriesAndFleetsDialog extends DataEntryDialog events) { if (!events.isEmpty()) { - Collection eventIds = new HashSet(); + Collection eventIds = new HashSet(); for (EventDTO event : events) { eventIds.add(event.id); } diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/SailingService.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/SailingService.java index 5994b32f4d3..40b14551683 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/SailingService.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/SailingService.java @@ -1,11 +1,11 @@ package com.sap.sailing.gwt.ui.client; -import java.io.Serializable; import java.util.Collection; import java.util.Date; import java.util.List; import java.util.Map; import java.util.Set; +import java.util.UUID; import com.google.gwt.user.client.rpc.RemoteService; import com.google.gwt.user.client.rpc.RemoteServiceRelativePath; @@ -130,9 +130,9 @@ public interface SailingService extends RemoteService { List getLeaderboardsByEvent(RegattaDTO regatta); - StrippedLeaderboardDTO updateLeaderboard(String leaderboardName, String newLeaderboardName, String newLeaderboardDisplayName, int[] newDiscardingThreasholds, String newCourseAreaIdAsString); + StrippedLeaderboardDTO updateLeaderboard(String leaderboardName, String newLeaderboardName, String newLeaderboardDisplayName, int[] newDiscardingThreasholds, UUID newCourseAreaId); - StrippedLeaderboardDTO createFlexibleLeaderboard(String leaderboardName, String leaderboardDisplayName, int[] discardThresholds, ScoringSchemeType scoringSchemeType, String courseAreaId); + StrippedLeaderboardDTO createFlexibleLeaderboard(String leaderboardName, String leaderboardDisplayName, int[] discardThresholds, ScoringSchemeType scoringSchemeType, UUID courseAreaId); StrippedLeaderboardDTO createRegattaLeaderboard(RegattaIdentifier regattaIdentifier, String leaderboardDisplayName, int[] discardThresholds); @@ -154,13 +154,13 @@ public interface SailingService extends RemoteService { RegattaDTO createRegatta(String regattaName, String boatClassName, RegattaCreationParametersDTO seriesNamesWithFleetNamesAndFleetOrderingAndMedal, boolean persistent, - ScoringSchemeType scoringSchemeType, String defaultCourseAreaId); + ScoringSchemeType scoringSchemeType, UUID defaultCourseAreaId); void removeRegatta(RegattaIdentifier regattaIdentifier); void removeRegattas(Collection regattas); - void updateRegatta(RegattaIdentifier regattaIdentifier, String defaultCourseAreaUuidAsString, RegattaConfigurationDTO regattaConfiguration); + void updateRegatta(RegattaIdentifier regattaIdentifier, UUID defaultCourseAreaUuid, RegattaConfigurationDTO regattaConfiguration); List addRaceColumnsToSeries(RegattaIdentifier regattaIdentifier, String seriesName, List columnNames); @@ -248,18 +248,20 @@ public interface SailingService extends RemoteService { void updateRacesDelayToLive(List regattaAndRaceIdentifiers, long delayToLiveInMs); - void updateEvent(String eventName, String eventIdAsString, VenueDTO venue, String publicationUrl, boolean isPublic, + void updateEvent(String eventName, UUID eventId, VenueDTO venue, String publicationUrl, boolean isPublic, List regattaNames); EventDTO createEvent(String eventName, String venueName, String publicationUrl, boolean isPublic, List courseAreaNames); - void removeEvent(String eventIdAsString); + void removeEvent(UUID eventId); - void removeEvents(Collection eventIdsAsStrings); + void removeEvents(Collection eventIds); - void renameEvent(String eventIdAsString, String newName); + void renameEvent(UUID eventId, String newName); EventDTO getEventByName(String eventName); + + EventDTO getEventById(UUID id); Iterable getScoreCorrectionProviderNames(); @@ -309,19 +311,15 @@ public interface SailingService extends RemoteService { PolarSheetGenerationResponse generatePolarSheetForRaces(List selectedRaces, PolarSheetGenerationSettings settings, String name) throws Exception; - EventDTO getEventById(Serializable id); - - CourseAreaDTO createCourseArea(String eventIdAsString, String courseAreaName); - - EventDTO getEventByIdAsString(String eventIdAsString); + CourseAreaDTO createCourseArea(UUID eventId, String courseAreaName); List> getLeaderboardsNamesOfMetaleaderboard(String metaLeaderboardName); Pair checkLeaderboardName(String leaderboardName); - List getRegattaStructureForEvent(String eventIdAsString); + List getRegattaStructureForEvent(UUID eventId); - List getRaceStateEntriesForRaceGroup(String eventIdAsString, List visibleCourseAreas, + List getRaceStateEntriesForRaceGroup(UUID eventId, List visibleCourseAreas, List visibleRegattas, boolean showOnlyCurrentlyRunningRaces, boolean showOnlyRacesOfSameDay); String getBuildVersion(); diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/SailingServiceAsync.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/SailingServiceAsync.java index d19fab0e55c..0baeb4a0591 100755 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/SailingServiceAsync.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/SailingServiceAsync.java @@ -1,11 +1,11 @@ package com.sap.sailing.gwt.ui.client; -import java.io.Serializable; import java.util.Collection; import java.util.Date; import java.util.List; import java.util.Map; import java.util.Set; +import java.util.UUID; import com.google.gwt.user.client.rpc.AsyncCallback; import com.sap.sailing.domain.common.DetailType; @@ -180,9 +180,9 @@ public interface SailingServiceAsync { void getLeaderboardsByRace(RaceDTO race, AsyncCallback> callback); void updateLeaderboard(String leaderboardName, String newLeaderboardName, String newLeaderboardDisplayName, - int[] newDiscardingThreasholds, String newCourseAreaIdAsId, AsyncCallback callback); + int[] newDiscardingThreasholds, UUID newCourseAreaId, AsyncCallback callback); - void createFlexibleLeaderboard(String leaderboardName, String leaderboardDisplayName, int[] discardThresholds, ScoringSchemeType scoringSchemeType, String courseAreaId, + void createFlexibleLeaderboard(String leaderboardName, String leaderboardDisplayName, int[] discardThresholds, ScoringSchemeType scoringSchemeType, UUID courseAreaId, AsyncCallback asyncCallback); void createRegattaLeaderboard(RegattaIdentifier regattaIdentifier, String leaderboardDisplayName, int[] discardThresholds, @@ -320,28 +320,28 @@ public interface SailingServiceAsync { */ void getEventByName(String eventName, AsyncCallback callback); - void getEventById(Serializable id, AsyncCallback callback); + void getEventById(UUID id, AsyncCallback callback); /** * Renames the event with the name oldName to the newName.
* If there's no event with the name oldName or there's already a event with the name * newName a {@link IllegalArgumentException} is thrown. */ - void renameEvent(String eventIdAsString, String newName, AsyncCallback callback); + void renameEvent(UUID eventId, String newName, AsyncCallback callback); /** * Removes the event with the id id from the service and the persistence store. */ - void removeEvent(String eventIdAsString, AsyncCallback callback); + void removeEvent(UUID eventId, AsyncCallback callback); - void removeEvents(Collection eventIdsAsStrings, AsyncCallback asyncCallback); + void removeEvents(Collection eventIds, AsyncCallback asyncCallback); void createEvent(String eventName, String description, String publicationUrl, boolean isPublic, List courseAreaNames, AsyncCallback callback); - void updateEvent(String eventName, String eventIdAsString, VenueDTO venue, String publicationUrl, boolean isPublic, + void updateEvent(String eventName, UUID eventId, VenueDTO venue, String publicationUrl, boolean isPublic, List regattaNames, AsyncCallback callback); - void createCourseArea(String eventIdAsString, String courseAreaName, AsyncCallback callback); + void createCourseArea(UUID eventId, String courseAreaName, AsyncCallback callback); void removeRegatta(RegattaIdentifier regattaIdentifier, AsyncCallback callback); @@ -361,7 +361,7 @@ public interface SailingServiceAsync { void createRegatta(String regattaName, String boatClassName, RegattaCreationParametersDTO seriesNamesWithFleetNamesAndFleetOrderingAndMedal, boolean persistent, - ScoringSchemeType scoringSchemeType, String defaultCourseAreaId, AsyncCallback callback); + ScoringSchemeType scoringSchemeType, UUID defaultCourseAreaId, AsyncCallback callback); void addRaceColumnsToSeries(RegattaIdentifier regattaIdentifier, String seriesName, List columnNames, AsyncCallback> callback); @@ -425,11 +425,9 @@ public interface SailingServiceAsync { void generatePolarSheetForRaces(List selectedRaces, PolarSheetGenerationSettings settings, String name, AsyncCallback asyncCallback); - - void getEventByIdAsString(String eventIdAsString, AsyncCallback asyncCallback); - void updateRegatta(RegattaIdentifier regattaIdentifier, String defaultCourseAreaUuidAsString, RegattaConfigurationDTO regattaConfiguration, AsyncCallback callback); + void updateRegatta(RegattaIdentifier regattaIdentifier, UUID defaultCourseAreaUuid, RegattaConfigurationDTO regattaConfiguration, AsyncCallback callback); void getLeaderboardDataEntriesForAllRaceColumns(String leaderboardName, Date date, DetailType detailType, AsyncCallback, List>>> callback); @@ -442,9 +440,9 @@ public interface SailingServiceAsync { void stopReplicatingFromMaster(AsyncCallback asyncCallback); - void getRegattaStructureForEvent(String eventIdAsString, AsyncCallback> asyncCallback); + void getRegattaStructureForEvent(UUID eventId, AsyncCallback> asyncCallback); - void getRaceStateEntriesForRaceGroup(String eventIdAsString, List visibleCourseAreas, + void getRaceStateEntriesForRaceGroup(UUID eventId, List visibleCourseAreas, List visibleRegattas, boolean showOnlyCurrentlyRunningRaces, boolean showOnlyRacesOfSameDay, AsyncCallback> markedAsyncCallback); diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/regattaoverview/RegattaOverviewEntryPoint.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/regattaoverview/RegattaOverviewEntryPoint.java index 81c04372b09..977f86e40da 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/regattaoverview/RegattaOverviewEntryPoint.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/regattaoverview/RegattaOverviewEntryPoint.java @@ -2,6 +2,7 @@ package com.sap.sailing.gwt.ui.regattaoverview; import java.util.ArrayList; import java.util.List; +import java.util.UUID; import com.google.gwt.dom.client.Style.Unit; import com.google.gwt.event.dom.client.ClickEvent; @@ -51,9 +52,13 @@ public class RegattaOverviewEntryPoint extends AbstractEntryPoint { } String eventIdAsString = Window.Location.getParameter(PARAM_EVENT); + if (eventIdAsString == null) { + Window.alert("Missing parameter"); + return; + } createAndAddDetailPanel(); - createAndAddRegattaPanel(eventIdAsString); + createAndAddRegattaPanel(UUID.fromString(eventIdAsString)); toggleDetailPanel(false); regattaPanel.setEntryClickedHandler(new EntryHandler() { @@ -74,9 +79,9 @@ public class RegattaOverviewEntryPoint extends AbstractEntryPoint { containerPanel.setWidgetHidden(detailPanel, !visibile); } - private void createAndAddRegattaPanel(String eventIdAsString) { + private void createAndAddRegattaPanel(UUID eventId) { RegattaRaceStatesSettings settings = createRegattaRaceStatesSettingsFromURL(); - regattaPanel = new RegattaOverviewPanel(sailingService, this, stringMessages, eventIdAsString, settings); + regattaPanel = new RegattaOverviewPanel(sailingService, this, stringMessages, eventId, settings); Panel centerPanel = new FlowPanel(); centerPanel.add(regattaPanel); ScrollPanel scrollPanel = new ScrollPanel(centerPanel); @@ -94,7 +99,7 @@ public class RegattaOverviewEntryPoint extends AbstractEntryPoint { } public static RegattaRaceStatesSettings createRegattaRaceStatesSettingsFromURL() { - List visibleCourseAreas = new ArrayList(); + List visibleCourseAreas = new ArrayList(); List visibleRegattas = new ArrayList(); boolean showOnlyCurrentlyRunningRaces = Window.Location.getParameter(PARAM_ONLY_RUNNING_RACES) == null @@ -104,7 +109,9 @@ public class RegattaOverviewEntryPoint extends AbstractEntryPoint { && Window.Location.getParameter(PARAM_ONLY_RACES_OF_SAME_DAY).equalsIgnoreCase("true"); if (Window.Location.getParameterMap().containsKey(PARAM_COURSE_AREA)) { - visibleCourseAreas.addAll(Window.Location.getParameterMap().get(PARAM_COURSE_AREA)); + for (String value : Window.Location.getParameterMap().get(PARAM_COURSE_AREA)) { + visibleCourseAreas.add(UUID.fromString(value)); + } } if (Window.Location.getParameterMap().containsKey(PARAM_REGATTA)) { @@ -114,7 +121,7 @@ public class RegattaOverviewEntryPoint extends AbstractEntryPoint { return new RegattaRaceStatesSettings(visibleCourseAreas, visibleRegattas, showOnlyRacesOfSameDay, showOnlyCurrentlyRunningRaces); } - public static String getUrl(String eventIdAsString, RegattaRaceStatesSettings settings, + public static String getUrl(UUID eventId, RegattaRaceStatesSettings settings, boolean isSetVisibleCourseAreasInUrl, boolean isSetVisibleRegattasInUrl) { String debugParam = Window.Location.getParameter("gwt.codesvr"); String showOnlyCurrentlyRunningRaces = "&" + PARAM_ONLY_RUNNING_RACES + "=" + (settings.isShowOnlyCurrentlyRunningRaces() ? "true" : "false"); @@ -122,11 +129,11 @@ public class RegattaOverviewEntryPoint extends AbstractEntryPoint { StringBuilder visibleCourseAreas = new StringBuilder(); if (isSetVisibleCourseAreasInUrl) { - for (String visibleCourseArea : settings.getVisibleCourseAreas()) { + for (UUID visibleCourseArea : settings.getVisibleCourseAreas()) { visibleCourseAreas.append('&'); visibleCourseAreas.append(PARAM_COURSE_AREA); visibleCourseAreas.append('='); - visibleCourseAreas.append(visibleCourseArea); + visibleCourseAreas.append(visibleCourseArea.toString()); } } StringBuilder visibleRegattas = new StringBuilder(); @@ -138,7 +145,7 @@ public class RegattaOverviewEntryPoint extends AbstractEntryPoint { visibleRegattas.append(visibleRegatta); } } - String link = URLEncoder.encode("/gwt/RegattaOverview.html?" + PARAM_EVENT+ "=" + eventIdAsString + String link = URLEncoder.encode("/gwt/RegattaOverview.html?" + PARAM_EVENT+ "=" + eventId.toString() + visibleCourseAreas.toString() + visibleRegattas.toString() + showOnlyCurrentlyRunningRaces diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/regattaoverview/RegattaOverviewPanel.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/regattaoverview/RegattaOverviewPanel.java index a81c0f049be..8d95056646e 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/regattaoverview/RegattaOverviewPanel.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/regattaoverview/RegattaOverviewPanel.java @@ -3,6 +3,7 @@ package com.sap.sailing.gwt.ui.regattaoverview; import java.util.ArrayList; import java.util.Date; import java.util.List; +import java.util.UUID; import com.google.gwt.dom.client.Style.Unit; import com.google.gwt.event.dom.client.ClickEvent; @@ -41,7 +42,7 @@ public class RegattaOverviewPanel extends SimplePanel { protected final StringMessages stringMessages; protected final ErrorReporter errorReporter; - private final String eventIdAsString; + private final UUID eventId; private EventDTO eventDTO; private List raceGroupDTOs; private List eventRaceGroupListeners; @@ -71,11 +72,11 @@ public class RegattaOverviewPanel extends SimplePanel { } public RegattaOverviewPanel(SailingServiceAsync sailingService, final ErrorReporter errorReporter, final StringMessages stringMessages, - String eventIdAsString, RegattaRaceStatesSettings settings) { + UUID eventId, RegattaRaceStatesSettings settings) { this.sailingService = sailingService; this.stringMessages = stringMessages; this.errorReporter = errorReporter; - this.eventIdAsString = eventIdAsString; + this.eventId = eventId; this.serverUpdateTimer = new Timer(PlayModes.Live, serverUpdateRateInMs); this.uiUpdateTimer = new Timer(PlayModes.Live, uiUpdateRateInMs); this.eventDTO = null; @@ -89,7 +90,7 @@ public class RegattaOverviewPanel extends SimplePanel { mainPanel.setWidth("100%"); mainPanel.addStyleName(STYLE_CONTENT_WRAPPER); - regattaRaceStatesComponent = new RegattaRaceStatesComponent(sailingService, errorReporter, stringMessages, eventIdAsString, settings, uiUpdateTimer); + regattaRaceStatesComponent = new RegattaRaceStatesComponent(sailingService, errorReporter, stringMessages, eventId, settings, uiUpdateTimer); this.eventRaceGroupListeners.add(regattaRaceStatesComponent); regattaRaceStatesComponent.setWidth("100%"); @@ -191,12 +192,12 @@ public class RegattaOverviewPanel extends SimplePanel { } private void retrieveEvent() { - sailingService.getEventByIdAsString(eventIdAsString, new MarkedAsyncCallback() { + sailingService.getEventById(eventId, new MarkedAsyncCallback() { @Override protected void handleFailure(Throwable cause) { settingsButton.setEnabled(false); - errorReporter.reportError("Error trying to load event with id " + eventIdAsString + " : " + errorReporter.reportError("Error trying to load event with id " + eventId + " : " + cause.getMessage()); } @@ -228,11 +229,11 @@ public class RegattaOverviewPanel extends SimplePanel { } private void retrieveRegattaStructure() { - sailingService.getRegattaStructureForEvent(eventIdAsString, new MarkedAsyncCallback>() { + sailingService.getRegattaStructureForEvent(eventId, new MarkedAsyncCallback>() { @Override protected void handleFailure(Throwable cause) { - errorReporter.reportError("Error trying to load regattas for event with id " + eventIdAsString + " : " + errorReporter.reportError("Error trying to load regattas for event with id " + eventId + " : " + cause.getMessage()); } diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/regattaoverview/RegattaRaceStatesComponent.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/regattaoverview/RegattaRaceStatesComponent.java index bf2d50d1b09..73e544acc95 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/regattaoverview/RegattaRaceStatesComponent.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/regattaoverview/RegattaRaceStatesComponent.java @@ -8,6 +8,7 @@ import java.util.Date; import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.UUID; import com.google.gwt.cell.client.FieldUpdater; import com.google.gwt.cell.client.SafeHtmlCell; @@ -84,7 +85,7 @@ public class RegattaRaceStatesComponent extends SimplePanel implements Component private final SailingServiceAsync sailingService; private final StringMessages stringMessages; - private final String eventIdAsString; + private final UUID eventId; private EventDTO eventDTO; private List raceGroupDTOs; @@ -121,17 +122,17 @@ public class RegattaRaceStatesComponent extends SimplePanel implements Component * timer passed for this argument will be synchronized. */ public RegattaRaceStatesComponent(final SailingServiceAsync sailingService, ErrorReporter errorReporter, - final StringMessages stringMessages, final String eventIdAsString, RegattaRaceStatesSettings settings, Timer timerToSynchronize) { + final StringMessages stringMessages, final UUID eventId, RegattaRaceStatesSettings settings, Timer timerToSynchronize) { this.sailingService = sailingService; this.stringMessages = stringMessages; - this.eventIdAsString = eventIdAsString; + this.eventId = eventId; this.allEntries = new ArrayList(); this.timerToSynchronize = timerToSynchronize; this.eventDTO = null; this.raceGroupDTOs = null; - this.localStorageRegattaOverviewEventKey = LOCAL_STORAGE_REGATTA_OVERVIEW_KEY + eventIdAsString; + this.localStorageRegattaOverviewEventKey = LOCAL_STORAGE_REGATTA_OVERVIEW_KEY + eventId.toString(); this.flagInterpreter = new RaceStateFlagsInterpreter(stringMessages); @@ -178,11 +179,11 @@ public class RegattaRaceStatesComponent extends SimplePanel implements Component /** */ protected void loadAndUpdateEventLog() { - if (eventIdAsString == null || eventDTO == null || raceGroupDTOs == null) { + if (eventId == null || eventDTO == null || raceGroupDTOs == null) { return; } final long clientTimeWhenRequestWasSent = System.currentTimeMillis(); - sailingService.getRaceStateEntriesForRaceGroup(eventIdAsString, settings.getVisibleCourseAreas(), settings.getVisibleRegattas(), + sailingService.getRaceStateEntriesForRaceGroup(eventId, settings.getVisibleCourseAreas(), settings.getVisibleRegattas(), settings.isShowOnlyCurrentlyRunningRaces(), settings.isShowOnlyRacesOfSameDay(), new MarkedAsyncCallback>() { @Override @@ -576,7 +577,7 @@ public class RegattaRaceStatesComponent extends SimplePanel implements Component @Override public SettingsDialogComponent getSettingsDialogComponent() { - return new RegattaRaceStatesSettingsDialogComponent(settings, stringMessages, eventIdAsString, + return new RegattaRaceStatesSettingsDialogComponent(settings, stringMessages, eventId, Collections.unmodifiableList(eventDTO.venue.getCourseAreas()), Collections.unmodifiableList(raceGroupDTOs)); } @@ -626,7 +627,7 @@ public class RegattaRaceStatesComponent extends SimplePanel implements Component private void fillVisibleCourseAreasInSettingsIfEmpty() { if (settings.getVisibleCourseAreas().isEmpty() && eventDTO != null) { for (CourseAreaDTO courseArea : eventDTO.venue.getCourseAreas()) { - settings.getVisibleCourseAreas().add(courseArea.uuidAsString); + settings.getVisibleCourseAreas().add(courseArea.id); } } } @@ -664,7 +665,7 @@ public class RegattaRaceStatesComponent extends SimplePanel implements Component private void storeRegattaRaceStatesSettings(RegattaRaceStatesSettings settings) { Storage localStorage = Storage.getLocalStorageIfSupported(); - if (localStorage != null && eventIdAsString != null) { + if (localStorage != null && eventId != null) { // delete old value localStorage.removeItem(localStorageRegattaOverviewEventKey); diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/regattaoverview/RegattaRaceStatesSettings.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/regattaoverview/RegattaRaceStatesSettings.java index ee54295ef35..5131777b4d4 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/regattaoverview/RegattaRaceStatesSettings.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/regattaoverview/RegattaRaceStatesSettings.java @@ -2,22 +2,23 @@ package com.sap.sailing.gwt.ui.regattaoverview; import java.util.ArrayList; import java.util.List; +import java.util.UUID; public class RegattaRaceStatesSettings { - private List visibleCourseAreas; + private List visibleCourseAreas; private List visibleRegattas; private boolean showOnlyRacesOfSameDay; private boolean showOnlyCurrentlyRunningRaces; public RegattaRaceStatesSettings() { - this.visibleCourseAreas = new ArrayList(); + this.visibleCourseAreas = new ArrayList(); this.visibleRegattas = new ArrayList(); this.showOnlyRacesOfSameDay = false; this.showOnlyCurrentlyRunningRaces = true; } - public RegattaRaceStatesSettings(List visibleCourseAreas, List visibleRegattas, + public RegattaRaceStatesSettings(List visibleCourseAreas, List visibleRegattas, boolean showOnlyRacesOfSameDay, boolean showOnlyCurrentlyRunningRaces) { this.visibleCourseAreas = visibleCourseAreas; this.visibleRegattas = visibleRegattas; @@ -25,7 +26,7 @@ public class RegattaRaceStatesSettings { this.showOnlyCurrentlyRunningRaces = showOnlyCurrentlyRunningRaces; } - public List getVisibleCourseAreas() { + public List getVisibleCourseAreas() { return visibleCourseAreas; } diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/regattaoverview/RegattaRaceStatesSettingsDialogComponent.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/regattaoverview/RegattaRaceStatesSettingsDialogComponent.java index 1345db57b30..2f644ecb372 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/regattaoverview/RegattaRaceStatesSettingsDialogComponent.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/regattaoverview/RegattaRaceStatesSettingsDialogComponent.java @@ -4,6 +4,7 @@ import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.UUID; import java.util.Map.Entry; import com.google.gwt.event.dom.client.ClickEvent; @@ -28,13 +29,13 @@ public class RegattaRaceStatesSettingsDialogComponent implements SettingsDialogC private final StringMessages stringMessages; private final RegattaRaceStatesSettings initialSettings; - private final String eventIdAsString; + private final UUID eventId; private final List courseAreas; private final List raceGroups; private CheckBox showOnlyRacesOfSameDayCheckBox; private CheckBox showOnlyCurrentlyRunningRacesCheckBox; - private final Map courseAreaCheckBoxMap; + private final Map courseAreaCheckBoxMap; private final Map regattaCheckBoxMap; private final Anchor resultingLink; private Button courseAreaDeselectButton; @@ -43,13 +44,13 @@ public class RegattaRaceStatesSettingsDialogComponent implements SettingsDialogC private final static String SETTINGS_DIALOG_COMPONENT = "SettingsDialogComponent"; public RegattaRaceStatesSettingsDialogComponent(RegattaRaceStatesSettings settings, StringMessages stringMessages, - String eventIdAsString, List courseAreas, List raceGroups) { + UUID eventId, List courseAreas, List raceGroups) { this.stringMessages = stringMessages; this.initialSettings = settings; - this.eventIdAsString = eventIdAsString; + this.eventId = eventId; this.courseAreas = courseAreas; this.raceGroups = raceGroups; - this.courseAreaCheckBoxMap = new HashMap(); + this.courseAreaCheckBoxMap = new HashMap(); this.regattaCheckBoxMap = new HashMap(); this.resultingLink = new Anchor(stringMessages.asLink()); } @@ -76,10 +77,10 @@ public class RegattaRaceStatesSettingsDialogComponent implements SettingsDialogC boolean allCheckboxesSelected = true; for (CourseAreaDTO courseAreaDTO : courseAreas) { CheckBox checkBox = dialog.createCheckbox(courseAreaDTO.getName()); - boolean isCourseAreaVisible = Util.contains(initialSettings.getVisibleCourseAreas(), courseAreaDTO.uuidAsString); + boolean isCourseAreaVisible = Util.contains(initialSettings.getVisibleCourseAreas(), courseAreaDTO.id); allCheckboxesSelected &= isCourseAreaVisible; checkBox.setValue(isCourseAreaVisible); - courseAreaCheckBoxMap.put(courseAreaDTO.uuidAsString, checkBox); + courseAreaCheckBoxMap.put(courseAreaDTO.id, checkBox); courseAreaGrid.setWidget(rowIndex, columnIndex++, checkBox); if(columnIndex == maxCourseAreasPerRow) { @@ -219,8 +220,8 @@ public class RegattaRaceStatesSettingsDialogComponent implements SettingsDialogC @Override public RegattaRaceStatesSettings getResult() { - List selectedCourseAreas = new ArrayList(); - for (Entry entry : courseAreaCheckBoxMap.entrySet()) { + List selectedCourseAreas = new ArrayList(); + for (Entry entry : courseAreaCheckBoxMap.entrySet()) { if (entry.getValue().getValue()) { selectedCourseAreas.add(entry.getKey()); } @@ -249,7 +250,7 @@ public class RegattaRaceStatesSettingsDialogComponent implements SettingsDialogC public String getErrorMessage(RegattaRaceStatesSettings settings) { String errorMessage = null; if (errorMessage == null) { - updateLinkUrl(eventIdAsString, settings); + updateLinkUrl(eventId, settings); } return errorMessage; } @@ -261,7 +262,7 @@ public class RegattaRaceStatesSettingsDialogComponent implements SettingsDialogC return null; } - private void updateLinkUrl(String eventIdAsString, RegattaRaceStatesSettings settings) { + private void updateLinkUrl(UUID eventId, RegattaRaceStatesSettings settings) { boolean isSetVisibleCourseAreasInUrl = true; boolean isSetVisibleRegattasInUrl = true; if (settings.getVisibleCourseAreas().size() == courseAreas.size()) { @@ -270,7 +271,7 @@ public class RegattaRaceStatesSettingsDialogComponent implements SettingsDialogC if (settings.getVisibleRegattas().size() == raceGroups.size()) { isSetVisibleRegattasInUrl = false; } - resultingLink.setHref(RegattaOverviewEntryPoint.getUrl(eventIdAsString, settings, isSetVisibleCourseAreasInUrl, isSetVisibleRegattasInUrl)); + resultingLink.setHref(RegattaOverviewEntryPoint.getUrl(eventId, settings, isSetVisibleCourseAreasInUrl, isSetVisibleRegattasInUrl)); } } diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/regattaoverview/RegattaRaceStatesSettingsJsonDeSerializer.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/regattaoverview/RegattaRaceStatesSettingsJsonDeSerializer.java index 8661d66de23..70bc6098b12 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/regattaoverview/RegattaRaceStatesSettingsJsonDeSerializer.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/regattaoverview/RegattaRaceStatesSettingsJsonDeSerializer.java @@ -2,6 +2,7 @@ package com.sap.sailing.gwt.ui.regattaoverview; import java.util.ArrayList; import java.util.List; +import java.util.UUID; import com.google.gwt.json.client.JSONArray; import com.google.gwt.json.client.JSONBoolean; @@ -24,7 +25,7 @@ public class RegattaRaceStatesSettingsJsonDeSerializer implements GwtJsonDeSeria JSONArray visibleCourseAreas = new JSONArray(); for (int i = 0 ; i < settings.getVisibleCourseAreas().size() ; i++) { - visibleCourseAreas.set(i, new JSONString(settings.getVisibleCourseAreas().get(i))); + visibleCourseAreas.set(i, new JSONString(settings.getVisibleCourseAreas().get(i).toString())); } result.put(FIELD_VISIBLE_COURSE_AREAS, visibleCourseAreas); @@ -47,10 +48,10 @@ public class RegattaRaceStatesSettingsJsonDeSerializer implements GwtJsonDeSeria JSONBoolean showOnlyRacesOfSameDay = (JSONBoolean) object.get(FIELD_SHOW_ONLY_RACES_OF_SAME_DAY); JSONArray jsonVisibleCourseAreas = (JSONArray) object.get(FIELD_VISIBLE_COURSE_AREAS); - List visibleCourseAreas = new ArrayList(); + List visibleCourseAreas = new ArrayList(); for (int i = 0 ; i < jsonVisibleCourseAreas.size() ; i++) { JSONString jsonCourseArea = (JSONString) jsonVisibleCourseAreas.get(i); - visibleCourseAreas.add(jsonCourseArea.stringValue()); + visibleCourseAreas.add(UUID.fromString(jsonCourseArea.stringValue())); } JSONArray jsonVisibleRegattas = (JSONArray) object.get(FIELD_VISIBLE_REGATTAS); diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/server/SailingServiceImpl.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/server/SailingServiceImpl.java index 83bb9c90b79..518628e0420 100755 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/server/SailingServiceImpl.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/server/SailingServiceImpl.java @@ -643,7 +643,7 @@ public class SailingServiceImpl extends ProxiedRemoteServiceServlet implements S regattaDTO.boatClass = new BoatClassDTO(boatClass.getName(), boatClass.getHullLength().getMeters()); } if (regatta.getDefaultCourseArea() != null) { - regattaDTO.defaultCourseAreaUuidAsString = regatta.getDefaultCourseArea().getId().toString(); + regattaDTO.defaultCourseAreaUuid = regatta.getDefaultCourseArea().getId(); regattaDTO.defaultCourseAreaName = regatta.getDefaultCourseArea().getName(); } regattaDTO.configuration = convertToRegattaConfigurationDTO(regatta.getRegattaConfiguration()); @@ -1805,20 +1805,9 @@ public class SailingServiceImpl extends ProxiedRemoteServiceServlet implements S @Override public StrippedLeaderboardDTO createFlexibleLeaderboard(String leaderboardName, String leaderboardDisplayName, int[] discardThresholds, ScoringSchemeType scoringSchemeType, - String courseAreaId) { - UUID courseAreaUuid = convertIdentifierStringToUuid(courseAreaId); + UUID courseAreaId) { return createStrippedLeaderboardDTO(getService().apply(new CreateFlexibleLeaderboard(leaderboardName, leaderboardDisplayName, discardThresholds, - baseDomainFactory.createScoringScheme(scoringSchemeType), courseAreaUuid)), false); - } - - private UUID convertIdentifierStringToUuid(String identifierToConvert) { - UUID convertedUuid = null; - if (identifierToConvert != null) { - try { - convertedUuid = UUID.fromString(identifierToConvert); - } catch (IllegalArgumentException iae) {} - } - return convertedUuid; + baseDomainFactory.createScoringScheme(scoringSchemeType), courseAreaId)), false); } public StrippedLeaderboardDTO createRegattaLeaderboard(RegattaIdentifier regattaIdentifier, String leaderboardDisplayName, int[] discardThresholds) { @@ -1911,7 +1900,7 @@ public class SailingServiceImpl extends ProxiedRemoteServiceServlet implements S leaderboardDTO.scoringScheme = leaderboard.getScoringScheme().getType(); } if (leaderboard.getDefaultCourseArea() != null) { - leaderboardDTO.defaultCourseAreaIdAsString = leaderboard.getDefaultCourseArea().getId().toString(); + leaderboardDTO.defaultCourseAreaId = leaderboard.getDefaultCourseArea().getId(); leaderboardDTO.defaultCourseAreaName = leaderboard.getDefaultCourseArea().getName(); } leaderboardDTO.setDelayToLiveInMillisForLatestRace(delayToLiveInMillisForLatestRace); @@ -1942,9 +1931,8 @@ public class SailingServiceImpl extends ProxiedRemoteServiceServlet implements S } @Override - public StrippedLeaderboardDTO updateLeaderboard(String leaderboardName, String newLeaderboardName, String newLeaderboardDisplayName, int[] newDiscardingThresholds, String newCourseAreaIdAsString) { - UUID newCourseAreaUuid = convertIdentifierStringToUuid(newCourseAreaIdAsString); - Leaderboard updatedLeaderboard = getService().apply(new UpdateLeaderboard(leaderboardName, newLeaderboardName, newLeaderboardDisplayName, newDiscardingThresholds, newCourseAreaUuid)); + public StrippedLeaderboardDTO updateLeaderboard(String leaderboardName, String newLeaderboardName, String newLeaderboardDisplayName, int[] newDiscardingThresholds, UUID newCourseAreaId) { + Leaderboard updatedLeaderboard = getService().apply(new UpdateLeaderboard(leaderboardName, newLeaderboardName, newLeaderboardDisplayName, newDiscardingThresholds, newCourseAreaId)); return createStrippedLeaderboardDTO(updatedLeaderboard, false); } @@ -2721,9 +2709,8 @@ public class SailingServiceImpl extends ProxiedRemoteServiceServlet implements S } @Override - public void updateEvent(String eventName, String eventIdAsString, VenueDTO venue, String publicationUrl, boolean isPublic, List regattaNames) { - UUID eventUuid = convertIdentifierStringToUuid(eventIdAsString); - getService().apply(new UpdateEvent(eventUuid, eventName, venue.getName(), publicationUrl, isPublic, regattaNames)); + public void updateEvent(String eventName, UUID eventId, VenueDTO venue, String publicationUrl, boolean isPublic, List regattaNames) { + getService().apply(new UpdateEvent(eventId, eventName, venue.getName(), publicationUrl, isPublic, regattaNames)); } @Override @@ -2731,35 +2718,32 @@ public class SailingServiceImpl extends ProxiedRemoteServiceServlet implements S UUID eventUuid = UUID.randomUUID(); getService().apply(new CreateEvent(eventName, venue, publicationUrl, isPublic, eventUuid)); for (String courseAreaName : courseAreaNames) { - createCourseArea(eventUuid.toString(), courseAreaName); + createCourseArea(eventUuid, courseAreaName); } return getEventById(eventUuid); } @Override - public CourseAreaDTO createCourseArea(String eventIdAsString, String courseAreaName) { - UUID eventUuid = convertIdentifierStringToUuid(eventIdAsString); - CourseArea courseArea = getService().apply(new AddCourseArea(eventUuid, courseAreaName, UUID.randomUUID())); + public CourseAreaDTO createCourseArea(UUID eventId, String courseAreaName) { + CourseArea courseArea = getService().apply(new AddCourseArea(eventId, courseAreaName, UUID.randomUUID())); return convertToCourseAreaDTO(courseArea); } @Override - public void removeEvents(Collection eventIdsAsStrings) { - for (String eventId : eventIdsAsStrings) { + public void removeEvents(Collection eventIds) { + for (UUID eventId : eventIds) { removeEvent(eventId); } } @Override - public void removeEvent(String eventIdAsString) { - UUID eventUuid = convertIdentifierStringToUuid(eventIdAsString); - getService().apply(new RemoveEvent(eventUuid)); + public void removeEvent(UUID eventId) { + getService().apply(new RemoveEvent(eventId)); } @Override - public void renameEvent(String eventIdAsString, String newName) { - UUID eventUuid = convertIdentifierStringToUuid(eventIdAsString); - getService().apply(new RenameEvent(eventUuid, newName)); + public void renameEvent(UUID eventId, String newName) { + getService().apply(new RenameEvent(eventId, newName)); } @Override @@ -2773,15 +2757,9 @@ public class SailingServiceImpl extends ProxiedRemoteServiceServlet implements S } return result; } - - @Override - public EventDTO getEventByIdAsString(String eventIdAsString) { - UUID eventUuid = convertIdentifierStringToUuid(eventIdAsString); - return getEventById(eventUuid); - } @Override - public EventDTO getEventById(Serializable id) { + public EventDTO getEventById(UUID id) { EventDTO result = null; Event event = getService().getEvent(id); if (event != null) { @@ -2796,7 +2774,7 @@ public class SailingServiceImpl extends ProxiedRemoteServiceServlet implements S eventDTO.venue.setName(event.getVenue() != null ? event.getVenue().getName() : null); eventDTO.publicationUrl = event.getPublicationUrl(); eventDTO.isPublic = event.isPublic(); - eventDTO.id = event.getId().toString(); + eventDTO.id = event.getId(); eventDTO.regattas = new ArrayList(); for (Regatta regatta: event.getRegattas()) { RegattaDTO regattaDTO = new RegattaDTO(); @@ -2813,14 +2791,14 @@ public class SailingServiceImpl extends ProxiedRemoteServiceServlet implements S private CourseAreaDTO convertToCourseAreaDTO(CourseArea courseArea) { CourseAreaDTO courseAreaDTO = new CourseAreaDTO(courseArea.getName()); - courseAreaDTO.uuidAsString = courseArea.getId().toString(); + courseAreaDTO.id = courseArea.getId(); return courseAreaDTO; } @Override - public List getRegattaStructureForEvent(String eventIdAsString) { + public List getRegattaStructureForEvent(UUID eventId) { List raceGroups = new ArrayList(); - Event event = getService().getEvent(convertIdentifierStringToUuid(eventIdAsString)); + Event event = getService().getEvent(eventId); if (event != null) { for (CourseArea courseArea : event.getVenue().getCourseAreas()) { for (Leaderboard leaderboard : getService().getLeaderboards().values()) { @@ -2899,10 +2877,9 @@ public class SailingServiceImpl extends ProxiedRemoteServiceServlet implements S } @Override - public void updateRegatta(RegattaIdentifier regattaName, String defaultCourseAreaUuidAsString, + public void updateRegatta(RegattaIdentifier regattaName, UUID defaultCourseAreaUuid, RegattaConfigurationDTO configurationDTO) { - UUID courseAreaUuid = convertIdentifierStringToUuid(defaultCourseAreaUuidAsString); - getService().apply(new UpdateSpecificRegatta(regattaName, courseAreaUuid, convertToRegattaConfiguration(configurationDTO))); + getService().apply(new UpdateSpecificRegatta(regattaName, defaultCourseAreaUuid, convertToRegattaConfiguration(configurationDTO))); } @Override @@ -2958,13 +2935,12 @@ public class SailingServiceImpl extends ProxiedRemoteServiceServlet implements S @Override public RegattaDTO createRegatta(String regattaName, String boatClassName, RegattaCreationParametersDTO seriesNamesWithFleetNamesAndFleetOrderingAndMedal, - boolean persistent, ScoringSchemeType scoringSchemeType, String defaultCourseAreaId) { - UUID courseAreaUuid = convertIdentifierStringToUuid(defaultCourseAreaId); + boolean persistent, ScoringSchemeType scoringSchemeType, UUID defaultCourseAreaId) { Regatta regatta = getService().apply( new AddSpecificRegatta( regattaName, boatClassName, UUID.randomUUID(), seriesNamesWithFleetNamesAndFleetOrderingAndMedal, - persistent, baseDomainFactory.createScoringScheme(scoringSchemeType), courseAreaUuid)); + persistent, baseDomainFactory.createScoringScheme(scoringSchemeType), defaultCourseAreaId)); return convertToRegattaDTO(regatta); } @@ -3125,17 +3101,17 @@ public class SailingServiceImpl extends ProxiedRemoteServiceServlet implements S } @Override - public List getRaceStateEntriesForRaceGroup(String eventIdAsString, List visibleCourseAreaIdsAsString, + public List getRaceStateEntriesForRaceGroup(UUID eventId, List visibleCourseAreaIds, List visibleRegattas, boolean showOnlyCurrentlyRunningRaces, boolean showOnlyRacesOfSameDay) { List result = new ArrayList(); Calendar dayToCheck = Calendar.getInstance(); dayToCheck.setTime(new Date()); - Event event = getService().getEvent(convertIdentifierStringToUuid(eventIdAsString)); + Event event = getService().getEvent(eventId); if (event != null) { for (CourseArea courseArea : event.getVenue().getCourseAreas()) { - if (!visibleCourseAreaIdsAsString.contains(courseArea.getId().toString())) { + if (!visibleCourseAreaIds.contains(courseArea.getId())) { continue; } for (Leaderboard leaderboard : getService().getLeaderboards().values()) { diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/CourseAreaDTO.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/CourseAreaDTO.java index 8cc6a250306..fdbcabfe611 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/CourseAreaDTO.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/CourseAreaDTO.java @@ -1,11 +1,13 @@ package com.sap.sailing.gwt.ui.shared; +import java.util.UUID; + import com.google.gwt.user.client.rpc.IsSerializable; import com.sap.sailing.domain.common.dto.NamedDTO; public class CourseAreaDTO extends NamedDTO implements IsSerializable { private static final long serialVersionUID = -5279690838452265454L; - public String uuidAsString; + public UUID id; public CourseAreaDTO() { } diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/EventDTO.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/EventDTO.java index baa9f68870d..5cb78d250b4 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/EventDTO.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/EventDTO.java @@ -3,6 +3,7 @@ package com.sap.sailing.gwt.ui.shared; import java.util.ArrayList; import java.util.Date; import java.util.List; +import java.util.UUID; import com.google.gwt.user.client.rpc.IsSerializable; import com.sap.sailing.domain.common.dto.NamedDTO; @@ -13,7 +14,7 @@ public class EventDTO extends NamedDTO implements IsSerializable { public VenueDTO venue; public String publicationUrl; public boolean isPublic; - public String id; + public UUID id; // maybe temporary: as long it's not clear how a leaderboard group relates to a sailing event public LeaderboardGroupDTO leaderboardGroup; diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/RegattaDTO.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/RegattaDTO.java index f5d211a14f4..34858241c06 100755 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/RegattaDTO.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/RegattaDTO.java @@ -2,6 +2,7 @@ package com.sap.sailing.gwt.ui.shared; import java.util.Date; import java.util.List; +import java.util.UUID; import com.sap.sailing.domain.common.RegattaIdentifier; import com.sap.sailing.domain.common.RegattaName; @@ -19,7 +20,7 @@ public class RegattaDTO extends NamedDTO { public List races; public List series; public ScoringSchemeType scoringScheme; - public String defaultCourseAreaUuidAsString; + public UUID defaultCourseAreaUuid; public String defaultCourseAreaName; public DeviceConfigurationDTO.RegattaConfigurationDTO configuration; diff --git a/java/com.sap.sailing.gwt.ui/src/main/resources/com/sap/sailing/gwt/ui/AdminConsole.gwt.xml b/java/com.sap.sailing.gwt.ui/src/main/resources/com/sap/sailing/gwt/ui/AdminConsole.gwt.xml index e64a6c0eae0..b8b70998d66 100755 --- a/java/com.sap.sailing.gwt.ui/src/main/resources/com/sap/sailing/gwt/ui/AdminConsole.gwt.xml +++ b/java/com.sap.sailing.gwt.ui/src/main/resources/com/sap/sailing/gwt/ui/AdminConsole.gwt.xml @@ -1,62 +1,65 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/java/com.sap.sailing.gwt.ui/src/main/resources/com/sap/sailing/gwt/ui/EmulatedJRE.gwt.xml b/java/com.sap.sailing.gwt.ui/src/main/resources/com/sap/sailing/gwt/ui/EmulatedJRE.gwt.xml new file mode 100644 index 00000000000..91be341f7ed --- /dev/null +++ b/java/com.sap.sailing.gwt.ui/src/main/resources/com/sap/sailing/gwt/ui/EmulatedJRE.gwt.xml @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/java/com.sap.sailing.gwt.ui/src/main/resources/com/sap/sailing/gwt/ui/Leaderboard.gwt.xml b/java/com.sap.sailing.gwt.ui/src/main/resources/com/sap/sailing/gwt/ui/Leaderboard.gwt.xml index ed6070794c0..81857fd9dc0 100755 --- a/java/com.sap.sailing.gwt.ui/src/main/resources/com/sap/sailing/gwt/ui/Leaderboard.gwt.xml +++ b/java/com.sap.sailing.gwt.ui/src/main/resources/com/sap/sailing/gwt/ui/Leaderboard.gwt.xml @@ -1,38 +1,39 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/java/com.sap.sailing.gwt.ui/src/main/resources/com/sap/sailing/gwt/ui/LeaderboardEditing.gwt.xml b/java/com.sap.sailing.gwt.ui/src/main/resources/com/sap/sailing/gwt/ui/LeaderboardEditing.gwt.xml index db38dd6c9f0..f76e0e11dd7 100755 --- a/java/com.sap.sailing.gwt.ui/src/main/resources/com/sap/sailing/gwt/ui/LeaderboardEditing.gwt.xml +++ b/java/com.sap.sailing.gwt.ui/src/main/resources/com/sap/sailing/gwt/ui/LeaderboardEditing.gwt.xml @@ -1,38 +1,39 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/java/com.sap.sailing.gwt.ui/src/main/resources/com/sap/sailing/gwt/ui/PolarSheets.gwt.xml b/java/com.sap.sailing.gwt.ui/src/main/resources/com/sap/sailing/gwt/ui/PolarSheets.gwt.xml index 32798e7f5a4..0904a219b80 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/resources/com/sap/sailing/gwt/ui/PolarSheets.gwt.xml +++ b/java/com.sap.sailing.gwt.ui/src/main/resources/com/sap/sailing/gwt/ui/PolarSheets.gwt.xml @@ -1,32 +1,33 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/java/com.sap.sailing.gwt.ui/src/main/resources/com/sap/sailing/gwt/ui/RaceBoard.gwt.xml b/java/com.sap.sailing.gwt.ui/src/main/resources/com/sap/sailing/gwt/ui/RaceBoard.gwt.xml index 48ab24e32bf..393ecfb1257 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/resources/com/sap/sailing/gwt/ui/RaceBoard.gwt.xml +++ b/java/com.sap.sailing.gwt.ui/src/main/resources/com/sap/sailing/gwt/ui/RaceBoard.gwt.xml @@ -1,43 +1,44 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/java/com.sap.sailing.gwt.ui/src/main/resources/com/sap/sailing/gwt/ui/RegattaOverview.gwt.xml b/java/com.sap.sailing.gwt.ui/src/main/resources/com/sap/sailing/gwt/ui/RegattaOverview.gwt.xml index 61a9e2ba218..d174e9fd027 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/resources/com/sap/sailing/gwt/ui/RegattaOverview.gwt.xml +++ b/java/com.sap.sailing.gwt.ui/src/main/resources/com/sap/sailing/gwt/ui/RegattaOverview.gwt.xml @@ -1,50 +1,51 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/java/com.sap.sailing.gwt.ui/src/main/resources/com/sap/sailing/gwt/ui/Simulator.gwt.xml b/java/com.sap.sailing.gwt.ui/src/main/resources/com/sap/sailing/gwt/ui/Simulator.gwt.xml index 5383982b2f6..5a2e5d51045 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/resources/com/sap/sailing/gwt/ui/Simulator.gwt.xml +++ b/java/com.sap.sailing.gwt.ui/src/main/resources/com/sap/sailing/gwt/ui/Simulator.gwt.xml @@ -1,48 +1,49 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/java/com.sap.sailing.gwt.ui/src/main/resources/com/sap/sailing/gwt/ui/Spectator.gwt.xml b/java/com.sap.sailing.gwt.ui/src/main/resources/com/sap/sailing/gwt/ui/Spectator.gwt.xml index 7ce9f733acc..01d6348116d 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/resources/com/sap/sailing/gwt/ui/Spectator.gwt.xml +++ b/java/com.sap.sailing.gwt.ui/src/main/resources/com/sap/sailing/gwt/ui/Spectator.gwt.xml @@ -1,35 +1,36 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/java/com.sap.sailing.gwt.ui/src/main/resources/com/sap/sailing/gwt/ui/TvView.gwt.xml b/java/com.sap.sailing.gwt.ui/src/main/resources/com/sap/sailing/gwt/ui/TvView.gwt.xml index dcec5f271d6..414e7cdf8f7 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/resources/com/sap/sailing/gwt/ui/TvView.gwt.xml +++ b/java/com.sap.sailing.gwt.ui/src/main/resources/com/sap/sailing/gwt/ui/TvView.gwt.xml @@ -1,42 +1,43 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/java/com.sap.sailing.gwt.ui/src/main/resources/com/sap/sailing/gwt/ui/UserManagement.gwt.xml b/java/com.sap.sailing.gwt.ui/src/main/resources/com/sap/sailing/gwt/ui/UserManagement.gwt.xml index f022fb37fd8..39260e86f7a 100755 --- a/java/com.sap.sailing.gwt.ui/src/main/resources/com/sap/sailing/gwt/ui/UserManagement.gwt.xml +++ b/java/com.sap.sailing.gwt.ui/src/main/resources/com/sap/sailing/gwt/ui/UserManagement.gwt.xml @@ -1,34 +1,35 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/java/com.sap.sailing.gwt.ui/src/main/resources/com/sap/sailing/gwt/ui/VideoPopup.gwt.xml b/java/com.sap.sailing.gwt.ui/src/main/resources/com/sap/sailing/gwt/ui/VideoPopup.gwt.xml index 08ae1a4fdc3..d8d0b1f0d45 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/resources/com/sap/sailing/gwt/ui/VideoPopup.gwt.xml +++ b/java/com.sap.sailing.gwt.ui/src/main/resources/com/sap/sailing/gwt/ui/VideoPopup.gwt.xml @@ -1,15 +1,16 @@ - - - - - - - - - - - - - + + + + + + + + + + + + + + \ No newline at end of file diff --git a/java/com.sap.sailing.gwt.ui/src/main/resources/com/sap/sailing/gwt/ui/YoutubePopup.gwt.xml b/java/com.sap.sailing.gwt.ui/src/main/resources/com/sap/sailing/gwt/ui/YoutubePopup.gwt.xml index 3b4ff9a5176..b004549a661 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/resources/com/sap/sailing/gwt/ui/YoutubePopup.gwt.xml +++ b/java/com.sap.sailing.gwt.ui/src/main/resources/com/sap/sailing/gwt/ui/YoutubePopup.gwt.xml @@ -3,6 +3,7 @@ + Date: Sat, 7 Dec 2013 16:06:02 +0100 Subject: [PATCH 07/20] # minor fixes # preparation for integration of polling --- .../gwt/ui/server/SailingServiceImpl.java | 2 +- .../app/data/OnlineDataManager.java | 5 ++- .../PreferencesDeviceConfigurationLoader.java | 2 +- .../racelog/impl/RaceLogEventsCallback.java | 8 +++-- .../sending/EventPersistenceManager.java | 8 +++-- .../app/services/sending/EventSenderTask.java | 4 +-- .../services/sending/EventSendingService.java | 36 ++++++++++++++----- .../app/services/sending/RaceEventSender.java | 2 +- .../services/sending/ServerReplyCallback.java | 4 ++- .../app/ui/utils/FlagPoleStateRenderer.java | 2 +- 10 files changed, 51 insertions(+), 22 deletions(-) diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/server/SailingServiceImpl.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/server/SailingServiceImpl.java index 518628e0420..5f832c5e86e 100755 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/server/SailingServiceImpl.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/server/SailingServiceImpl.java @@ -3545,7 +3545,7 @@ public class SailingServiceImpl extends ProxiedRemoteServiceServlet implements S if (result == null) { return null; } - return new Pair(result.getA().asDate(), result.getB()); + return new Pair(result.getA() == null ? null : result.getA().asDate(), result.getB()); } } \ No newline at end of file diff --git a/mobile/com.sap.sailing.racecommittee.app/src/com/sap/sailing/racecommittee/app/data/OnlineDataManager.java b/mobile/com.sap.sailing.racecommittee.app/src/com/sap/sailing/racecommittee/app/data/OnlineDataManager.java index b8aefb61040..844b162968e 100644 --- a/mobile/com.sap.sailing.racecommittee.app/src/com/sap/sailing/racecommittee/app/data/OnlineDataManager.java +++ b/mobile/com.sap.sailing.racecommittee.app/src/com/sap/sailing/racecommittee/app/data/OnlineDataManager.java @@ -232,9 +232,12 @@ public class OnlineDataManager extends DataManager { DataHandler handler = new NullDataHandler(); DataParser parser = new DeviceConfigurationParser(DeviceConfigurationJsonDeserializer.create()); + String encodedIdentifier = URLEncoder.encode(identifier.getClientIdentifier()); + encodedIdentifier = encodedIdentifier.replace("+", "%20"); + return new OnlineDataLoader( context, - new URL(preferences.getServerBaseURL() + "/sailingserver/rc/configuration?client="+ identifier.getClientIdentifier()), + new URL(preferences.getServerBaseURL() + "/sailingserver/rc/configuration?client="+ encodedIdentifier), parser, handler); } }); diff --git a/mobile/com.sap.sailing.racecommittee.app/src/com/sap/sailing/racecommittee/app/domain/configuration/impl/PreferencesDeviceConfigurationLoader.java b/mobile/com.sap.sailing.racecommittee.app/src/com/sap/sailing/racecommittee/app/domain/configuration/impl/PreferencesDeviceConfigurationLoader.java index e2050da8db5..03d8d74e52e 100644 --- a/mobile/com.sap.sailing.racecommittee.app/src/com/sap/sailing/racecommittee/app/domain/configuration/impl/PreferencesDeviceConfigurationLoader.java +++ b/mobile/com.sap.sailing.racecommittee.app/src/com/sap/sailing/racecommittee/app/domain/configuration/impl/PreferencesDeviceConfigurationLoader.java @@ -55,7 +55,7 @@ public class PreferencesDeviceConfigurationLoader implements ConfigurationLoader if (regattaConfigurationLoader != null) { regattaConfigurationLoader.store(); - logApply("regatta configuration", configuration.getRegattaConfiguration()); + logApply("regatta configuration", "[object]"); } if (configuration.getAllowedCourseAreaNames() != null) { diff --git a/mobile/com.sap.sailing.racecommittee.app/src/com/sap/sailing/racecommittee/app/domain/racelog/impl/RaceLogEventsCallback.java b/mobile/com.sap.sailing.racecommittee.app/src/com/sap/sailing/racecommittee/app/domain/racelog/impl/RaceLogEventsCallback.java index 8cd8ea12f4f..76669c7f407 100644 --- a/mobile/com.sap.sailing.racecommittee.app/src/com/sap/sailing/racecommittee/app/domain/racelog/impl/RaceLogEventsCallback.java +++ b/mobile/com.sap.sailing.racecommittee.app/src/com/sap/sailing/racecommittee/app/domain/racelog/impl/RaceLogEventsCallback.java @@ -2,8 +2,10 @@ package com.sap.sailing.racecommittee.app.domain.racelog.impl; import java.io.InputStream; import java.io.InputStreamReader; +import java.io.Serializable; import java.util.ArrayList; import java.util.List; +import java.util.Set; import org.json.simple.JSONArray; import org.json.simple.JSONObject; @@ -27,14 +29,14 @@ public class RaceLogEventsCallback implements ServerReplyCallback { private static final String TAG = RaceLogEventsCallback.class.getName(); @Override - public void onReply(Intent originalIntent, Context context, InputStream inputStream) { + public void processResponse(Intent originalIntent, Context context, InputStream responseStream, Set suppressedEvents) { ReadonlyDataManager dataManager = DataManager.create(context); final List eventsToAdd = new ArrayList(); SharedDomainFactory domainFactory = DataManager.create(context).getDataStore().getDomainFactory(); JSONParser parser = new JSONParser(); try { - JSONArray eventsToAddAsJson = (JSONArray) parser.parse(new InputStreamReader(inputStream)); + JSONArray eventsToAddAsJson = (JSONArray) parser.parse(new InputStreamReader(responseStream)); for (Object o : eventsToAddAsJson) { try { RaceLogEvent eventToAdd = RaceLogEventDeserializer.create(domainFactory).deserialize((JSONObject) o); @@ -45,7 +47,6 @@ public class RaceLogEventsCallback implements ServerReplyCallback { } } catch (Exception e) { ExLog.e(TAG, "Error parsing server response"); - //ExLog.ex(TAG, e); } String raceId = originalIntent.getStringExtra(AppConstants.RACE_ID_KEY); @@ -54,6 +55,7 @@ public class RaceLogEventsCallback implements ServerReplyCallback { if (raceLog != null) { ExLog.i(TAG, "Successfully retrieved race log for race ID " + raceId); for (RaceLogEvent eventToAddToRaceLog : eventsToAdd) { + suppressedEvents.add(eventToAddToRaceLog.getId()); raceLog.add(eventToAddToRaceLog); ExLog.i(TAG, "added event " + eventToAddToRaceLog.toString() + " to client's race log"); } diff --git a/mobile/com.sap.sailing.racecommittee.app/src/com/sap/sailing/racecommittee/app/services/sending/EventPersistenceManager.java b/mobile/com.sap.sailing.racecommittee.app/src/com/sap/sailing/racecommittee/app/services/sending/EventPersistenceManager.java index 1d741ecda32..6bba00e5946 100644 --- a/mobile/com.sap.sailing.racecommittee.app/src/com/sap/sailing/racecommittee/app/services/sending/EventPersistenceManager.java +++ b/mobile/com.sap.sailing.racecommittee.app/src/com/sap/sailing/racecommittee/app/services/sending/EventPersistenceManager.java @@ -141,8 +141,10 @@ public class EventPersistenceManager { } } + // We are passing no event id, because we know it used to suppress event sending and + // we want this event to be sent. Intent eventIntent = EventSendingService.createEventIntent(context, url, raceId, - URLDecoder.decode(serializedEventAsUrlEncodedJson), callbackClass); + null, URLDecoder.decode(serializedEventAsUrlEncodedJson), callbackClass); if (eventIntent != null) { delayedIntents.add(eventIntent); } @@ -168,9 +170,9 @@ public class EventPersistenceManager { ExLog.i(TAG, "Event didn't need to be readded. Same event already in the log"); } } catch (JsonDeserializationException e) { - ExLog.w(TAG, String.format("Error readding event to race log: %s", e.toString())); + ExLog.w(TAG, String.format("Error while readding event to race log: %s", e.toString())); } catch (ParseException e) { - ExLog.w(TAG, String.format("Error readding event to race log: %s", e.toString())); + ExLog.w(TAG, String.format("Error while readding event to race log: %s", e.toString())); } } diff --git a/mobile/com.sap.sailing.racecommittee.app/src/com/sap/sailing/racecommittee/app/services/sending/EventSenderTask.java b/mobile/com.sap.sailing.racecommittee.app/src/com/sap/sailing/racecommittee/app/services/sending/EventSenderTask.java index cdc4254406e..179bf793bd8 100755 --- a/mobile/com.sap.sailing.racecommittee.app/src/com/sap/sailing/racecommittee/app/services/sending/EventSenderTask.java +++ b/mobile/com.sap.sailing.racecommittee.app/src/com/sap/sailing/racecommittee/app/services/sending/EventSenderTask.java @@ -18,7 +18,7 @@ public class EventSenderTask extends AsyncTask resultTriple) { super.onPostExecute(resultTriple); - listener.onResult(resultTriple.getA(), resultTriple.getB(), resultTriple.getC()); + listener.onEventSent(resultTriple.getA(), resultTriple.getB(), resultTriple.getC()); } } diff --git a/mobile/com.sap.sailing.racecommittee.app/src/com/sap/sailing/racecommittee/app/services/sending/EventSendingService.java b/mobile/com.sap.sailing.racecommittee.app/src/com/sap/sailing/racecommittee/app/services/sending/EventSendingService.java index 9180854d76b..b3d692321b0 100644 --- a/mobile/com.sap.sailing.racecommittee.app/src/com/sap/sailing/racecommittee/app/services/sending/EventSendingService.java +++ b/mobile/com.sap.sailing.racecommittee.app/src/com/sap/sailing/racecommittee/app/services/sending/EventSendingService.java @@ -6,7 +6,9 @@ import java.io.Serializable; import java.net.URLEncoder; import java.util.Calendar; import java.util.Date; +import java.util.HashSet; import java.util.List; +import java.util.Set; import java.util.UUID; import android.app.Service; @@ -50,6 +52,8 @@ public class EventSendingService extends Service implements EventSendingListener private final IBinder mBinder = new EventSendingBinder(); private EventPersistenceManager persistenceManager; private boolean isHandlerSet; + + private Set suppressedEventIds = new HashSet(); private EventSendingServiceLogger serviceLogger = new EventSendingServiceLogger() { @Override @@ -116,7 +120,7 @@ public class EventSendingService extends Service implements EventSendingListener * the class of the callback which should process the server reply * @return the intent that shall be sent to the EventSendingService */ - public static Intent createEventIntent(Context context, ManagedRace race, String serializedEventAsJson, + public static Intent createEventIntent(Context context, ManagedRace race, Serializable eventId, String serializedEventAsJson, Class callbackClass) { String url = String.format("%s/sailingserver/rc/racelog?"+ RaceLogServletConstants.PARAMS_LEADERBOARD_NAME+"=%s&"+ @@ -125,19 +129,30 @@ public class EventSendingService extends Service implements EventSendingListener RaceLogServletConstants.PARAMS_CLIENT_UUID+"=%s", AppPreferences.on(context).getServerBaseURL(), URLEncoder.encode(race.getRaceGroup().getName()), URLEncoder.encode(race.getName()), URLEncoder.encode(race.getFleet().getName()), uuid); - return createEventIntent(context, url, race.getId(), serializedEventAsJson, callbackClass); + return createEventIntent(context, url, race.getId(), eventId, serializedEventAsJson, callbackClass); } - public static Intent createEventIntent(Context context, String url, Serializable raceId, String serializedEventAsJson, + public static Intent createEventIntent(Context context, String url, Serializable raceId, Serializable eventId, String serializedEventAsJson, Class callbackClass) { Intent eventIntent = new Intent(AppConstants.INTENT_ACTION_SEND_EVENT); eventIntent.putExtra(AppConstants.RACE_ID_KEY, raceId); + eventIntent.putExtra(EXTRAS_EVENT_ID, eventId); eventIntent.putExtra(AppConstants.EXTRAS_JSON_SERIALIZED_EVENT, serializedEventAsJson); eventIntent.putExtra(AppConstants.EXTRAS_URL, url); eventIntent.putExtra(AppConstants.EXTRAS_CALLBACK_CLASS, callbackClass == null ? null : callbackClass.getName()); - ExLog.i(TAG, "Created event " + eventIntent + " for sending to backend"); return eventIntent; } + + private static final String EXTRAS_EVENT_ID = "_EXTRAS_EVENT_ID"; + + private Serializable getEventId(Intent intent) { + Serializable id = intent.getSerializableExtra(EXTRAS_EVENT_ID); + if (id != null) { + return id; + } + ExLog.w(TAG, "Unanble to extract event identifier from event intent."); + return null; + } /* * (non-Javadoc) @@ -213,13 +228,18 @@ public class EventSendingService extends Service implements EventSendingListener if (!AppPreferences.on(this).isSendingActive()) { ExLog.i(TAG, "Sending deactivated. Event will not be sent to server."); } else { - EventSenderTask task = new EventSenderTask(this); - task.execute(intent); + Serializable eventId = getEventId(intent); + if (eventId != null && suppressedEventIds.contains(eventId)) { + ExLog.i(TAG, String.format("Event %s is suppressed, won't be sent.", eventId)); + } else { + EventSenderTask task = new EventSenderTask(this); + task.execute(intent); + } } } @Override - public void onResult(Intent intent, boolean success, InputStream inputStream) { + public void onEventSent(Intent intent, boolean success, InputStream inputStream) { if (!success) { ExLog.w(TAG, "Error while posting intent to server. Will persist intent..."); persistenceManager.persistIntent(intent); @@ -248,7 +268,7 @@ public class EventSendingService extends Service implements EventSendingListener } } if (callback != null) { - callback.onReply(intent, this, inputStream); + callback.processResponse(intent, this, inputStream, suppressedEventIds); } try { inputStream.close(); diff --git a/mobile/com.sap.sailing.racecommittee.app/src/com/sap/sailing/racecommittee/app/services/sending/RaceEventSender.java b/mobile/com.sap.sailing.racecommittee.app/src/com/sap/sailing/racecommittee/app/services/sending/RaceEventSender.java index 361ed007db3..d1b52ea3998 100644 --- a/mobile/com.sap.sailing.racecommittee.app/src/com/sap/sailing/racecommittee/app/services/sending/RaceEventSender.java +++ b/mobile/com.sap.sailing.racecommittee.app/src/com/sap/sailing/racecommittee/app/services/sending/RaceEventSender.java @@ -26,7 +26,7 @@ public class RaceEventSender implements RaceLogChangedListener { public void eventAdded(RaceLogEvent event) { JSONObject serializedEvent = serializer.serialize(event); service.startService( - EventSendingService.createEventIntent(service, race, serializedEvent.toJSONString(), + EventSendingService.createEventIntent(service, race, event.getId(), serializedEvent.toJSONString(), RaceLogEventsCallback.class)); } diff --git a/mobile/com.sap.sailing.racecommittee.app/src/com/sap/sailing/racecommittee/app/services/sending/ServerReplyCallback.java b/mobile/com.sap.sailing.racecommittee.app/src/com/sap/sailing/racecommittee/app/services/sending/ServerReplyCallback.java index ca5ab1d6fef..5fc7d9f55b0 100644 --- a/mobile/com.sap.sailing.racecommittee.app/src/com/sap/sailing/racecommittee/app/services/sending/ServerReplyCallback.java +++ b/mobile/com.sap.sailing.racecommittee.app/src/com/sap/sailing/racecommittee/app/services/sending/ServerReplyCallback.java @@ -1,6 +1,8 @@ package com.sap.sailing.racecommittee.app.services.sending; import java.io.InputStream; +import java.io.Serializable; +import java.util.Set; import android.content.Context; import android.content.Intent; @@ -20,5 +22,5 @@ public interface ServerReplyCallback { /** * The inputStream does not need to be closed by the implementing class. */ - void onReply(Intent originalIntent, Context context, InputStream inputStream); + void processResponse(Intent originalIntent, Context context, InputStream inputStream, Set suppressedEvents); } diff --git a/mobile/com.sap.sailing.racecommittee.app/src/com/sap/sailing/racecommittee/app/ui/utils/FlagPoleStateRenderer.java b/mobile/com.sap.sailing.racecommittee.app/src/com/sap/sailing/racecommittee/app/ui/utils/FlagPoleStateRenderer.java index 599b8838046..44a399c76ee 100644 --- a/mobile/com.sap.sailing.racecommittee.app/src/com/sap/sailing/racecommittee/app/ui/utils/FlagPoleStateRenderer.java +++ b/mobile/com.sap.sailing.racecommittee.app/src/com/sap/sailing/racecommittee/app/ui/utils/FlagPoleStateRenderer.java @@ -68,7 +68,7 @@ public class FlagPoleStateRenderer { Toast.makeText(v.getContext(), upperFlag.toString() + "|" + lowerFlag.toString(), Toast.LENGTH_SHORT).show(); } }); - if (upperFlag == Flags.CLASS) { + if (upperFlag == Flags.CLASS && race.getFleet().getColor() != null) { flagView.setPadding(6, 6, 6, 6); flagView.setBackgroundColor(getFleetColorId()); } From 94399661d5f614e3da46781bbe3251027cc48375 Mon Sep 17 00:00:00 2001 From: Lukas Niemeier Date: Sat, 7 Dec 2013 16:27:52 +0100 Subject: [PATCH 08/20] # fixing the clock display # rewiring of certain ui elements --- .../basic/impl/BasicRacingProcedureImpl.java | 5 ++++- .../app/ui/fragments/RaceInfoFragment.java | 6 ------ .../fragments/dialogs/AbortModeSelectionDialog.java | 12 ++++++++---- .../fragments/raceinfo/BaseRaceInfoRaceFragment.java | 2 +- .../finishing/BaseFinishingRaceFragment.java | 2 +- .../raceinfo/running/BaseRunningRaceFragment.java | 6 ++++-- .../startphase/BaseStartphaseRaceFragment.java | 2 +- .../sailing/racecommittee/app/utils/TimeUtils.java | 11 ++++++++++- 8 files changed, 29 insertions(+), 17 deletions(-) diff --git a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/racelog/state/racingprocedure/basic/impl/BasicRacingProcedureImpl.java b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/racelog/state/racingprocedure/basic/impl/BasicRacingProcedureImpl.java index 5844b57e048..ddd92d664a4 100644 --- a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/racelog/state/racingprocedure/basic/impl/BasicRacingProcedureImpl.java +++ b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/racelog/state/racingprocedure/basic/impl/BasicRacingProcedureImpl.java @@ -1,5 +1,6 @@ package com.sap.sailing.domain.racelog.state.racingprocedure.basic.impl; +import java.util.Arrays; import java.util.Collection; import java.util.Collections; @@ -11,6 +12,8 @@ import com.sap.sailing.domain.racelog.RaceLog; import com.sap.sailing.domain.racelog.RaceLogEventAuthor; import com.sap.sailing.domain.racelog.RaceLogEventFactory; import com.sap.sailing.domain.racelog.state.RaceStateEvent; +import com.sap.sailing.domain.racelog.state.impl.RaceStateEventImpl; +import com.sap.sailing.domain.racelog.state.impl.RaceStateEvents; import com.sap.sailing.domain.racelog.state.racingprocedure.FlagPoleState; import com.sap.sailing.domain.racelog.state.racingprocedure.RacingProcedureChangedListener; import com.sap.sailing.domain.racelog.state.racingprocedure.RacingProcedurePrerequisite; @@ -59,7 +62,7 @@ public class BasicRacingProcedureImpl extends BaseRacingProcedure { @Override protected Collection createStartStateEvents(TimePoint startTime) { - return Collections.emptyList(); + return Arrays.asList(new RaceStateEventImpl(startTime, RaceStateEvents.START)); } } diff --git a/mobile/com.sap.sailing.racecommittee.app/src/com/sap/sailing/racecommittee/app/ui/fragments/RaceInfoFragment.java b/mobile/com.sap.sailing.racecommittee.app/src/com/sap/sailing/racecommittee/app/ui/fragments/RaceInfoFragment.java index 7807d759676..b8ceb748bba 100644 --- a/mobile/com.sap.sailing.racecommittee.app/src/com/sap/sailing/racecommittee/app/ui/fragments/RaceInfoFragment.java +++ b/mobile/com.sap.sailing.racecommittee.app/src/com/sap/sailing/racecommittee/app/ui/fragments/RaceInfoFragment.java @@ -78,12 +78,6 @@ public class RaceInfoFragment extends RaceFragment implements RaceInfoListener { @Override public void onClick(View v) { -/* getRace().getRaceLog().add( - RaceLogEventFactory.INSTANCE.createStartTimeEvent( - MillisecondsTimePoint.now(), - AppPreferences.getAuthor(getActivity()), - getRace().getRaceLog().getCurrentPassId(), - MillisecondsTimePoint.now().plus(3000000)));*/ showCourseDesignDialog(); } }); diff --git a/mobile/com.sap.sailing.racecommittee.app/src/com/sap/sailing/racecommittee/app/ui/fragments/dialogs/AbortModeSelectionDialog.java b/mobile/com.sap.sailing.racecommittee.app/src/com/sap/sailing/racecommittee/app/ui/fragments/dialogs/AbortModeSelectionDialog.java index a2322c55894..b8ae9b02518 100644 --- a/mobile/com.sap.sailing.racecommittee.app/src/com/sap/sailing/racecommittee/app/ui/fragments/dialogs/AbortModeSelectionDialog.java +++ b/mobile/com.sap.sailing.racecommittee.app/src/com/sap/sailing/racecommittee/app/ui/fragments/dialogs/AbortModeSelectionDialog.java @@ -7,8 +7,10 @@ import android.view.View.OnClickListener; import android.view.ViewGroup; import android.widget.ImageButton; +import com.sap.sailing.domain.common.TimePoint; import com.sap.sailing.domain.common.impl.MillisecondsTimePoint; import com.sap.sailing.domain.common.racelog.Flags; +import com.sap.sailing.domain.racelog.state.RaceState; import com.sap.sailing.racecommittee.app.AppConstants; import com.sap.sailing.racecommittee.app.R; import com.sap.sailing.racecommittee.app.logging.ExLog; @@ -92,13 +94,15 @@ public class AbortModeSelectionDialog extends RaceDialogFragment { } private void signalAbort(Flags additionalFlag) { + TimePoint now = MillisecondsTimePoint.now(); + RaceState state = getRaceState(); if (this.abortFlag.equals(Flags.AP)) { - //getRace().getState().getStartProcedure().setPostponed(MillisecondsTimePoint.now(), additionalFlag); - getRace().getState().setAborted(MillisecondsTimePoint.now(), true, additionalFlag); + state.setAborted(now, true, additionalFlag); + } else if (this.abortFlag.equals(Flags.NOVEMBER)) { - //getRace().getState().getStartProcedure().setAbandoned(MillisecondsTimePoint.now(), additionalFlag); - getRace().getState().setAborted(MillisecondsTimePoint.now(), false, additionalFlag); + state.setAborted(now, false, additionalFlag); } + state.setAdvancePass(now); this.dismiss(); } diff --git a/mobile/com.sap.sailing.racecommittee.app/src/com/sap/sailing/racecommittee/app/ui/fragments/raceinfo/BaseRaceInfoRaceFragment.java b/mobile/com.sap.sailing.racecommittee.app/src/com/sap/sailing/racecommittee/app/ui/fragments/raceinfo/BaseRaceInfoRaceFragment.java index d1c23f10c77..5c3c0e819ab 100644 --- a/mobile/com.sap.sailing.racecommittee.app/src/com/sap/sailing/racecommittee/app/ui/fragments/raceinfo/BaseRaceInfoRaceFragment.java +++ b/mobile/com.sap.sailing.racecommittee.app/src/com/sap/sailing/racecommittee/app/ui/fragments/raceinfo/BaseRaceInfoRaceFragment.java @@ -136,7 +136,7 @@ public abstract class BaseRaceInfoRaceFragment Date: Sat, 7 Dec 2013 18:34:32 +0100 Subject: [PATCH 09/20] # added polling --- .../sap/sailing/domain/racelog/RaceLog.java | 17 +- .../racelog/impl/NoAddingRaceLogWrapper.java | 5 + .../domain/racelog/impl/RaceLogImpl.java | 13 +- .../rc/AddEntryToRaceLogJsonPostServlet.java | 81 ++++++--- .../AndroidManifest.xml | 4 +- .../res/values-de/strings.xml | 7 +- .../res/values/preferences.xml | 5 + .../res/values/strings.xml | 7 +- .../res/xml/preference_general.xml | 15 ++ .../racecommittee/app/AppPreferences.java | 46 ++++- .../racecommittee/app/RaceApplication.java | 2 +- .../app/data/http/HttpJsonPostRequest.java | 8 +- .../app/data/http/HttpRequest.java | 5 +- .../racelog/impl/RaceLogEventsCallback.java | 119 ++++++++++--- .../app/services/RaceStateService.java | 12 +- .../app/services/polling/PollingResult.java | 16 ++ .../app/services/polling/RaceLogPoller.java | 168 ++++++++++++++++++ .../services/polling/RaceLogPollerTask.java | 62 +++++++ .../sending/EventPersistenceManager.java | 6 +- .../app/services/sending/EventSenderTask.java | 14 +- .../services/sending/EventSendingService.java | 35 ++-- .../services/sending/ServerReplyCallback.java | 5 +- .../preference/BasePreferenceFragment.java | 6 +- .../preference/GeneralPreferenceFragment.java | 35 ++-- .../preference/RegattaPreferenceFragment.java | 6 + .../app/utils/PreferenceHelper.java | 2 +- 26 files changed, 600 insertions(+), 101 deletions(-) create mode 100644 mobile/com.sap.sailing.racecommittee.app/src/com/sap/sailing/racecommittee/app/services/polling/PollingResult.java create mode 100644 mobile/com.sap.sailing.racecommittee.app/src/com/sap/sailing/racecommittee/app/services/polling/RaceLogPoller.java create mode 100644 mobile/com.sap.sailing.racecommittee.app/src/com/sap/sailing/racecommittee/app/services/polling/RaceLogPollerTask.java diff --git a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/racelog/RaceLog.java b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/racelog/RaceLog.java index 9fcaf733bd6..5a6a248b3b0 100644 --- a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/racelog/RaceLog.java +++ b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/racelog/RaceLog.java @@ -69,15 +69,20 @@ public interface RaceLog extends Track, WithID { Iterable getAllListeners(); /** - * Adds an event to this race log and returns a superset of all race log events (excluding the new - * event) that were added to this race log but not yet returned to the client with ID - * clientId by this method. In general, the list returned is not a true superset but - * equals exactly those events not yet delivered to the client. However, if the server was re-started - * since the client last called this method, and since the underlying data structures are not durably - * stored, the entire set of all race log events would be delivered to the client once. + * Adds an event to this race log and returns {@link RaceLog#getEventsToDeliver(UUID)} + * (excluding the new event) */ Iterable add(RaceLogEvent event, UUID clientId); + /** + * Returns a superset of all race log events that were added to this race log but not yet returned to + * the client with ID clientId by this method. In general, the list returned is not a true + * superset but equals exactly those events not yet delivered to the client. However, if the server + * was re-started since the client last called this method, and since the underlying data structures + * are not durably stored, the entire set of all race log events would be delivered to the client once. + */ + Iterable getEventsToDeliver(UUID clientId); + /** * Returns all {@link #getRawFixes() raw fixes} and marks them as delivered to the client identified by clientId * so that when that ID appears in a subsequent call to {@link #add(RaceLogEvent, UUID)}, the fixes returned by this call diff --git a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/racelog/impl/NoAddingRaceLogWrapper.java b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/racelog/impl/NoAddingRaceLogWrapper.java index 159c52f49c4..026b3482c5d 100644 --- a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/racelog/impl/NoAddingRaceLogWrapper.java +++ b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/racelog/impl/NoAddingRaceLogWrapper.java @@ -189,4 +189,9 @@ public class NoAddingRaceLogWrapper implements RaceLog { public Iterator getRawFixesDescendingIterator(TimePoint startingAt, boolean inclusive) { return innerRaceLog.getRawFixesDescendingIterator(startingAt, inclusive); } + + @Override + public Iterable getEventsToDeliver(UUID clientId) { + return innerRaceLog.getEventsToDeliver(clientId); + } } diff --git a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/racelog/impl/RaceLogImpl.java b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/racelog/impl/RaceLogImpl.java index 2251aabc9e6..840904b68f7 100644 --- a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/racelog/impl/RaceLogImpl.java +++ b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/racelog/impl/RaceLogImpl.java @@ -152,9 +152,18 @@ public class RaceLogImpl extends TrackImpl implements RaceLog { } else { logger.warning(String.format("%s (%s) was not added to log. Ignoring", event, event.getClass().getName())); } + return getEventsToDeliver(clientId, event); + } + + @Override + public Iterable getEventsToDeliver(UUID clientId) { + return getEventsToDeliver(clientId, null); + } + + protected Iterable getEventsToDeliver(UUID clientId, RaceLogEvent suppressedEvent) { // FIXME lock for read getInternalRawFixes? LinkedHashSet stillToDeliverToClient = new LinkedHashSet(getInternalRawFixes()); - stillToDeliverToClient.remove(event); + stillToDeliverToClient.remove(suppressedEvent); Set deliveredToClient = eventsDeliveredToClient.get(clientId); if (deliveredToClient != null) { stillToDeliverToClient.removeAll(deliveredToClient); @@ -163,7 +172,7 @@ public class RaceLogImpl extends TrackImpl implements RaceLog { eventsDeliveredToClient.put(clientId, deliveredToClient); } deliveredToClient.addAll(stillToDeliverToClient); - deliveredToClient.add(event); + deliveredToClient.add(suppressedEvent); return stillToDeliverToClient; } diff --git a/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/impl/rc/AddEntryToRaceLogJsonPostServlet.java b/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/impl/rc/AddEntryToRaceLogJsonPostServlet.java index 825c10c0cd0..e0e5e6b19f5 100644 --- a/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/impl/rc/AddEntryToRaceLogJsonPostServlet.java +++ b/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/impl/rc/AddEntryToRaceLogJsonPostServlet.java @@ -1,5 +1,6 @@ package com.sap.sailing.server.gateway.impl.rc; +import java.io.BufferedReader; import java.io.IOException; import java.util.UUID; import java.util.logging.Logger; @@ -16,6 +17,7 @@ import org.json.simple.parser.ParseException; import com.sap.sailing.domain.base.Fleet; import com.sap.sailing.domain.base.RaceColumn; import com.sap.sailing.domain.leaderboard.Leaderboard; +import com.sap.sailing.domain.racelog.RaceLog; import com.sap.sailing.domain.racelog.RaceLogEvent; import com.sap.sailing.domain.racelog.RaceLogServletConstants; import com.sap.sailing.server.RacingEventService; @@ -63,7 +65,8 @@ public class AddEntryToRaceLogJsonPostServlet extends AbstractJsonHttpServlet { String.format("Missing parameter '%s'.", RaceLogServletConstants.PARAMS_RACE_FLEET_NAME)); return; } - + + logger.fine("Post issued for race log of " + leaderboardName + ", " + raceColumnName + ", " + fleetName); RacingEventService service = getService(); Leaderboard leaderboard = service.getLeaderboardByName(leaderboardName); @@ -84,36 +87,58 @@ public class AddEntryToRaceLogJsonPostServlet extends AbstractJsonHttpServlet { return; } - JsonDeserializer deserializer = RaceLogEventDeserializer.create(getService().getBaseDomainFactory()); - - try { - logger.fine("Post issued for " + leaderboardName + ", " + raceColumnName + ", " + fleetName + " to add a race log event"); - Object requestBody = JSONValue.parseWithException(request.getReader()); - JSONObject requestObject = Helpers.toJSONObjectSafe(requestBody); - logger.fine("JSON requestObject is: " + requestObject.toString()); - RaceLogEvent logEvent = deserializer.deserialize(requestObject); - logger.fine("JSON is deserialized to a RaceLogEvent"); - Iterable eventsToSendBackToClient = raceColumn.getRaceLog(fleet).add(logEvent, clientUuid); - JsonSerializer serializer = RaceLogEventSerializer.create(new CompetitorJsonSerializer()); - ServletOutputStream outputStream = response.getOutputStream(); - boolean first = true; - outputStream.write('['); - for (RaceLogEvent eventToSendBackToClient : eventsToSendBackToClient) { - if (first) { - first = false; - } else { - outputStream.write(','); - } - outputStream.write(serializer.serialize(eventToSendBackToClient).toJSONString().getBytes()); - } - outputStream.write(']'); - } catch (ParseException pe) { - response.sendError(HttpServletResponse.SC_BAD_REQUEST, - String.format("Invalid JSON in request body:\n%s", pe)); - logger.warning(String.format("Exception while parsing post request:\n%s", pe.toString())); + RaceLog raceLog = raceColumn.getRaceLog(fleet); + if (raceLog == null) { + response.sendError(HttpServletResponse.SC_NOT_FOUND, "Race Log not found."); return; } + BufferedReader reader = request.getReader(); + StringBuilder requestBody = new StringBuilder(); + String line = ""; + // TODO: we are remove line feeds here, intented? + while ((line = reader.readLine()) != null) { + requestBody.append(line); + } + reader.close(); + + if (requestBody.length() == 0) { + logger.fine("Client wants to receive server events"); + sendResponse(response, clientUuid, raceLog, raceLog.getEventsToDeliver(clientUuid)); + } else { + try { + logger.fine("Client wants to add a race log event"); + JsonDeserializer deserializer = RaceLogEventDeserializer.create(getService().getBaseDomainFactory()); + Object requestObject = JSONValue.parseWithException(requestBody.toString()); + JSONObject requestJsonObject = Helpers.toJSONObjectSafe(requestObject); + logger.fine("JSON requestObject is: " + requestObject.toString()); + RaceLogEvent logEvent = deserializer.deserialize(requestJsonObject); + logger.fine("JSON is deserialized to a RaceLogEvent"); + Iterable eventsToSendBackToClient = raceLog.add(logEvent, clientUuid); + sendResponse(response, clientUuid, raceLog, eventsToSendBackToClient); + } catch (ParseException pe) { + response.sendError(HttpServletResponse.SC_BAD_REQUEST, + String.format("Invalid JSON in request body:\n%s", pe)); + logger.warning(String.format("Exception while parsing post request: %s", pe.toString())); + } + } + } + + protected void sendResponse(HttpServletResponse response, final UUID clientUuid, RaceLog raceLog, + Iterable eventsToSendBackToClient) throws IOException { + JsonSerializer serializer = RaceLogEventSerializer.create(new CompetitorJsonSerializer()); + ServletOutputStream outputStream = response.getOutputStream(); + boolean first = true; + outputStream.write('['); + for (RaceLogEvent eventToSendBackToClient : eventsToSendBackToClient) { + if (first) { + first = false; + } else { + outputStream.write(','); + } + outputStream.write(serializer.serialize(eventToSendBackToClient).toJSONString().getBytes()); + } + outputStream.write(']'); } } diff --git a/mobile/com.sap.sailing.racecommittee.app/AndroidManifest.xml b/mobile/com.sap.sailing.racecommittee.app/AndroidManifest.xml index 7f13622f12d..ddbdd10037c 100644 --- a/mobile/com.sap.sailing.racecommittee.app/AndroidManifest.xml +++ b/mobile/com.sap.sailing.racecommittee.app/AndroidManifest.xml @@ -1,8 +1,8 @@ + android:versionCode="4" + android:versionName="4.1 - Khalid" > Windeingaben speichern - Allgemeine Einstellungen + Weitere Einstellungen Verwaltete Rennbahnen Sprache auswählen Sprache auswählen. Eventuell muss die App neugestartet werden. @@ -145,6 +145,11 @@ Zum Übernehmen der Änderung bitte Aktion \'Neuladen\' durchführen. Server URL Empfänger der Ergebnislisten + + Polling Einstellungen + Aktiviere Polling + Wenn aktiv wird im festgelegten Intervall Änderungen an den Rennen beim Server abgefragt. + Polling Intervall (Minuten) Kompass diff --git a/mobile/com.sap.sailing.racecommittee.app/res/values/preferences.xml b/mobile/com.sap.sailing.racecommittee.app/res/values/preferences.xml index 817b37d1787..bd30953486b 100644 --- a/mobile/com.sap.sailing.racecommittee.app/res/values/preferences.xml +++ b/mobile/com.sap.sailing.racecommittee.app/res/values/preferences.xml @@ -23,6 +23,11 @@ mailRecipientPreference lukas.niemeier@sap.com + + pollingActivePreference + true + pollingIntervalPreference + 2 defaultRacingProcedureType RRS26 diff --git a/mobile/com.sap.sailing.racecommittee.app/res/values/strings.xml b/mobile/com.sap.sailing.racecommittee.app/res/values/strings.xml index 92ae61f4201..9c0eed31eef 100644 --- a/mobile/com.sap.sailing.racecommittee.app/res/values/strings.xml +++ b/mobile/com.sap.sailing.racecommittee.app/res/values/strings.xml @@ -126,7 +126,7 @@ Store wind - General + Other Managed Course Areas Select Language Select the language. You might need to restart the app to have changes applied. @@ -140,6 +140,11 @@ Webservice URL Positioning mail recipient + Polling + Activate Polling + When active the server will be polled for changes. + Polling Interval (minutes) + Compass Needle diff --git a/mobile/com.sap.sailing.racecommittee.app/res/xml/preference_general.xml b/mobile/com.sap.sailing.racecommittee.app/res/xml/preference_general.xml index 0211ba5ff5a..ae0c65239c3 100644 --- a/mobile/com.sap.sailing.racecommittee.app/res/xml/preference_general.xml +++ b/mobile/com.sap.sailing.racecommittee.app/res/xml/preference_general.xml @@ -29,6 +29,21 @@ + + + + + + + + pollingActiveChangedListeners = new HashSet(); + + private OnSharedPreferenceChangeListener pollingActiveChangedListener = new OnSharedPreferenceChangeListener() { + @Override + public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) { + if (key(R.string.preference_polling_active_key).equals(key)) { + for (PollingActiveChangedListener listener : pollingActiveChangedListeners) { + listener.onPollingActiveChanged(isPollingActive()); + } + } + } + }; + + public void registerPollingActiveChangedListener(final PollingActiveChangedListener listener) { + if (pollingActiveChangedListeners.isEmpty()) { + preferences.registerOnSharedPreferenceChangeListener(pollingActiveChangedListener); + } + pollingActiveChangedListeners.add(listener); + } + + public void unregisterPollingActiveChangedListener(PollingActiveChangedListener listener) { + pollingActiveChangedListeners.remove(listener); + if (pollingActiveChangedListeners.isEmpty()) { + preferences.unregisterOnSharedPreferenceChangeListener(pollingActiveChangedListener); + } + } } diff --git a/mobile/com.sap.sailing.racecommittee.app/src/com/sap/sailing/racecommittee/app/RaceApplication.java b/mobile/com.sap.sailing.racecommittee.app/src/com/sap/sailing/racecommittee/app/RaceApplication.java index 4c379f40c6d..960d2770a5e 100644 --- a/mobile/com.sap.sailing.racecommittee.app/src/com/sap/sailing/racecommittee/app/RaceApplication.java +++ b/mobile/com.sap.sailing.racecommittee.app/src/com/sap/sailing/racecommittee/app/RaceApplication.java @@ -31,7 +31,7 @@ public class RaceApplication extends Application { @Override public void onCreate() { super.onCreate(); - ExLog.i(TAG, "Application is starting"); + ExLog.i(TAG, "Application is starting."); Thread.setDefaultUncaughtExceptionHandler(new LoggingExceptionHandler(Thread .getDefaultUncaughtExceptionHandler())); diff --git a/mobile/com.sap.sailing.racecommittee.app/src/com/sap/sailing/racecommittee/app/data/http/HttpJsonPostRequest.java b/mobile/com.sap.sailing.racecommittee.app/src/com/sap/sailing/racecommittee/app/data/http/HttpJsonPostRequest.java index 426bfc5a95a..4836beafdc7 100644 --- a/mobile/com.sap.sailing.racecommittee.app/src/com/sap/sailing/racecommittee/app/data/http/HttpJsonPostRequest.java +++ b/mobile/com.sap.sailing.racecommittee.app/src/com/sap/sailing/racecommittee/app/data/http/HttpJsonPostRequest.java @@ -13,6 +13,10 @@ public class HttpJsonPostRequest extends HttpRequest { private String requestBody; + public HttpJsonPostRequest(URL requestUrl) { + this(requestUrl, null); + } + public HttpJsonPostRequest(URL requestUrl, String body) { super(requestUrl); this.requestBody = body; @@ -34,6 +38,8 @@ public class HttpJsonPostRequest extends HttpRequest { } private void sendBody(OutputStream outputStream) throws IOException { - outputStream.write(requestBody.getBytes(Charset.forName("UTF-8"))); + if (requestBody != null) { + outputStream.write(requestBody.getBytes(Charset.forName("UTF-8"))); + } } } diff --git a/mobile/com.sap.sailing.racecommittee.app/src/com/sap/sailing/racecommittee/app/data/http/HttpRequest.java b/mobile/com.sap.sailing.racecommittee.app/src/com/sap/sailing/racecommittee/app/data/http/HttpRequest.java index 3664df95885..a6ef9939241 100644 --- a/mobile/com.sap.sailing.racecommittee.app/src/com/sap/sailing/racecommittee/app/data/http/HttpRequest.java +++ b/mobile/com.sap.sailing.racecommittee.app/src/com/sap/sailing/racecommittee/app/data/http/HttpRequest.java @@ -62,7 +62,7 @@ public abstract class HttpRequest { * Returns a copied {@link InputStream} of the server's response. * You must close this stream when done. */ - public InputStream execute() throws Exception { + public InputStream execute() throws IOException { ExLog.i(TAG, String.format("(Request %d) Executing HTTP request on %s.", this.hashCode(), url)); HttpURLConnection connection = (HttpURLConnection) url.openConnection(); @@ -94,6 +94,9 @@ public abstract class HttpRequest { connection.disconnect(); return copiedResponseInputStream; + } catch (IOException e) { + ExLog.i(TAG, String.format("(Request %d) HTTP request failed.", this.hashCode())); + throw e; } finally { if (responseInputStream != null) { responseInputStream.close(); diff --git a/mobile/com.sap.sailing.racecommittee.app/src/com/sap/sailing/racecommittee/app/domain/racelog/impl/RaceLogEventsCallback.java b/mobile/com.sap.sailing.racecommittee.app/src/com/sap/sailing/racecommittee/app/domain/racelog/impl/RaceLogEventsCallback.java index 76669c7f407..a7c4638d20e 100644 --- a/mobile/com.sap.sailing.racecommittee.app/src/com/sap/sailing/racecommittee/app/domain/racelog/impl/RaceLogEventsCallback.java +++ b/mobile/com.sap.sailing.racecommittee.app/src/com/sap/sailing/racecommittee/app/domain/racelog/impl/RaceLogEventsCallback.java @@ -5,41 +5,65 @@ import java.io.InputStreamReader; import java.io.Serializable; import java.util.ArrayList; import java.util.List; -import java.util.Set; import org.json.simple.JSONArray; import org.json.simple.JSONObject; import org.json.simple.parser.JSONParser; +import android.content.ComponentName; import android.content.Context; import android.content.Intent; +import android.content.ServiceConnection; +import android.os.IBinder; import com.sap.sailing.domain.base.SharedDomainFactory; import com.sap.sailing.domain.racelog.RaceLog; import com.sap.sailing.domain.racelog.RaceLogEvent; -import com.sap.sailing.racecommittee.app.AppConstants; import com.sap.sailing.racecommittee.app.data.DataManager; import com.sap.sailing.racecommittee.app.data.ReadonlyDataManager; import com.sap.sailing.racecommittee.app.logging.ExLog; +import com.sap.sailing.racecommittee.app.services.sending.EventSendingService; +import com.sap.sailing.racecommittee.app.services.sending.EventSendingService.EventSendingBinder; import com.sap.sailing.racecommittee.app.services.sending.ServerReplyCallback; import com.sap.sailing.server.gateway.deserialization.JsonDeserializationException; import com.sap.sailing.server.gateway.deserialization.racelog.impl.RaceLogEventDeserializer; +/** + *

+ * Processes (and closes) the {@link InputStream} when posting a {@link RaceLogEvent} to the server. + *

+ *

+ * If the server sends back some {@link RaceLogEvent}s the {@link RaceLogEventsCallback} will try to reach the + * {@link EventSendingService} and tell him about the server-side {@link RaceLogEvent}s that will be added to + * the {@link RaceLog}. This gives the {@link EventSendingService} the chance to ignore them the next time they + * come around. The execution of the {@link RaceLogEventsCallback} will be deferred until the service is bound. + *

+ *

+ * If the {@link EventSendingService} cannot be reached (this is a really bad sign) the events are added to the + * {@link RaceLogEvent} immediately. + *

+ */ public class RaceLogEventsCallback implements ServerReplyCallback { private static final String TAG = RaceLogEventsCallback.class.getName(); @Override - public void processResponse(Intent originalIntent, Context context, InputStream responseStream, Set suppressedEvents) { + public void processResponse(Context context, InputStream responseStream, Serializable raceId) { ReadonlyDataManager dataManager = DataManager.create(context); - final List eventsToAdd = new ArrayList(); - SharedDomainFactory domainFactory = DataManager.create(context).getDataStore().getDomainFactory(); + List eventsToAdd = parseResponse(dataManager, responseStream); + addEvents(context, raceId, dataManager, eventsToAdd); + } + + protected List parseResponse(ReadonlyDataManager dataManager, InputStream responseStream) { + List eventsToAdd = new ArrayList(); JSONParser parser = new JSONParser(); try { JSONArray eventsToAddAsJson = (JSONArray) parser.parse(new InputStreamReader(responseStream)); + SharedDomainFactory domainFactory = dataManager.getDataStore().getDomainFactory(); + RaceLogEventDeserializer deserializer = RaceLogEventDeserializer.create(domainFactory); for (Object o : eventsToAddAsJson) { try { - RaceLogEvent eventToAdd = RaceLogEventDeserializer.create(domainFactory).deserialize((JSONObject) o); + RaceLogEvent eventToAdd = deserializer.deserialize((JSONObject) o); eventsToAdd.add(eventToAdd); } catch (JsonDeserializationException e) { ExLog.e(TAG, "Error deserializing Race Log event:\n" + o); @@ -48,23 +72,78 @@ public class RaceLogEventsCallback implements ServerReplyCallback { } catch (Exception e) { ExLog.e(TAG, "Error parsing server response"); } + + return eventsToAdd; + } + + private void addEvents(Context context, Serializable raceId, ReadonlyDataManager dataManager, + List eventsToAdd) { + if (eventsToAdd.isEmpty()) { + ExLog.i(TAG, "No server-side events to add for race " + raceId); + return; + } - String raceId = originalIntent.getStringExtra(AppConstants.RACE_ID_KEY); - if (dataManager.getDataStore().hasRace(raceId)) { - RaceLog raceLog = dataManager.getDataStore().getRace(raceId).getRaceLog(); - if (raceLog != null) { - ExLog.i(TAG, "Successfully retrieved race log for race ID " + raceId); - for (RaceLogEvent eventToAddToRaceLog : eventsToAdd) { - suppressedEvents.add(eventToAddToRaceLog.getId()); - raceLog.add(eventToAddToRaceLog); - ExLog.i(TAG, "added event " + eventToAddToRaceLog.toString() + " to client's race log"); - } - } else { - ExLog.w(TAG, "Couldn't retrieve race log for race ID " + raceId); - } + ExLog.i(TAG, String.format("Server sent %d events to be added for race %s.", eventsToAdd.size(), raceId)); + + if (!dataManager.getDataStore().hasRace(raceId)) { + ExLog.w(TAG, "I have no race " + raceId); + return; + } + RaceLog raceLog = dataManager.getDataStore().getRace(raceId).getRaceLog(); + if (raceLog == null) { + ExLog.w(TAG, "Unable to retrieve race log for race " + raceId); + return; + } + + EventSendingConnection connection = new EventSendingConnection(context, eventsToAdd, raceLog); + if (context.bindService(new Intent(context, EventSendingService.class), connection, + Context.BIND_AUTO_CREATE)) { + // execution deferred until service is bound + ExLog.i(TAG, "Waiting for sending service to be bound."); } else { - ExLog.w(TAG, "There is no race with id " + raceId); + ExLog.e(TAG,"Unable to bind to sending service. Processing server response without suppressing received events..."); + addEvents(eventsToAdd, raceLog, null); } } + protected void addEvents(List eventsToAdd, RaceLog raceLog, EventSendingService sendingService) { + for (RaceLogEvent eventToAddToRaceLog : eventsToAdd) { + if (sendingService != null) { + sendingService.registerEventForSuppression(eventToAddToRaceLog.getId()); + } + raceLog.add(eventToAddToRaceLog); + ExLog.i(TAG, "Added event " + eventToAddToRaceLog.toString() + " to client's race log"); + } + } + + /** + * Connects to the {@link EventSendingService} and continues with execution. The service will be released afterwards. + */ + private class EventSendingConnection implements ServiceConnection { + + private final Context context; + private final List eventsToAdd; + private final RaceLog raceLog; + private EventSendingService sendingService; + + public EventSendingConnection(Context context, List eventsToAdd, RaceLog raceLog) { + this.context = context; + this.eventsToAdd = eventsToAdd; + this.raceLog = raceLog; + } + + @Override + public void onServiceConnected(ComponentName className, IBinder service) { + EventSendingBinder binder = (EventSendingBinder) service; + sendingService = binder.getService(); + ExLog.i(TAG, "Sending service is bound. Continue to process server response..."); + addEvents(eventsToAdd, raceLog, sendingService); + context.unbindService(this); + } + + @Override + public void onServiceDisconnected(ComponentName arg) { + + } + } } diff --git a/mobile/com.sap.sailing.racecommittee.app/src/com/sap/sailing/racecommittee/app/services/RaceStateService.java b/mobile/com.sap.sailing.racecommittee.app/src/com/sap/sailing/racecommittee/app/services/RaceStateService.java index 2de4b5c8ead..4ad95b6a14f 100644 --- a/mobile/com.sap.sailing.racecommittee.app/src/com/sap/sailing/racecommittee/app/services/RaceStateService.java +++ b/mobile/com.sap.sailing.racecommittee.app/src/com/sap/sailing/racecommittee/app/services/RaceStateService.java @@ -33,6 +33,7 @@ import com.sap.sailing.racecommittee.app.data.DataManager; import com.sap.sailing.racecommittee.app.data.ReadonlyDataManager; import com.sap.sailing.racecommittee.app.domain.ManagedRace; import com.sap.sailing.racecommittee.app.logging.ExLog; +import com.sap.sailing.racecommittee.app.services.polling.RaceLogPoller; import com.sap.sailing.racecommittee.app.services.sending.RaceEventSender; import com.sap.sailing.racecommittee.app.ui.activities.LoginActivity; import com.sap.sailing.server.gateway.serialization.JsonSerializer; @@ -65,6 +66,8 @@ public class RaceStateService extends Service { private ReadonlyDataManager dataManager; + private RaceLogPoller poller; + private Map registeredLogListeners; private Map registeredStateEventSchedulers; @@ -79,6 +82,8 @@ public class RaceStateService extends Service { this.alarmManager = (AlarmManager) getSystemService(Context.ALARM_SERVICE); this.dataManager = DataManager.create(this); + this.poller = new RaceLogPoller(this); + this.registeredLogListeners = new HashMap(); this.registeredStateEventSchedulers = new HashMap(); this.managedIntents = new HashMap>>(); @@ -132,6 +137,8 @@ public class RaceStateService extends Service { } private void unregisterAllRaces() { + poller.unregisterAllAndStop(); + for (Entry entry : registeredLogListeners.entrySet()) { entry.getKey().getState().getRaceLog().removeListener(entry.getValue()); } @@ -235,9 +242,12 @@ public class RaceStateService extends Service { RaceLogChangedVisitor logListener = new RaceLogChangedVisitor(sender); state.getRaceLog().addListener(logListener); - // ... register on state changes! + // ... register on state changes... RaceStateEventScheduler stateEventScheduler = new RaceStateEventSchedulerOnService(this, race); state.setStateEventScheduler(stateEventScheduler); + + // ... and register for polling! + poller.register(race); this.registeredLogListeners.put(race, logListener); this.registeredStateEventSchedulers.put(race, stateEventScheduler); diff --git a/mobile/com.sap.sailing.racecommittee.app/src/com/sap/sailing/racecommittee/app/services/polling/PollingResult.java b/mobile/com.sap.sailing.racecommittee.app/src/com/sap/sailing/racecommittee/app/services/polling/PollingResult.java new file mode 100644 index 00000000000..3cc96ca728d --- /dev/null +++ b/mobile/com.sap.sailing.racecommittee.app/src/com/sap/sailing/racecommittee/app/services/polling/PollingResult.java @@ -0,0 +1,16 @@ +package com.sap.sailing.racecommittee.app.services.polling; + +import java.io.InputStream; +import java.io.Serializable; + +import com.sap.sailing.domain.common.impl.Util.Pair; + +public class PollingResult { + public final boolean isSuccess; + public final Pair resultStreamForRaceId; + + public PollingResult(boolean isSuccess, Pair resultStreamForRaceId) { + this.isSuccess = isSuccess; + this.resultStreamForRaceId = resultStreamForRaceId; + } +} diff --git a/mobile/com.sap.sailing.racecommittee.app/src/com/sap/sailing/racecommittee/app/services/polling/RaceLogPoller.java b/mobile/com.sap.sailing.racecommittee.app/src/com/sap/sailing/racecommittee/app/services/polling/RaceLogPoller.java new file mode 100644 index 00000000000..bad7c227004 --- /dev/null +++ b/mobile/com.sap.sailing.racecommittee.app/src/com/sap/sailing/racecommittee/app/services/polling/RaceLogPoller.java @@ -0,0 +1,168 @@ +package com.sap.sailing.racecommittee.app.services.polling; + +import java.io.InputStream; +import java.io.Serializable; +import java.net.MalformedURLException; +import java.net.URL; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; + +import android.content.Context; +import android.os.Handler; +import android.os.Looper; + +import com.sap.sailing.domain.common.impl.Util.Pair; +import com.sap.sailing.racecommittee.app.AppPreferences; +import com.sap.sailing.racecommittee.app.AppPreferences.PollingActiveChangedListener; +import com.sap.sailing.racecommittee.app.domain.ManagedRace; +import com.sap.sailing.racecommittee.app.domain.racelog.impl.RaceLogEventsCallback; +import com.sap.sailing.racecommittee.app.logging.ExLog; +import com.sap.sailing.racecommittee.app.services.polling.RaceLogPollerTask.PollingResultListener; +import com.sap.sailing.racecommittee.app.services.sending.EventSendingService; + +/** + *

+ * Polls for server-side race log changes + *

+ * + *

+ * There is no multi-threading involved, everything will be done on the UI thread. + *

+ */ +public class RaceLogPoller implements PollingActiveChangedListener { + + protected static final String TAG = RaceLogPoller.class.getName(); + + private final Context context; + private final Handler pollingHandler; + private final PollingWorker pollingWorker; + private final Map races; + private final AppPreferences appPreferences; + private boolean hasRacesToPoll; + + public RaceLogPoller(Context context) { + this.context = context; + // We want to use the main (UI) loop + this.pollingHandler = new Handler(Looper.getMainLooper()); + this.pollingWorker = new PollingWorker(this); + this.races = new HashMap(); + this.appPreferences = AppPreferences.on(context); + this.appPreferences.registerPollingActiveChangedListener(this); + this.hasRacesToPoll = false; + } + + public void register(ManagedRace race) { + try { + races.put(race, createURL(race)); + // remove pending pollingWorker, to ensure that we only have one at once + pollingHandler.removeCallbacks(pollingWorker); + long pollingInterval = getPollingIntervalInMs(); + pollingHandler.postDelayed(pollingWorker, pollingInterval); + this.hasRacesToPoll = true; + ExLog.i(TAG, String.format("Registered race %s for polling, will start in %d milliseconds.", race.getId(), + pollingInterval)); + } catch (MalformedURLException e) { + ExLog.e(TAG, String.format("Unable to create polling URL for race %s: %s", race.getId(), e.getMessage())); + } + } + + private URL createURL(ManagedRace race) throws MalformedURLException { + return new URL(EventSendingService.getRaceLogEventSendAndReceiveUrl(context, race.getRaceGroup().getName(), + race.getName(), race.getFleet().getName())); + } + + public void unregisterAllAndStop() { + hasRacesToPoll = false; + pollingHandler.removeCallbacksAndMessages(null); + races.clear(); + appPreferences.unregisterPollingActiveChangedListener(this); + ExLog.i(TAG, "Polling will be stopped."); + } + + protected boolean isPollingActive() { + return hasRacesToPoll && appPreferences.isPollingActive(); + } + + protected long getPollingIntervalInMs() { + return appPreferences.getPollingInterval() * 60 * 1000; + } + + @Override + public void onPollingActiveChanged(boolean isActive) { + if (isActive) { + long pollingInterval = getPollingIntervalInMs(); + pollingHandler.postDelayed(pollingWorker, pollingInterval); + ExLog.i(TAG, String.format("Polling has been activated, will start in %d milliseconds.", pollingInterval)); + } else { + ExLog.i(TAG, "Polling has been deactivated, next polling attempt will be aborted."); + } + }; + + /** + * Will be run on the main (UI) thread! + */ + private static class PollingWorker implements Runnable, PollingResultListener { + + private final RaceLogPoller poller; + private final RaceLogEventsCallback processor; + private RaceLogPollerTask task; + + public PollingWorker(RaceLogPoller poller) { + this.poller = poller; + this.processor = new RaceLogEventsCallback(); + } + + @SuppressWarnings("unchecked") + @Override + public void run() { + ExLog.i(TAG, "Polling for server-side race log changes..."); + if (!poller.isPollingActive()) { + ExLog.i(TAG, "Polling aborted."); + return; + } + + List> queries = getPollingQueries(); + task = new RaceLogPollerTask(this); + task.execute(queries.toArray(new Pair[0])); + } + + @Override + public void onPollingResult(PollingResult result) { + if (!poller.isPollingActive()) { + task.cancel(true); + ExLog.i(TAG, "Polling aborted."); + return; + } + if (result.isSuccess) { + Serializable raceId = result.resultStreamForRaceId.getA(); + InputStream responseStream = result.resultStreamForRaceId.getB(); + processor.processResponse(poller.context, responseStream, raceId); + } else { + ExLog.i(TAG, "Polling attempt not successful."); + } + } + + @Override + public void onPollingFinished() { + if (!poller.isPollingActive()) { + ExLog.i(TAG, "Polling aborted."); + return; + } + long pollingInterval = poller.getPollingIntervalInMs(); + ExLog.i(TAG, String.format("Polling done. Will poll again in %d milliseconds.", pollingInterval)); + poller.pollingHandler.postDelayed(this, pollingInterval); + } + + private List> getPollingQueries() { + List> queries = new ArrayList>(); + for (Entry entry : poller.races.entrySet()) { + queries.add(new Pair(entry.getKey().getId(), entry.getValue())); + } + return queries; + } + } + +} diff --git a/mobile/com.sap.sailing.racecommittee.app/src/com/sap/sailing/racecommittee/app/services/polling/RaceLogPollerTask.java b/mobile/com.sap.sailing.racecommittee.app/src/com/sap/sailing/racecommittee/app/services/polling/RaceLogPollerTask.java new file mode 100644 index 00000000000..4a30abcd38b --- /dev/null +++ b/mobile/com.sap.sailing.racecommittee.app/src/com/sap/sailing/racecommittee/app/services/polling/RaceLogPollerTask.java @@ -0,0 +1,62 @@ +package com.sap.sailing.racecommittee.app.services.polling; + +import java.io.IOException; +import java.io.InputStream; +import java.io.Serializable; +import java.net.URL; + +import android.os.AsyncTask; + +import com.sap.sailing.domain.common.impl.Util.Pair; +import com.sap.sailing.racecommittee.app.data.http.HttpJsonPostRequest; +import com.sap.sailing.racecommittee.app.data.http.HttpRequest; + +public class RaceLogPollerTask extends AsyncTask, PollingResult, Void> { + + public interface PollingResultListener { + public void onPollingResult(PollingResult result); + public void onPollingFinished(); + } + + private final PollingResultListener listener; + + public RaceLogPollerTask(PollingResultListener listener) { + this.listener = listener; + } + + @Override + protected Void doInBackground(Pair... queries) { + for (Pair query : queries) { + if (isCancelled()) { + return null; + } + + HttpRequest request = new HttpJsonPostRequest(query.getB()); + InputStream responseStream = null; + try { + responseStream = request.execute(); + publishProgress(new PollingResult(true, + new Pair(query.getA(), responseStream))); + } catch (IOException e) { + if (responseStream != null) { + try { + responseStream.close(); + } catch (IOException ie) { + } + } + publishProgress(new PollingResult(false, null)); + } + } + return null; + } + + @Override + protected void onProgressUpdate(PollingResult... values) { + listener.onPollingResult(values[0]); + } + + @Override + protected void onPostExecute(Void result) { + listener.onPollingFinished(); + } +} diff --git a/mobile/com.sap.sailing.racecommittee.app/src/com/sap/sailing/racecommittee/app/services/sending/EventPersistenceManager.java b/mobile/com.sap.sailing.racecommittee.app/src/com/sap/sailing/racecommittee/app/services/sending/EventPersistenceManager.java index 6bba00e5946..c60f547e084 100644 --- a/mobile/com.sap.sailing.racecommittee.app/src/com/sap/sailing/racecommittee/app/services/sending/EventPersistenceManager.java +++ b/mobile/com.sap.sailing.racecommittee.app/src/com/sap/sailing/racecommittee/app/services/sending/EventPersistenceManager.java @@ -125,9 +125,9 @@ public class EventPersistenceManager { String[] lineParts = persistedEvent.split(";"); String url = lineParts[2]; String raceId = lineParts[0]; - String serializedEventAsUrlEncodedJson = lineParts[1]; + String serializedEventJson = URLDecoder.decode(lineParts[1]); String callbackClassString = lineParts[3]; - addEventToLog(raceId, serializedEventAsUrlEncodedJson); + addEventToLog(raceId, serializedEventJson); Class callbackClass = null; if (! "null".equals(callbackClassString)) { @@ -144,7 +144,7 @@ public class EventPersistenceManager { // We are passing no event id, because we know it used to suppress event sending and // we want this event to be sent. Intent eventIntent = EventSendingService.createEventIntent(context, url, raceId, - null, URLDecoder.decode(serializedEventAsUrlEncodedJson), callbackClass); + null, serializedEventJson, callbackClass); if (eventIntent != null) { delayedIntents.add(eventIntent); } diff --git a/mobile/com.sap.sailing.racecommittee.app/src/com/sap/sailing/racecommittee/app/services/sending/EventSenderTask.java b/mobile/com.sap.sailing.racecommittee.app/src/com/sap/sailing/racecommittee/app/services/sending/EventSenderTask.java index 179bf793bd8..da65024b354 100755 --- a/mobile/com.sap.sailing.racecommittee.app/src/com/sap/sailing/racecommittee/app/services/sending/EventSenderTask.java +++ b/mobile/com.sap.sailing.racecommittee.app/src/com/sap/sailing/racecommittee/app/services/sending/EventSenderTask.java @@ -1,5 +1,6 @@ package com.sap.sailing.racecommittee.app.services.sending; +import java.io.IOException; import java.io.InputStream; import java.net.URL; @@ -27,6 +28,7 @@ public class EventSenderTask extends AsyncTask doInBackground(Intent... params) { Triple result; @@ -40,13 +42,19 @@ public class EventSenderTask extends AsyncTask(intent, false, null); } + InputStream responseStream = null; try { ExLog.i(TAG, "Posting event: " + serializedEventAsJson); HttpRequest post = new HttpJsonPostRequest(new URL(url), serializedEventAsJson); - final InputStream inputStream = post.execute(); + responseStream = post.execute(); ExLog.i(TAG, "Post successful for the following event: " + serializedEventAsJson); - result = new Triple(intent, true, inputStream); - } catch (Exception e) { + result = new Triple(intent, true, responseStream); + } catch (IOException e) { + if (responseStream != null) { + try { + responseStream.close(); + } catch (IOException ie) { } + } ExLog.e(TAG, String.format("Post not successful, exception occured: %s", e.toString())); result = new Triple(intent, false, null); } diff --git a/mobile/com.sap.sailing.racecommittee.app/src/com/sap/sailing/racecommittee/app/services/sending/EventSendingService.java b/mobile/com.sap.sailing.racecommittee.app/src/com/sap/sailing/racecommittee/app/services/sending/EventSendingService.java index b3d692321b0..36b207eeb9b 100644 --- a/mobile/com.sap.sailing.racecommittee.app/src/com/sap/sailing/racecommittee/app/services/sending/EventSendingService.java +++ b/mobile/com.sap.sailing.racecommittee.app/src/com/sap/sailing/racecommittee/app/services/sending/EventSendingService.java @@ -1,6 +1,5 @@ package com.sap.sailing.racecommittee.app.services.sending; -import java.io.IOException; import java.io.InputStream; import java.io.Serializable; import java.net.URLEncoder; @@ -54,6 +53,10 @@ public class EventSendingService extends Service implements EventSendingListener private boolean isHandlerSet; private Set suppressedEventIds = new HashSet(); + + public void registerEventForSuppression(Serializable eventId) { + suppressedEventIds.add(eventId); + } private EventSendingServiceLogger serviceLogger = new EventSendingServiceLogger() { @Override @@ -106,6 +109,18 @@ public class EventSendingService extends Service implements EventSendingListener serviceLogger.onEventSentSuccessful(); } + public static String getRaceLogEventSendAndReceiveUrl(Context context, final String raceGroupName, + final String raceName, final String fleetName) { + String url = String.format("%s/sailingserver/rc/racelog?"+ + RaceLogServletConstants.PARAMS_LEADERBOARD_NAME+"=%s&"+ + RaceLogServletConstants.PARAMS_RACE_COLUMN_NAME+"=%s&"+ + RaceLogServletConstants.PARAMS_RACE_FLEET_NAME+"=%s&"+ + RaceLogServletConstants.PARAMS_CLIENT_UUID+"=%s", + AppPreferences.on(context).getServerBaseURL(), URLEncoder.encode(raceGroupName), + URLEncoder.encode(raceName), URLEncoder.encode(fleetName), uuid); + return url; + } + /** * Creates an intent that contains the event to be sent and the race id which shall be sent to the back end. See * constants in AddEntryToRaceLogJsonPostServlet for URL construction rules. @@ -122,13 +137,8 @@ public class EventSendingService extends Service implements EventSendingListener */ public static Intent createEventIntent(Context context, ManagedRace race, Serializable eventId, String serializedEventAsJson, Class callbackClass) { - String url = String.format("%s/sailingserver/rc/racelog?"+ - RaceLogServletConstants.PARAMS_LEADERBOARD_NAME+"=%s&"+ - RaceLogServletConstants.PARAMS_RACE_COLUMN_NAME+"=%s&"+ - RaceLogServletConstants.PARAMS_RACE_FLEET_NAME+"=%s&"+ - RaceLogServletConstants.PARAMS_CLIENT_UUID+"=%s", - AppPreferences.on(context).getServerBaseURL(), URLEncoder.encode(race.getRaceGroup().getName()), - URLEncoder.encode(race.getName()), URLEncoder.encode(race.getFleet().getName()), uuid); + String url = getRaceLogEventSendAndReceiveUrl(context, + race.getRaceGroup().getName(), race.getName(), race.getFleet().getName()); return createEventIntent(context, url, race.getId(), eventId, serializedEventAsJson, callbackClass); } @@ -150,7 +160,7 @@ public class EventSendingService extends Service implements EventSendingListener if (id != null) { return id; } - ExLog.w(TAG, "Unanble to extract event identifier from event intent."); + ExLog.w(TAG, "Unable to extract event identifier from event intent."); return null; } @@ -230,6 +240,7 @@ public class EventSendingService extends Service implements EventSendingListener } else { Serializable eventId = getEventId(intent); if (eventId != null && suppressedEventIds.contains(eventId)) { + suppressedEventIds.remove(eventId); ExLog.i(TAG, String.format("Event %s is suppressed, won't be sent.", eventId)); } else { EventSenderTask task = new EventSenderTask(this); @@ -268,11 +279,9 @@ public class EventSendingService extends Service implements EventSendingListener } } if (callback != null) { - callback.processResponse(intent, this, inputStream, suppressedEventIds); + String raceId = intent.getStringExtra(AppConstants.RACE_ID_KEY); + callback.processResponse(this, inputStream, raceId); } - try { - inputStream.close(); - } catch (IOException e) {} } } diff --git a/mobile/com.sap.sailing.racecommittee.app/src/com/sap/sailing/racecommittee/app/services/sending/ServerReplyCallback.java b/mobile/com.sap.sailing.racecommittee.app/src/com/sap/sailing/racecommittee/app/services/sending/ServerReplyCallback.java index 5fc7d9f55b0..3182b993deb 100644 --- a/mobile/com.sap.sailing.racecommittee.app/src/com/sap/sailing/racecommittee/app/services/sending/ServerReplyCallback.java +++ b/mobile/com.sap.sailing.racecommittee.app/src/com/sap/sailing/racecommittee/app/services/sending/ServerReplyCallback.java @@ -2,7 +2,6 @@ package com.sap.sailing.racecommittee.app.services.sending; import java.io.InputStream; import java.io.Serializable; -import java.util.Set; import android.content.Context; import android.content.Intent; @@ -20,7 +19,7 @@ import com.sap.sailing.domain.racelog.RaceLogEvent; */ public interface ServerReplyCallback { /** - * The inputStream does not need to be closed by the implementing class. + * The inputStream MUST be closed by the implementing class. */ - void processResponse(Intent originalIntent, Context context, InputStream inputStream, Set suppressedEvents); + void processResponse(Context context, InputStream inputStream, Serializable raceId); } diff --git a/mobile/com.sap.sailing.racecommittee.app/src/com/sap/sailing/racecommittee/app/ui/fragments/preference/BasePreferenceFragment.java b/mobile/com.sap.sailing.racecommittee.app/src/com/sap/sailing/racecommittee/app/ui/fragments/preference/BasePreferenceFragment.java index b636ae2d28a..52edb27ed7b 100644 --- a/mobile/com.sap.sailing.racecommittee.app/src/com/sap/sailing/racecommittee/app/ui/fragments/preference/BasePreferenceFragment.java +++ b/mobile/com.sap.sailing.racecommittee.app/src/com/sap/sailing/racecommittee/app/ui/fragments/preference/BasePreferenceFragment.java @@ -6,9 +6,6 @@ import java.util.HashSet; import java.util.List; import java.util.Set; -import com.sap.sailing.racecommittee.app.ui.utils.MultiplePreferenceChangeListener; -import com.sap.sailing.racecommittee.app.ui.views.EditSetPreference; - import android.preference.CheckBoxPreference; import android.preference.ListPreference; import android.preference.MultiSelectListPreference; @@ -17,6 +14,9 @@ import android.preference.Preference.OnPreferenceChangeListener; import android.preference.PreferenceFragment; import android.preference.PreferenceManager; +import com.sap.sailing.racecommittee.app.ui.utils.MultiplePreferenceChangeListener; +import com.sap.sailing.racecommittee.app.ui.views.EditSetPreference; + /** * Created by I074137 on 18.09.13. */ diff --git a/mobile/com.sap.sailing.racecommittee.app/src/com/sap/sailing/racecommittee/app/ui/fragments/preference/GeneralPreferenceFragment.java b/mobile/com.sap.sailing.racecommittee.app/src/com/sap/sailing/racecommittee/app/ui/fragments/preference/GeneralPreferenceFragment.java index 65e98acedfa..e2c0e1924bb 100644 --- a/mobile/com.sap.sailing.racecommittee.app/src/com/sap/sailing/racecommittee/app/ui/fragments/preference/GeneralPreferenceFragment.java +++ b/mobile/com.sap.sailing.racecommittee.app/src/com/sap/sailing/racecommittee/app/ui/fragments/preference/GeneralPreferenceFragment.java @@ -9,6 +9,7 @@ import android.content.Intent; import android.content.SharedPreferences; import android.net.Uri; import android.os.Bundle; +import android.preference.CheckBoxPreference; import android.preference.Preference; import android.preference.Preference.OnPreferenceChangeListener; import android.preference.Preference.OnPreferenceClickListener; @@ -26,7 +27,6 @@ public class GeneralPreferenceFragment extends BasePreferenceFragment { private static int requestCodeQRCode = 45392; - private AppPreferences appPreferences; private Preference identifierPreference; private Preference serverUrlPreference; @@ -35,21 +35,37 @@ public class GeneralPreferenceFragment extends BasePreferenceFragment { super.onCreate(savedInstanceState); addPreferencesFromResource(R.xml.preference_general); - appPreferences = AppPreferences.on(getActivity()); - + setupConnection(); + setupPolling(); + setupGeneral(); + } + protected void setupGeneral() { setupLanguageButton(); - setupIdentifierBox(); - setupSyncQRCodeButton(); - setupForceUpdateButton(); - setupServerUrlBox(); setupCourseAreasList(); - bindPreferenceSummaryToValue(findPreference(R.string.preference_server_url_key)); bindPreferenceSummaryToSet(findPreference(R.string.preference_course_areas_key)); bindPreferenceSummaryToValue(findPreference(R.string.preference_mail_key)); } + private void setupPolling() { + Preference intervalPreference = findPreference(R.string.preference_polling_interval_key); + CheckBoxPreference activePreference = findPreference(R.string.preference_polling_active_key); + bindPreferenceToCheckbox(activePreference, intervalPreference); + bindPreferenceSummaryToInteger(intervalPreference); + } + + + protected void setupConnection() { + setupIdentifierBox(); + setupServerUrlBox(); + setupSyncQRCodeButton(); + setupForceUpdateButton(); + + bindPreferenceSummaryToValue(findPreference(R.string.preference_server_url_key)); + } + private void setupIdentifierBox() { + final AppPreferences appPreferences = AppPreferences.on(getActivity()); identifierPreference = findPreference(R.string.preference_identifier_key); identifierPreference.setSummary(appPreferences.getDeviceIdentifier()); addOnPreferenceChangeListener(identifierPreference, new OnPreferenceChangeListener() { @@ -102,8 +118,7 @@ public class GeneralPreferenceFragment extends BasePreferenceFragment { private void setupCourseAreasList() { EditSetPreference preference = findPreference(R.string.preference_course_areas_key); - //ReadonlyDataManager dataManager = DataManager.create(getActivity()); - + // TODO: example values from DataStore preference.setExampleValues(getResources().getStringArray(R.array.preference_course_areas_example)); } diff --git a/mobile/com.sap.sailing.racecommittee.app/src/com/sap/sailing/racecommittee/app/ui/fragments/preference/RegattaPreferenceFragment.java b/mobile/com.sap.sailing.racecommittee.app/src/com/sap/sailing/racecommittee/app/ui/fragments/preference/RegattaPreferenceFragment.java index c57f13067c6..e18c1fea1da 100644 --- a/mobile/com.sap.sailing.racecommittee.app/src/com/sap/sailing/racecommittee/app/ui/fragments/preference/RegattaPreferenceFragment.java +++ b/mobile/com.sap.sailing.racecommittee.app/src/com/sap/sailing/racecommittee/app/ui/fragments/preference/RegattaPreferenceFragment.java @@ -11,12 +11,18 @@ import android.preference.MultiSelectListPreference; import android.preference.Preference; import android.preference.Preference.OnPreferenceClickListener; +import com.sap.sailing.domain.base.configuration.RegattaConfiguration; import com.sap.sailing.domain.common.CourseDesignerMode; import com.sap.sailing.domain.common.racelog.Flags; import com.sap.sailing.domain.common.racelog.RacingProcedureType; import com.sap.sailing.racecommittee.app.R; import com.sap.sailing.racecommittee.app.ui.activities.SettingsActivity; +/** + *

This preference fragment can be redirected to display the {@link RegattaConfiguration} of a specifc regatta.

+ * + *

See {@link SettingsActivity}. + */ public class RegattaPreferenceFragment extends BasePreferenceFragment { private boolean isRedirected = false; diff --git a/mobile/com.sap.sailing.racecommittee.app/src/com/sap/sailing/racecommittee/app/utils/PreferenceHelper.java b/mobile/com.sap.sailing.racecommittee.app/src/com/sap/sailing/racecommittee/app/utils/PreferenceHelper.java index a1d1b3721c0..bce8c017cb7 100644 --- a/mobile/com.sap.sailing.racecommittee.app/src/com/sap/sailing/racecommittee/app/utils/PreferenceHelper.java +++ b/mobile/com.sap.sailing.racecommittee.app/src/com/sap/sailing/racecommittee/app/utils/PreferenceHelper.java @@ -22,7 +22,7 @@ public class PreferenceHelper { * Whenever you change a preference's type (e.g. from Integer to String) you need to bump this version code to the * appropriate app version (see AndroidManifest.xml). */ - private final static int LAST_COMPATIBLE_VERSION = 3; + private final static int LAST_COMPATIBLE_VERSION = 4; /** * Application stores preference version code in this preference file (and key). From 0c8cb26333e96eedec365032023f9c00fc02473e Mon Sep 17 00:00:00 2001 From: Lukas Niemeier Date: Sun, 8 Dec 2013 00:57:46 +0100 Subject: [PATCH 10/20] lint --- .../res/values-de/strings.xml | 60 ++++++++++++++++--- .../res/values/strings.xml | 40 +++++++++---- .../app/ui/activities/WindActivity.java | 2 +- .../dialogs/PositioningFragment.java | 8 +++ .../RegattaSpecificPreferenceFragment.java | 7 +-- .../raceinfo/SetStartTimeRaceFragment.java | 2 +- .../running/RRS26RunningRaceFragment.java | 5 +- .../app/utils/autoupdate/AutoUpdater.java | 9 ++- .../utils/autoupdate/AutoUpdaterChecker.java | 24 ++++---- mobile/google-play-services_lib/lint.xml | 5 ++ 10 files changed, 115 insertions(+), 47 deletions(-) create mode 100644 mobile/google-play-services_lib/lint.xml diff --git a/mobile/com.sap.sailing.racecommittee.app/res/values-de/strings.xml b/mobile/com.sap.sailing.racecommittee.app/res/values-de/strings.xml index 7d42ceec12d..bbf65a349ce 100644 --- a/mobile/com.sap.sailing.racecommittee.app/res/values-de/strings.xml +++ b/mobile/com.sap.sailing.racecommittee.app/res/values-de/strings.xml @@ -81,11 +81,6 @@ Steuerbord Gate - - Nach oben - Nach unten - Entfernen - Veröffentlichen Zurücknehmen @@ -137,8 +132,6 @@ Regatta Einstellungen (Speziell) Kursdesigner Einstellungen - Standard Startprozedur überschreiben - Aktivieren wenn Startprozedur der Rennen überschrieben werden soll. Standard Startprozedur (wenn überschrieben) Wenn Option "Standard Startprozedur überschreiben" aktiv ist, wird ausgewählte Startprozedur als Standard gewählt. @@ -185,9 +178,60 @@ Lade Konfiguration… Fehler beim Laden der Konfiguration. -Für dieses Gerät existiert keine Konfiguration auf dem Server. + Für dieses Gerät existiert keine Konfiguration auf dem Server. Konfiguration vom Server übernommen. Installieren Trotzdem installieren + + + + Einzelrückruf entfernen + Als Startschiff-Wettfahrleiter einloggen + Als Zielschiff-Wettfahrleiter einloggen + Als Shore-Control einloggen + Fehler + Gate Launch stoppt nach %dmin + Kursdesigner + Kursnamen + Neues Element eingeben + Hinzufügen + Bisher keine Elemente. + Startmodus Flaggen + Klassenflagge + Einzelrückruf + Diese Option aktiviert den Einzelrückruf + Diese Option aktiviert den Pathfinder + Pathfinder + Diese Option aktiviert das Wählen der zusätzlichen Golfflaggenzeit. + Zusätzliche Golfflaggenzeit. + Gerätename + Synchronisiere mit Server + Zur Synchronisierung der Gerätekonfiguration vom Server per QR-Code hier klicken. + Update erzwingen + Erzwingt ein Update. Es ist besser die Synchronisierung zu nutzen. + Technische Informationen + Gate Launch + Golf + Regattakonfiguration - %1$s + Speichere %1$s Konfiguration + Hier klicken um Regattakonfiguration für 1$s zu speichern. + Auto-Update + Prüfe Versionsinformation auf Server… + Versuche Versionsinformation von %1$s zu erhalten + Link zur Versionsinformation ungültig. + Klicke \'Installieren\' um ein Update auf Version %1$d durchzuführen. + Es ist bereits die Server-Version installiert (Version %1$d). + Alles aktuell! + Downloade APK vom Server… + Der Downloadlink ist ungültig. + Konnte Zieldatei nicht erstellen. + Fehler beim Update. + Auto-Update erfolgreich + Update erfolgreich ausgeführt. Es sollte erneut mit dem Server synchronisiert werden. + Bring' mich hin + GPS ist ausgeschaltet, soll es aktiviert werde? + Startmodus Flagge verändert zu %1$s + Bisher keine Regatta geladen. + Konfiguriere Regatta %1$s \ No newline at end of file diff --git a/mobile/com.sap.sailing.racecommittee.app/res/values/strings.xml b/mobile/com.sap.sailing.racecommittee.app/res/values/strings.xml index 9c0eed31eef..0ee676c796b 100644 --- a/mobile/com.sap.sailing.racecommittee.app/res/values/strings.xml +++ b/mobile/com.sap.sailing.racecommittee.app/res/values/strings.xml @@ -1,6 +1,6 @@ - - + + (on course %s) Course has %s waypoints @@ -131,8 +131,6 @@ Select Language Select the language. You might need to restart the app to have changes applied. - Override default start procedure type - Check the box if races should use the start procedure type defined below as a default. Default start procedure type when overriden Races will use selected start procedure type as a default. For this option to be active override checkbox has to be enabled. @@ -168,13 +166,13 @@ Today Start - Application Information - Identifier - Version - Install Date - Persistence Status - Waiting events - Clear events + Application Information + Identifier + Install Date + Persistence Status + Clear events + Waiting events + Version Error @@ -198,8 +196,6 @@ Regatta Configuration (default) Regatta Configuration (specific) Course Designer Configuration - Override Course Designer type - Use configured Course Designer instead of race\'s. Course Designer type Course Names @@ -231,4 +227,22 @@ Regatta Configuration - %1$s Save %1$s configuration This will save the shown configuration for all races of %1$s. + Auto-Update + Checking for version information on server… + Trying to download auto-update info from %1$s + The version file link was not valid. + Click \'Install\' to perform the update to version %1$d. + You already have installed the version offered by the server (version %1$d). + You are already up to date! + Downloading APK from server… + The download link was not valid. + The download file couldn\'t be created. + Error while trying to auto-update. + Auto-Update completed + The automatic update has been completed. You should now re-synchronize your connection settings with the server. + Take me there + Your GPS seems to be disabled, do you want to enable it? + Start mode flag changed to %1$s + There are no regattas loaded. + Configure regatta %1$s \ No newline at end of file diff --git a/mobile/com.sap.sailing.racecommittee.app/src/com/sap/sailing/racecommittee/app/ui/activities/WindActivity.java b/mobile/com.sap.sailing.racecommittee.app/src/com/sap/sailing/racecommittee/app/ui/activities/WindActivity.java index f32bbf847a7..53d0e3aab69 100644 --- a/mobile/com.sap.sailing.racecommittee.app/src/com/sap/sailing/racecommittee/app/ui/activities/WindActivity.java +++ b/mobile/com.sap.sailing.racecommittee.app/src/com/sap/sailing/racecommittee/app/ui/activities/WindActivity.java @@ -150,7 +150,7 @@ public class WindActivity extends SessionActivity implements CompassDirectionLis private void buildAlertMessageNoGps() { AlertDialog.Builder builder = new AlertDialog.Builder(this); - builder.setMessage("Your GPS seems to be disabled, do you want to enable it?") + builder.setMessage(R.string.wind_gps_is_disabled) .setCancelable(false) .setPositiveButton(getResources().getString(R.string.yes), new DialogInterface.OnClickListener() { public void onClick(final DialogInterface dialog, final int id) { diff --git a/mobile/com.sap.sailing.racecommittee.app/src/com/sap/sailing/racecommittee/app/ui/fragments/dialogs/PositioningFragment.java b/mobile/com.sap.sailing.racecommittee.app/src/com/sap/sailing/racecommittee/app/ui/fragments/dialogs/PositioningFragment.java index 0ce516ef002..a477b2586f4 100644 --- a/mobile/com.sap.sailing.racecommittee.app/src/com/sap/sailing/racecommittee/app/ui/fragments/dialogs/PositioningFragment.java +++ b/mobile/com.sap.sailing.racecommittee.app/src/com/sap/sailing/racecommittee/app/ui/fragments/dialogs/PositioningFragment.java @@ -26,6 +26,7 @@ import com.mobeta.android.dslv.DragSortController; import com.mobeta.android.dslv.DragSortListView; import com.sap.sailing.domain.base.Competitor; import com.sap.sailing.domain.base.CompetitorStore; +import com.sap.sailing.domain.base.SharedDomainFactory; import com.sap.sailing.domain.common.MaxPointsReason; import com.sap.sailing.domain.common.Named; import com.sap.sailing.domain.common.impl.MillisecondsTimePoint; @@ -171,7 +172,14 @@ public class PositioningFragment extends RaceDialogFragment { private void loadCompetitors() { getActivity().setProgressBarIndeterminateVisibility(true); + + // invalidate all competitors of this race ReadonlyDataManager dataManager = OnlineDataManager.create(getActivity()); + SharedDomainFactory domainFactory = dataManager.getDataStore().getDomainFactory(); + for (Competitor competitor : getRace().getCompetitors()) { + domainFactory.getCompetitorStore().allowCompetitorResetToDefaults(competitor); + } + Loader competitorLoaders = getLoaderManager().initLoader(0, null, dataManager.createCompetitorsLoader(getRace(), new LoadClient>() { diff --git a/mobile/com.sap.sailing.racecommittee.app/src/com/sap/sailing/racecommittee/app/ui/fragments/preference/RegattaSpecificPreferenceFragment.java b/mobile/com.sap.sailing.racecommittee.app/src/com/sap/sailing/racecommittee/app/ui/fragments/preference/RegattaSpecificPreferenceFragment.java index 638511ba63c..661cdb615bf 100644 --- a/mobile/com.sap.sailing.racecommittee.app/src/com/sap/sailing/racecommittee/app/ui/fragments/preference/RegattaSpecificPreferenceFragment.java +++ b/mobile/com.sap.sailing.racecommittee.app/src/com/sap/sailing/racecommittee/app/ui/fragments/preference/RegattaSpecificPreferenceFragment.java @@ -5,15 +5,14 @@ import java.util.Collections; import java.util.Comparator; import java.util.List; import java.util.Set; - import android.content.Context; import android.os.Bundle; import android.preference.Preference; import android.preference.Preference.OnPreferenceClickListener; import android.preference.PreferenceScreen; - import com.sap.sailing.domain.base.racegroup.RaceGroup; import com.sap.sailing.domain.common.impl.NaturalComparator; +import com.sap.sailing.racecommittee.app.R; import com.sap.sailing.racecommittee.app.data.DataManager; import com.sap.sailing.racecommittee.app.data.ReadonlyDataManager; import com.sap.sailing.racecommittee.app.ui.activities.SettingsActivity; @@ -31,7 +30,7 @@ public class RegattaSpecificPreferenceFragment extends BasePreferenceFragment { Set raceGroups = getRaceGroups(context); if (raceGroups.isEmpty()) { Preference preference = new Preference(context); - preference.setTitle("There are no regattas loaded."); + preference.setTitle(R.string.preference_there_are_no_regattas); screen.addPreference(preference); } else { List sortedGroups = new ArrayList(raceGroups); @@ -52,7 +51,7 @@ public class RegattaSpecificPreferenceFragment extends BasePreferenceFragment { private void addPreference(PreferenceScreen screen, final RaceGroup raceGroup) { Preference preference = new Preference(screen.getContext()); - preference.setTitle(String.format("Configure regatta %s", raceGroup.getName())); + preference.setTitle(getString(R.string.configure_regatta, raceGroup.getName())); preference.setOnPreferenceClickListener(new OnPreferenceClickListener() { @Override diff --git a/mobile/com.sap.sailing.racecommittee.app/src/com/sap/sailing/racecommittee/app/ui/fragments/raceinfo/SetStartTimeRaceFragment.java b/mobile/com.sap.sailing.racecommittee.app/src/com/sap/sailing/racecommittee/app/ui/fragments/raceinfo/SetStartTimeRaceFragment.java index 24723b99950..9b88e94677e 100644 --- a/mobile/com.sap.sailing.racecommittee.app/src/com/sap/sailing/racecommittee/app/ui/fragments/raceinfo/SetStartTimeRaceFragment.java +++ b/mobile/com.sap.sailing.racecommittee.app/src/com/sap/sailing/racecommittee/app/ui/fragments/raceinfo/SetStartTimeRaceFragment.java @@ -132,7 +132,7 @@ public class SetStartTimeRaceFragment extends RaceFragment { if (startDate.get(Calendar.YEAR) == today.get(Calendar.YEAR) && startDate.get(Calendar.DAY_OF_YEAR) == today.get(Calendar.DAY_OF_YEAR)) { - btSetDate.setText("Today"); + btSetDate.setText(R.string.today); } else { String dateString = DateFormat.getDateFormat(getActivity()).format(startDate.getTime()); btSetDate.setText(dateString); diff --git a/mobile/com.sap.sailing.racecommittee.app/src/com/sap/sailing/racecommittee/app/ui/fragments/raceinfo/running/RRS26RunningRaceFragment.java b/mobile/com.sap.sailing.racecommittee.app/src/com/sap/sailing/racecommittee/app/ui/fragments/raceinfo/running/RRS26RunningRaceFragment.java index 4151426d55c..7691073adcd 100644 --- a/mobile/com.sap.sailing.racecommittee.app/src/com/sap/sailing/racecommittee/app/ui/fragments/raceinfo/running/RRS26RunningRaceFragment.java +++ b/mobile/com.sap.sailing.racecommittee.app/src/com/sap/sailing/racecommittee/app/ui/fragments/raceinfo/running/RRS26RunningRaceFragment.java @@ -2,11 +2,11 @@ package com.sap.sailing.racecommittee.app.ui.fragments.raceinfo.running; import android.view.View; import android.widget.Toast; - import com.sap.sailing.domain.racelog.state.racingprocedure.impl.BaseRacingProcedureChangedListener; import com.sap.sailing.domain.racelog.state.racingprocedure.rrs26.RRS26ChangedListener; import com.sap.sailing.domain.racelog.state.racingprocedure.rrs26.RRS26RacingProcedure; import com.sap.sailing.domain.racelog.state.racingprocedure.rrs26.ReadonlyRRS26RacingProcedure; +import com.sap.sailing.racecommittee.app.R; public class RRS26RunningRaceFragment extends BaseRunningRaceFragment { @@ -33,8 +33,7 @@ public class RRS26RunningRaceFragment extends BaseRunningRaceFragment + + + + \ No newline at end of file From f978695ff4c0ea7000f7cb48f1648f762fbf4e8a Mon Sep 17 00:00:00 2001 From: Lukas Niemeier Date: Sun, 8 Dec 2013 14:42:38 +0100 Subject: [PATCH 11/20] typo --- .../com.sap.sailing.racecommittee.app/res/values-de/strings.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mobile/com.sap.sailing.racecommittee.app/res/values-de/strings.xml b/mobile/com.sap.sailing.racecommittee.app/res/values-de/strings.xml index bbf65a349ce..447cf38a707 100644 --- a/mobile/com.sap.sailing.racecommittee.app/res/values-de/strings.xml +++ b/mobile/com.sap.sailing.racecommittee.app/res/values-de/strings.xml @@ -229,7 +229,7 @@ Fehler beim Update. Auto-Update erfolgreich Update erfolgreich ausgeführt. Es sollte erneut mit dem Server synchronisiert werden. - Bring' mich hin + Bring\' mich hin GPS ist ausgeschaltet, soll es aktiviert werde? Startmodus Flagge verändert zu %1$s Bisher keine Regatta geladen. From cfe1d11024f9eeff65e1a1959adf361553ffab51 Mon Sep 17 00:00:00 2001 From: Axel Uhl Date: Wed, 22 Jan 2014 16:42:56 +0100 Subject: [PATCH 12/20] started to fix merge issues regarding UUID use in GWT client --- .../main/java/com/sap/sailing/gwt/ui/client/SailingService.java | 2 -- .../java/com/sap/sailing/gwt/ui/server/SailingServiceImpl.java | 2 -- 2 files changed, 4 deletions(-) diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/SailingService.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/SailingService.java index a98472806b2..33b3ecd094d 100755 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/SailingService.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/SailingService.java @@ -264,8 +264,6 @@ public interface SailingService extends RemoteService { EventDTO getEventByName(String eventName); - EventDTO getEventById(UUID id); - Iterable getScoreCorrectionProviderNames(); ScoreCorrectionProviderDTO getScoreCorrectionsOfProvider(String providerName) throws Exception; diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/server/SailingServiceImpl.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/server/SailingServiceImpl.java index a306ed4dd29..3f4ddb81b43 100755 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/server/SailingServiceImpl.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/server/SailingServiceImpl.java @@ -2798,8 +2798,6 @@ public class SailingServiceImpl extends ProxiedRemoteServiceServlet implements S return result; } - @Override - public EventDTO getEventById(UUID id) { private EventDTO getEventById(UUID id) { EventDTO result = null; Event event = getService().getEvent(id); From e1edaab309c4094a4ddf9895ced08084a06ae321 Mon Sep 17 00:00:00 2001 From: Axel Uhl Date: Thu, 23 Jan 2014 13:47:15 +0100 Subject: [PATCH 13/20] went back to using UUID for course area and event querying because with JRE emulation GWT can use UUIDs by now --- .../java/com/sap/sailing/gwt/ui/client/SailingService.java | 2 ++ .../com/sap/sailing/gwt/ui/client/SailingServiceAsync.java | 2 ++ .../java/com/sap/sailing/gwt/ui/server/SailingServiceImpl.java | 3 ++- 3 files changed, 6 insertions(+), 1 deletion(-) diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/SailingService.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/SailingService.java index 33b3ecd094d..a98472806b2 100755 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/SailingService.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/SailingService.java @@ -264,6 +264,8 @@ public interface SailingService extends RemoteService { EventDTO getEventByName(String eventName); + EventDTO getEventById(UUID id); + Iterable getScoreCorrectionProviderNames(); ScoreCorrectionProviderDTO getScoreCorrectionsOfProvider(String providerName) throws Exception; diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/SailingServiceAsync.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/SailingServiceAsync.java index 3473cf180f1..065193a1f0c 100755 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/SailingServiceAsync.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/SailingServiceAsync.java @@ -503,5 +503,7 @@ public interface SailingServiceAsync { void removeIgtimiAccount(String eMailOfAccountToRemove, AsyncCallback asyncCallback); void importWindFromIgtimi(List selectedRaces, AsyncCallback> asyncCallback); + + void getEventById(UUID id, AsyncCallback callback); } diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/server/SailingServiceImpl.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/server/SailingServiceImpl.java index 3f4ddb81b43..e31199aebfc 100755 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/server/SailingServiceImpl.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/server/SailingServiceImpl.java @@ -2798,7 +2798,8 @@ public class SailingServiceImpl extends ProxiedRemoteServiceServlet implements S return result; } - private EventDTO getEventById(UUID id) { + @Override + public EventDTO getEventById(UUID id) { EventDTO result = null; Event event = getService().getEvent(id); if (event != null) { From dc93e52454c7158b1ba94a380c6b78eaa628bdb9 Mon Sep 17 00:00:00 2001 From: Axel Uhl Date: Thu, 23 Jan 2014 13:55:30 +0100 Subject: [PATCH 14/20] added locking for iteration over the race log's "raw" entries --- .../com/sap/sailing/domain/racelog/impl/RaceLogImpl.java | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/racelog/impl/RaceLogImpl.java b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/racelog/impl/RaceLogImpl.java index 840904b68f7..ae61d87ef29 100644 --- a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/racelog/impl/RaceLogImpl.java +++ b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/racelog/impl/RaceLogImpl.java @@ -161,8 +161,13 @@ public class RaceLogImpl extends TrackImpl implements RaceLog { } protected Iterable getEventsToDeliver(UUID clientId, RaceLogEvent suppressedEvent) { - // FIXME lock for read getInternalRawFixes? - LinkedHashSet stillToDeliverToClient = new LinkedHashSet(getInternalRawFixes()); + final LinkedHashSet stillToDeliverToClient; + lockForRead(); + try { + stillToDeliverToClient = new LinkedHashSet(getInternalRawFixes()); + } finally { + unlockAfterRead(); + } stillToDeliverToClient.remove(suppressedEvent); Set deliveredToClient = eventsDeliveredToClient.get(clientId); if (deliveredToClient != null) { From ead21fcfe0341be12dc2bf84a29d2e2f8d88a1a3 Mon Sep 17 00:00:00 2001 From: Frederik Petersen Date: Mon, 27 Jan 2014 15:53:03 +0000 Subject: [PATCH 15/20] Updated production environment (markdown) --- wiki/production-environment.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/wiki/production-environment.md b/wiki/production-environment.md index a168118910e..c6ff3c60b01 100644 --- a/wiki/production-environment.md +++ b/wiki/production-environment.md @@ -6,7 +6,7 @@ Our current server deployment uses a 64bit Java7 Hotspot virtual machine and runs on a 64bit Linux CentOS distribution. We have a single host (sapsailing.com) which runs a number of Java VMs, some to offer the application in different development stages (dev, test, prod, ...), some to perform specific tasks such as replicating UDP wind data to the various server processes, or a process to store data received from the SwissTiming connector durably while forwarding that data to a server VM requesting it. -The various processes run in "tmux" sessions to which, once connected to sapsailing.com with an ssh client, users can gain access using the `tmux -2 attach-session -t sailing` command. The tmux environment including is started automagically upon system boot by invoking the script _/home/trac/servers/tmuxManagementConsole.sh_. +The various processes run in "tmux" sessions to which, once connected to the desired EC2 instance with an ssh client and becoming the sailing user 'su - sailing', users can gain access using the `tmux attach` command. The tmux environment including is started automagically upon system boot by invoking the script _/home/trac/servers/tmuxManagementConsole.sh_. For the OSGi containers by convention we have one directory under _/home/trac/servers/_ per deployable branch (dev, test, prod1, prod2). In those directories we have copies of the "install" script from the git's java/target folder. Running it after a successful product build on the branch corresponding to the current directory will copy the compiled product to the server directory. Running the start script will then launch the respective server instance. A safety check in the install script avoids accidentally overwriting a server directory with a non-matching product version by comparing the directory name with the branch name checked out under _/home/trac/git_. @@ -254,4 +254,4 @@ MongoDB configuration can be found in /opt/mongodb/etc. This service is automati ### MySQL -MySQL serves as database backend for Piwik and Bugzilla. Configuration can be found in /etc/my.cnf and database files in /var/lib/mysql. +MySQL serves as database backend for Piwik and Bugzilla. Configuration can be found in /etc/my.cnf and database files in /var/lib/mysql. \ No newline at end of file From fe68e14f1930c78d614e141934efdafa287f4a4a Mon Sep 17 00:00:00 2001 From: Frederik Petersen Date: Mon, 27 Jan 2014 17:40:29 +0100 Subject: [PATCH 16/20] Increased timeout for master data import Especially when testing with a local client on a machine connected per wifi, the 10 second timeout led to exceptions when importing big leaderboard groups from a remote server. This will not happen anymore, as the timeout was increased to 10 minutes. --- .../com/sap/sailing/gwt/ui/server/SailingServiceImpl.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/server/SailingServiceImpl.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/server/SailingServiceImpl.java index 97703b230a0..595c6396dda 100755 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/server/SailingServiceImpl.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/server/SailingServiceImpl.java @@ -59,12 +59,12 @@ import com.sap.sailing.datamining.shared.QueryResult; import com.sap.sailing.domain.base.BoatClass; import com.sap.sailing.domain.base.Competitor; import com.sap.sailing.domain.base.ControlPoint; +import com.sap.sailing.domain.base.ControlPointWithTwoMarks; import com.sap.sailing.domain.base.Course; import com.sap.sailing.domain.base.CourseArea; import com.sap.sailing.domain.base.CourseBase; import com.sap.sailing.domain.base.Event; import com.sap.sailing.domain.base.Fleet; -import com.sap.sailing.domain.base.ControlPointWithTwoMarks; import com.sap.sailing.domain.base.Mark; import com.sap.sailing.domain.base.RaceColumn; import com.sap.sailing.domain.base.RaceColumnInSeries; @@ -3365,7 +3365,7 @@ public class SailingServiceImpl extends ProxiedRemoteServiceServlet implements S connection = (HttpURLConnection)serverAddress.openConnection(); connection.setRequestMethod("GET"); connection.setDoOutput(true); - connection.setReadTimeout(10000); + connection.setReadTimeout(600000); connection.connect(); //read the result from the server From 6999d731dd43504dfc129e2e202957e83c55aebe Mon Sep 17 00:00:00 2001 From: Axel Uhl Date: Mon, 27 Jan 2014 17:55:51 +0100 Subject: [PATCH 17/20] (re-?)added the code to increase the passId after the general recall pennant has been hoisted --- java/com.sap.sailing.gwt.ui/SailingGWT.launch | 2 +- .../ui/fragments/raceinfo/running/BaseRunningRaceFragment.java | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/java/com.sap.sailing.gwt.ui/SailingGWT.launch b/java/com.sap.sailing.gwt.ui/SailingGWT.launch index 09caff60333..2a3d82ae5a5 100755 --- a/java/com.sap.sailing.gwt.ui/SailingGWT.launch +++ b/java/com.sap.sailing.gwt.ui/SailingGWT.launch @@ -49,7 +49,7 @@ - + diff --git a/mobile/com.sap.sailing.racecommittee.app/src/com/sap/sailing/racecommittee/app/ui/fragments/raceinfo/running/BaseRunningRaceFragment.java b/mobile/com.sap.sailing.racecommittee.app/src/com/sap/sailing/racecommittee/app/ui/fragments/raceinfo/running/BaseRunningRaceFragment.java index ab565b50498..01f725da753 100644 --- a/mobile/com.sap.sailing.racecommittee.app/src/com/sap/sailing/racecommittee/app/ui/fragments/raceinfo/running/BaseRunningRaceFragment.java +++ b/mobile/com.sap.sailing.racecommittee.app/src/com/sap/sailing/racecommittee/app/ui/fragments/raceinfo/running/BaseRunningRaceFragment.java @@ -81,6 +81,8 @@ public abstract class BaseRunningRaceFragment Date: Mon, 27 Jan 2014 21:21:31 +0100 Subject: [PATCH 18/20] Wrapped MasterDataImport InputStream to automatically extend timeout while receiving data --- .../gwt/ui/server/SailingServiceImpl.java | 55 ++++++++++++++++--- 1 file changed, 46 insertions(+), 9 deletions(-) diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/server/SailingServiceImpl.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/server/SailingServiceImpl.java index 53c3ac3313a..162382dee7b 100755 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/server/SailingServiceImpl.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/server/SailingServiceImpl.java @@ -1,7 +1,9 @@ package com.sap.sailing.gwt.ui.server; import java.io.BufferedReader; +import java.io.FilterInputStream; import java.io.IOException; +import java.io.InputStream; import java.io.InputStreamReader; import java.io.ObjectOutputStream; import java.io.Serializable; @@ -3356,7 +3358,8 @@ public class SailingServiceImpl extends ProxiedRemoteServiceServlet implements S HttpURLConnection connection = null; URL serverAddress = null; - GZIPInputStream gzip = null; + InputStream inputStream = null; + BufferedReader rd = null; try { serverAddress = createUrl(hostname, port, query); //set up out communications stuff @@ -3365,17 +3368,19 @@ public class SailingServiceImpl extends ProxiedRemoteServiceServlet implements S connection = (HttpURLConnection)serverAddress.openConnection(); connection.setRequestMethod("GET"); connection.setDoOutput(true); - connection.setReadTimeout(600000); + connection.setReadTimeout(60000); connection.connect(); - //read the result from the server - BufferedReader rd; + if (compress) { - gzip = new GZIPInputStream(connection.getInputStream()); - rd = new BufferedReader(new InputStreamReader(gzip, Charset.forName("UTF-8"))); + InputStream timeoutExtendingInputStream = new TimeoutExtendingInputStream(connection.getInputStream(), + connection); + inputStream = new GZIPInputStream(timeoutExtendingInputStream); } else { - rd = new BufferedReader(new InputStreamReader(connection.getInputStream(), Charset.forName("UTF-8"))); + inputStream = new TimeoutExtendingInputStream(connection.getInputStream(), connection); } + + rd = new BufferedReader(new InputStreamReader(inputStream, Charset.forName("UTF-8"))); StringBuilder sb = new StringBuilder(); String line; while ((line = rd.readLine()) != null) { @@ -3391,8 +3396,11 @@ public class SailingServiceImpl extends ProxiedRemoteServiceServlet implements S long timeToImport = System.currentTimeMillis() - startTime; logger.info(String.format("Took %s ms overall to import master data.", timeToImport)); try { - if (gzip != null) { - gzip.close(); + if (inputStream != null) { + inputStream.close(); + } + if (rd != null) { + rd.close(); } } catch (IOException e) { } @@ -3703,4 +3711,33 @@ public class SailingServiceImpl extends ProxiedRemoteServiceServlet implements S } return result; } + + private class TimeoutExtendingInputStream extends FilterInputStream { + + private final HttpURLConnection connection; + + protected TimeoutExtendingInputStream(InputStream in, HttpURLConnection connection) { + super(in); + this.connection = connection; + } + + @Override + public int read() throws IOException { + connection.setReadTimeout(10000); + return super.read(); + } + + @Override + public int read(byte[] b) throws IOException { + connection.setReadTimeout(10000); + return super.read(b); + } + + @Override + public int read(byte[] b, int off, int len) throws IOException { + connection.setReadTimeout(10000); + return super.read(b, off, len); + } + + } } \ No newline at end of file From d2d71945eccb046794ea0fd9fe7881436892e0ae Mon Sep 17 00:00:00 2001 From: Frederik Petersen Date: Mon, 27 Jan 2014 22:56:03 +0100 Subject: [PATCH 19/20] MasterDataImport now streams gzipped data while already responding --- .../gwt/ui/server/SailingServiceImpl.java | 1 + .../gateway/jaxrs/api/MasterDataResource.java | 32 ++++++++++++------- 2 files changed, 22 insertions(+), 11 deletions(-) diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/server/SailingServiceImpl.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/server/SailingServiceImpl.java index 162382dee7b..4a490ad8215 100755 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/server/SailingServiceImpl.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/server/SailingServiceImpl.java @@ -3368,6 +3368,7 @@ public class SailingServiceImpl extends ProxiedRemoteServiceServlet implements S connection = (HttpURLConnection)serverAddress.openConnection(); connection.setRequestMethod("GET"); connection.setDoOutput(true); + // Initial timeout needs to be big enough to allow the first parts of the response to reach this server connection.setReadTimeout(60000); connection.connect(); diff --git a/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/jaxrs/api/MasterDataResource.java b/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/jaxrs/api/MasterDataResource.java index 4f8d444e5fe..c2871a3d615 100644 --- a/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/jaxrs/api/MasterDataResource.java +++ b/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/jaxrs/api/MasterDataResource.java @@ -1,7 +1,8 @@ package com.sap.sailing.server.gateway.jaxrs.api; -import java.io.ByteArrayOutputStream; import java.io.IOException; +import java.io.OutputStream; +import java.io.UnsupportedEncodingException; import java.util.HashSet; import java.util.List; import java.util.Map; @@ -13,9 +14,11 @@ import javax.ws.rs.GET; import javax.ws.rs.Path; import javax.ws.rs.Produces; import javax.ws.rs.QueryParam; +import javax.ws.rs.WebApplicationException; import javax.ws.rs.core.MediaType; import javax.ws.rs.core.Response; import javax.ws.rs.core.Response.ResponseBuilder; +import javax.ws.rs.core.StreamingOutput; import org.json.simple.JSONObject; @@ -32,8 +35,7 @@ public class MasterDataResource extends AbstractSailingServerResource { @Produces("application/json;charset=UTF-8") @Path("leaderboardgroups") public Response getMasterDataByLeaderboardGroups(@QueryParam("names[]") List leaderboardGroupNames, - @QueryParam("compress") Boolean compress) - throws IOException { + @QueryParam("compress") Boolean compress) throws UnsupportedEncodingException { long startTime = System.currentTimeMillis(); if (compress == null) { compress = false; @@ -57,14 +59,22 @@ public class MasterDataResource extends AbstractSailingServerResource { JSONObject masterData = masterSerializer.serialize(requestedLeaderboardGroupNames); ResponseBuilder resp; if (compress) { - byte[] uncompressedResult = masterData.toJSONString().getBytes("UTF-8"); - byte[] result; - ByteArrayOutputStream out = new ByteArrayOutputStream(); - GZIPOutputStream gzip = new GZIPOutputStream(out); - gzip.write(uncompressedResult); - gzip.close(); - result = out.toByteArray(); - resp = Response.ok(result, MediaType.APPLICATION_JSON).header("Content-Encoding", "gzip"); + final byte[] uncompressedResult = masterData.toJSONString().getBytes("UTF-8"); + + StreamingOutput streamingOutput = new StreamingOutput() { + + @Override + public void write(OutputStream output) throws IOException, WebApplicationException { + GZIPOutputStream gzip = null; + try { + gzip = new GZIPOutputStream(output); + gzip.write(uncompressedResult); + } finally { + gzip.close(); + } + } + }; + resp = Response.ok(streamingOutput, MediaType.APPLICATION_JSON).header("Content-Encoding", "gzip"); } else { String result = masterData.toJSONString(); resp = Response.ok(result, MediaType.APPLICATION_JSON); From 822677f06099b7031e5958f5f87298a74347b30b Mon Sep 17 00:00:00 2001 From: Axel Uhl Date: Tue, 28 Jan 2014 00:07:39 +0100 Subject: [PATCH 20/20] when StoreAndForward gets a SocketException while reading from SwissTiming's inbound connection, terminate the connection --- .../persistence/StoreAndForward.java | 111 ++++++++++-------- 1 file changed, 60 insertions(+), 51 deletions(-) diff --git a/java/com.sap.sailing.domain.swisstimingadapter.persistence/src/com/sap/sailing/domain/swisstimingadapter/persistence/StoreAndForward.java b/java/com.sap.sailing.domain.swisstimingadapter.persistence/src/com/sap/sailing/domain/swisstimingadapter/persistence/StoreAndForward.java index 96944ff6362..b709adec18e 100755 --- a/java/com.sap.sailing.domain.swisstimingadapter.persistence/src/com/sap/sailing/domain/swisstimingadapter/persistence/StoreAndForward.java +++ b/java/com.sap.sailing.domain.swisstimingadapter.persistence/src/com/sap/sailing/domain/swisstimingadapter/persistence/StoreAndForward.java @@ -5,6 +5,7 @@ import java.io.InputStream; import java.io.OutputStream; import java.net.ServerSocket; import java.net.Socket; +import java.net.SocketException; import java.net.UnknownHostException; import java.util.ArrayList; import java.util.Collections; @@ -266,67 +267,75 @@ public class StoreAndForward implements Runnable { while (!stopped) { try { InputStream is = socket.getInputStream(); - Pair messageAndOptionalSequenceNumber = transceiver.receiveMessage(is); - if (messageAndOptionalSequenceNumber == null) { - // found EOF; stopping - stopped = true; - } else { - // ignore any sequence number contained in the message; we'll create our own - DBObject emptyQuery = new BasicDBObject(); - DBObject incrementLastMessageCountQuery = new BasicDBObject().append("$inc", - new BasicDBObject().append(FieldNames.LAST_MESSAGE_COUNT.name(), 1)); - while (!stopped && messageAndOptionalSequenceNumber != null) { - logger.fine("Thread " + this + " received message: " - + messageAndOptionalSequenceNumber.getA()); - DBObject newCountRecord = lastMessageCountCollection.findAndModify(emptyQuery, - incrementLastMessageCountQuery); - lastMessageCount = ((newCountRecord == null) ? 0l : ((Number) newCountRecord - .get(FieldNames.LAST_MESSAGE_COUNT.name())).longValue()); - SailMasterMessage message = swissTimingFactory.createMessage( - messageAndOptionalSequenceNumber.getA(), lastMessageCount); - swissTimingAdapterPersistence.storeSailMasterMessage(message); - synchronized (StoreAndForward.this) { - for (OutputStream os : new ArrayList(streamsToForwardTo)) { - // write the sequence number of the message into the stream before actually writing - // the - // SwissTiming message - try { - transceiver.sendMessage(message, os); - } catch (Exception e) { - logger.log(Level.SEVERE, "Error sending message to " + os, e); - int i = streamsToForwardTo.indexOf(os); + try { + Pair messageAndOptionalSequenceNumber = transceiver.receiveMessage(is); + if (messageAndOptionalSequenceNumber == null) { + // found EOF; stopping + stopped = true; + } else { + // ignore any sequence number contained in the message; we'll create our own + DBObject emptyQuery = new BasicDBObject(); + DBObject incrementLastMessageCountQuery = new BasicDBObject().append("$inc", + new BasicDBObject().append(FieldNames.LAST_MESSAGE_COUNT.name(), 1)); + while (!stopped && messageAndOptionalSequenceNumber != null) { + logger.fine("Thread " + this + " received message: " + + messageAndOptionalSequenceNumber.getA()); + DBObject newCountRecord = lastMessageCountCollection.findAndModify(emptyQuery, + incrementLastMessageCountQuery); + lastMessageCount = ((newCountRecord == null) ? 0l : ((Number) newCountRecord + .get(FieldNames.LAST_MESSAGE_COUNT.name())).longValue()); + SailMasterMessage message = swissTimingFactory.createMessage( + messageAndOptionalSequenceNumber.getA(), lastMessageCount); + swissTimingAdapterPersistence.storeSailMasterMessage(message); + synchronized (StoreAndForward.this) { + for (OutputStream os : new ArrayList(streamsToForwardTo)) { + // write the sequence number of the message into the stream before actually + // writing + // the + // SwissTiming message try { - os.close(); - } catch (Exception exc) { - logger.log(Level.SEVERE, "Exception closing socket output stream " + os - + " after being unable to forward message " + message, exc); - } - streamsToForwardTo.remove(os); - Socket s = socketsToForwardTo.remove(i); - logger.info("Unable to send to socket " + s - + ". Trying to close. Removing from sockets to forward to."); - try { - s.close(); - } catch (Exception exc) { - logger.log(Level.WARNING, "Exception trying to close socket " + s - + " after being unable to forward message " + message, exc); + transceiver.sendMessage(message, os); + } catch (Exception e) { + logger.log(Level.SEVERE, "Error sending message to " + os, e); + int i = streamsToForwardTo.indexOf(os); + try { + os.close(); + } catch (Exception exc) { + logger.log(Level.SEVERE, "Exception closing socket output stream " + os + + " after being unable to forward message " + message, exc); + } + streamsToForwardTo.remove(os); + Socket s = socketsToForwardTo.remove(i); + logger.info("Unable to send to socket " + s + + ". Trying to close. Removing from sockets to forward to."); + try { + s.close(); + } catch (Exception exc) { + logger.log(Level.WARNING, "Exception trying to close socket " + s + + " after being unable to forward message " + message, exc); + } } } } - } - if (!stopped) { - messageAndOptionalSequenceNumber = transceiver.receiveMessage(is); - if (messageAndOptionalSequenceNumber == null) { - // received EOF; stopping received - stopped = true; + if (!stopped) { + messageAndOptionalSequenceNumber = transceiver.receiveMessage(is); + if (messageAndOptionalSequenceNumber == null) { + // received EOF; stopping received + stopped = true; + } } } } + } catch (SocketException e) { + logger.log( + Level.INFO, + "Error during receiving message. Terminating this receiver and waiting for another inbound connection.", + e); + stopped = true; } // note that we're not changing anything with the sockets to which we forward messages; that will only happen // if forwarding to any of those sockets fails } catch (Exception e) { - e.printStackTrace(); if (!stopped) { logger.log(Level.INFO, "Error during forwarding message. Continuing...", e); try { @@ -402,7 +411,7 @@ public class StoreAndForward implements Runnable { try { ReceivingThread receivingThread = establishConnection(); if (!isInSailMasterListeningMode()) { - receivingThread.join(); // we're in active connecting mode; wait for thread to die, then trie again + receivingThread.join(); // we're in active connecting mode; wait for thread to die, then try again } } catch (Exception e) { logger.log(Level.SEVERE, "Exception in StoreAndForward", e);