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.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"; 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 old mode 100644 new mode 100755 index 2c5021b1fc5..dcfca33d16c --- 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 @@ -190,6 +190,11 @@ public class NoAddingRaceLogWrapper implements RaceLog { return innerRaceLog.getRawFixesDescendingIterator(startingAt, inclusive); } + @Override + public Iterable getEventsToDeliver(UUID clientId) { + return innerRaceLog.getEventsToDeliver(clientId); + } + @Override public Iterable getFixes(TimePoint from, boolean fromInclusive, TimePoint to, boolean toInclusive) { return innerRaceLog.getFixes(from, fromInclusive, to, toInclusive); 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..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 @@ -152,9 +152,23 @@ public class RaceLogImpl extends TrackImpl implements RaceLog { } else { logger.warning(String.format("%s (%s) was not added to log. Ignoring", event, event.getClass().getName())); } - // FIXME lock for read getInternalRawFixes? - LinkedHashSet stillToDeliverToClient = new LinkedHashSet(getInternalRawFixes()); - stillToDeliverToClient.remove(event); + return getEventsToDeliver(clientId, event); + } + + @Override + public Iterable getEventsToDeliver(UUID clientId) { + return getEventsToDeliver(clientId, null); + } + + protected Iterable getEventsToDeliver(UUID clientId, RaceLogEvent suppressedEvent) { + final LinkedHashSet stillToDeliverToClient; + lockForRead(); + try { + stillToDeliverToClient = new LinkedHashSet(getInternalRawFixes()); + } finally { + unlockAfterRead(); + } + stillToDeliverToClient.remove(suppressedEvent); Set deliveredToClient = eventsDeliveredToClient.get(clientId); if (deliveredToClient != null) { stillToDeliverToClient.removeAll(deliveredToClient); @@ -163,7 +177,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.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/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); 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/.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/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/java/com.sap.sailing.gwt.ui/pom.xml b/java/com.sap.sailing.gwt.ui/pom.xml index b39a75baf83..40a053817e1 100644 --- a/java/com.sap.sailing.gwt.ui/pom.xml +++ b/java/com.sap.sailing.gwt.ui/pom.xml @@ -81,6 +81,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/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/adminconsole/EventDialog.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/EventDialog.java index 83fa01c9a27..64fe5f47f8a 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 144bb2b4ead..affa5bda89c 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 @@ -299,7 +299,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; } }; @@ -324,7 +324,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, @@ -340,7 +340,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); } } @@ -1111,7 +1111,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) { @@ -1167,7 +1167,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 e23de300135..67710bea756 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 657cc546fb0..ac537274225 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 48dd2017607..f884564dbf8 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 c81fea1eb4b..2994e4f8436 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 old mode 100644 new mode 100755 index 540f6e42a63..a98472806b2 --- 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 @@ -5,6 +5,7 @@ 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; @@ -132,9 +133,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); @@ -156,13 +157,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); @@ -250,18 +251,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(); @@ -311,17 +314,15 @@ public interface SailingService extends RemoteService { PolarSheetGenerationResponse generatePolarSheetForRaces(List selectedRaces, PolarSheetGenerationSettings settings, String name) throws Exception; - 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 46d85e39069..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 @@ -5,6 +5,7 @@ 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.datamining.shared.DataMiningSerializationDummy; @@ -182,9 +183,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, @@ -327,21 +328,21 @@ public interface SailingServiceAsync { * 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 +362,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 +426,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 +441,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); @@ -482,8 +481,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); @@ -496,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/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; + } + +} 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 ba062810f75..619c3901149 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 5f32c3de86e..28c1c43d645 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 98b2f72dc5d..382b297c3d2 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; @@ -59,12 +61,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; @@ -668,7 +670,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()); @@ -1822,20 +1824,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) { @@ -1928,7 +1919,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); @@ -1959,9 +1950,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); } @@ -2761,9 +2751,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 @@ -2771,35 +2760,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 @@ -2813,14 +2799,9 @@ public class SailingServiceImpl extends ProxiedRemoteServiceServlet implements S } return result; } - - @Override - public EventDTO getEventByIdAsString(String eventIdAsString) { - UUID eventUuid = convertIdentifierStringToUuid(eventIdAsString); - return getEventById(eventUuid); - } - private EventDTO getEventById(UUID id) { + @Override + public EventDTO getEventById(UUID id) { EventDTO result = null; Event event = getService().getEvent(id); if (event != null) { @@ -2835,7 +2816,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(); @@ -2852,14 +2833,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()) { @@ -2938,10 +2919,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 @@ -2997,13 +2977,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); } @@ -3164,17 +3143,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()) { @@ -3356,7 +3335,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 +3345,20 @@ public class SailingServiceImpl extends ProxiedRemoteServiceServlet implements S connection = (HttpURLConnection)serverAddress.openConnection(); connection.setRequestMethod("GET"); connection.setDoOutput(true); - connection.setReadTimeout(10000); + // Initial timeout needs to be big enough to allow the first parts of the response to reach this server + 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 +3374,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) { } @@ -3626,7 +3612,7 @@ public class SailingServiceImpl extends ProxiedRemoteServiceServlet implements S if (result == null || result.getA() == null) { return null; } - return new Pair(result.getA().asDate(), result.getB()); + return new Pair(result.getA() == null ? null : result.getA().asDate(), result.getB()); } @Override @@ -3703,4 +3689,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 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/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/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 635133eb9fd..536416af269 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,63 +1,67 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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 f3303295e58..4280877a4c0 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,40 +1,41 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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 a8a6196325c..a24a9872828 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,41 +1,42 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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 old mode 100644 new mode 100755 index 537d1a83962..8b97eba9ede --- 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,34 +1,35 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ 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 old mode 100644 new mode 100755 index 926be3928b6..bf79c3849fe --- 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,45 +1,46 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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 old mode 100644 new mode 100755 index 20958b117e1..cbd506a8ecc --- 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,52 +1,53 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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 old mode 100644 new mode 100755 index 5579d461132..208f86673ec --- 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,50 +1,51 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ 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 old mode 100644 new mode 100755 index 6567bfbab48..e22ec208b6c --- 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,37 +1,38 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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 old mode 100644 new mode 100755 index 66c7e3caf85..53a661e0114 --- 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,44 +1,45 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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 9661ca8a8a8..cc721d3e60c 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,36 +1,37 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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 old mode 100644 new mode 100755 index 17af566e72b..fc3383256be --- 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,17 +1,18 @@ - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + \ 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 old mode 100644 new mode 100755 index f1f2d367917..e22592ab2cf --- 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,7 +3,8 @@ - + + 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/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); 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 4bf3087fd6b..304e7a17023 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 @@ -426,7 +426,7 @@ public interface RacingEventService extends TrackedRegattaRegistry, RegattaFetch UUID id); CourseArea addCourseAreaWithoutReplication(UUID eventId, UUID courseAreaId, String courseAreaName); - + /** * Returns a mobile device's configuration. * @param identifier of the client (may include event) @@ -454,7 +454,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 @@ -469,10 +469,9 @@ 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. Returns null if there - * is no attached race log. + * Gets the start time and pass identifier for the queried race. Start time might be null. */ - Pair getStartTime(String leaderboardName, String raceColumnName, String fleetName); + Pair getStartTime(String leaderboardName, String raceColumnName, String fleetName); MongoObjectFactory getMongoObjectFactory(); 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 e8c25eda183..ae035a6c6ee 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 @@ -235,6 +235,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; @@ -1275,14 +1279,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; } 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" > Linie Ablauf - - Nach oben - Nach unten - Entfernen - Veröffentlichen Zurücknehmen @@ -130,7 +125,7 @@ Windeingaben speichern - Allgemeine Einstellungen + Weitere Einstellungen Verwaltete Rennbahnen Sprache auswählen Sprache auswählen. Eventuell muss die App neugestartet werden. @@ -139,14 +134,17 @@ 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. 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 @@ -182,9 +180,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/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 04bdf6e5ead..c4ff47d9695 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 @@ -128,13 +128,11 @@ Store wind - General + Other Managed Course Areas 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. @@ -142,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 @@ -165,13 +168,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 @@ -195,8 +198,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 @@ -228,4 +229,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/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/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/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/configuration/impl/PreferencesDeviceConfigurationLoader.java b/mobile/com.sap.sailing.racecommittee.app/src/com/sap/sailing/racecommittee/app/domain/configuration/impl/PreferencesDeviceConfigurationLoader.java index 40d81de3f6a..6ec16af8222 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..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 @@ -2,6 +2,7 @@ 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; @@ -9,35 +10,60 @@ 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 onReply(Intent originalIntent, Context context, InputStream inputStream) { + 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(inputStream)); + 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); @@ -45,24 +71,79 @@ public class RaceLogEventsCallback implements ServerReplyCallback { } } catch (Exception e) { ExLog.e(TAG, "Error parsing server response"); - //ExLog.ex(TAG, e); + } + + 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) { - 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 1d741ecda32..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)) { @@ -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, serializedEventJson, 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..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; @@ -18,7 +19,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); } @@ -56,7 +64,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..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,12 +1,13 @@ package com.sap.sailing.racecommittee.app.services.sending; -import java.io.IOException; import java.io.InputStream; 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 +51,12 @@ public class EventSendingService extends Service implements EventSendingListener private final IBinder mBinder = new EventSendingBinder(); private EventPersistenceManager persistenceManager; private boolean isHandlerSet; + + private Set suppressedEventIds = new HashSet(); + + public void registerEventForSuppression(Serializable eventId) { + suppressedEventIds.add(eventId); + } private EventSendingServiceLogger serviceLogger = new EventSendingServiceLogger() { @Override @@ -102,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. @@ -116,28 +135,34 @@ 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&"+ - 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); - return createEventIntent(context, url, race.getId(), serializedEventAsJson, callbackClass); + String url = getRaceLogEventSendAndReceiveUrl(context, + race.getRaceGroup().getName(), race.getName(), race.getFleet().getName()); + 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, "Unable to extract event identifier from event intent."); + return null; + } /* * (non-Javadoc) @@ -213,13 +238,19 @@ 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)) { + suppressedEventIds.remove(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,11 +279,9 @@ public class EventSendingService extends Service implements EventSendingListener } } if (callback != null) { - callback.onReply(intent, this, inputStream); + 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/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..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 @@ -1,6 +1,7 @@ package com.sap.sailing.racecommittee.app.services.sending; import java.io.InputStream; +import java.io.Serializable; import android.content.Context; import android.content.Intent; @@ -18,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 onReply(Intent originalIntent, Context context, InputStream inputStream); + void processResponse(Context context, InputStream inputStream, Serializable raceId); } 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/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/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/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/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/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 { @@ -33,8 +33,7 @@ public class RRS26RunningRaceFragment extends BaseRunningRaceFragment + + + + \ No newline at end of file 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