diff --git a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/base/racegroup/RaceCell.java b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/base/racegroup/RaceCell.java index d86e479054a..a90347df508 100644 --- a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/base/racegroup/RaceCell.java +++ b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/base/racegroup/RaceCell.java @@ -1,6 +1,5 @@ package com.sap.sailing.domain.base.racegroup; -import com.sap.sailing.domain.base.Competitor; import com.sap.sailing.domain.common.Named; import com.sap.sailing.domain.racelog.RaceLog; @@ -13,6 +12,4 @@ import com.sap.sailing.domain.racelog.RaceLog; */ public interface RaceCell extends Named { RaceLog getRaceLog(); - - Iterable getCompetitors(); } diff --git a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/base/racegroup/impl/RaceCellImpl.java b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/base/racegroup/impl/RaceCellImpl.java index 6d9a3b0a9b7..82fdd4a2fa7 100644 --- a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/base/racegroup/impl/RaceCellImpl.java +++ b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/base/racegroup/impl/RaceCellImpl.java @@ -1,6 +1,5 @@ package com.sap.sailing.domain.base.racegroup.impl; -import com.sap.sailing.domain.base.Competitor; import com.sap.sailing.domain.base.racegroup.RaceCell; import com.sap.sailing.domain.common.impl.NamedImpl; import com.sap.sailing.domain.racelog.RaceLog; @@ -9,12 +8,10 @@ public class RaceCellImpl extends NamedImpl implements RaceCell { private static final long serialVersionUID = 971598420407273594L; private RaceLog raceLog; - private Iterable competitors; - public RaceCellImpl(String name, RaceLog raceLog, Iterable competitors) { + public RaceCellImpl(String name, RaceLog raceLog) { super(name); this.raceLog = raceLog; - this.competitors = competitors; } @Override @@ -22,9 +19,4 @@ public class RaceCellImpl extends NamedImpl implements RaceCell { return raceLog; } - @Override - public Iterable getCompetitors() { - return competitors; - } - } diff --git a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/base/impl/CourseImpl.java b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/base/impl/CourseImpl.java index 3caaaafd5bc..5847a1ab27a 100755 --- a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/base/impl/CourseImpl.java +++ b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/base/impl/CourseImpl.java @@ -3,6 +3,7 @@ package com.sap.sailing.domain.base.impl; import java.io.IOException; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; +import java.io.Serializable; import java.util.ArrayList; import java.util.HashMap; import java.util.HashSet; @@ -43,8 +44,16 @@ public class CourseImpl extends NamedImpl implements Course { private transient Set listeners; private transient NamedReentrantReadWriteLock lock; + /** + * This monitor is used to serialize calls to {@link #update(List, DomainFactory)}. This helps to guarantee that + * the transition from a read lock to a write lock, in case a write is actually needed, isn't interrupted by any other + * call to {@link #update(List, DomainFactory)}. + */ + private final Serializable updateMonitor; + public CourseImpl(String name, Iterable waypoints) { super(name); + updateMonitor = ""; lock = new NamedReentrantReadWriteLock("lock for CourseImpl "+name, /* fair */ true); // if non-fair, course update may need to wait forever for many concurrent readers listeners = new HashSet(); @@ -320,7 +329,7 @@ public class CourseImpl extends NamedImpl implements Course { } @Override - public synchronized Waypoint getWaypointForControlPoint(ControlPoint controlPoint, int start) { + public Waypoint getWaypointForControlPoint(ControlPoint controlPoint, int start) { lockForRead(); try { if (start > legs.size()) { @@ -372,44 +381,51 @@ public class CourseImpl extends NamedImpl implements Course { @Override public void update(List> newControlPoints, DomainFactory baseDomainFactory) throws PatchFailedException { - LockUtil.lockForWrite(lock); - try { - Iterable courseWaypoints = getWaypoints(); - List newWaypointList = new LinkedList(); - // key existing waypoints by control points and re-use each one at most once during construction of the - // new waypoint list; since several waypoints can have the same control point, the map goes from - // control point to List. The waypoints in the lists are held in the order of their - // occurrence in courseToUpdate.getWaypoints(). - Map> existingWaypointsByControlPoint = - new HashMap>(); - for (Waypoint waypoint : courseWaypoints) { - List wpl = existingWaypointsByControlPoint.get(waypoint.getControlPoint()); - if (wpl == null) { - wpl = new ArrayList(); - existingWaypointsByControlPoint.put(waypoint.getControlPoint(), wpl); + Patch patch = null; + synchronized (updateMonitor) { + lockForRead(); + try { + Iterable courseWaypoints = getWaypoints(); + List newWaypointList = new LinkedList(); + // key existing waypoints by control points and re-use each one at most once during construction of the + // new waypoint list; since several waypoints can have the same control point, the map goes from + // control point to List. The waypoints in the lists are held in the order of their + // occurrence in courseToUpdate.getWaypoints(). + Map> existingWaypointsByControlPoint = new HashMap>(); + for (Waypoint waypoint : courseWaypoints) { + List wpl = existingWaypointsByControlPoint.get(waypoint.getControlPoint()); + if (wpl == null) { + wpl = new ArrayList(); + existingWaypointsByControlPoint.put(waypoint.getControlPoint(), wpl); + } + wpl.add(waypoint); } - wpl.add(waypoint); - } - for (Pair newDomainControlPoint : newControlPoints) { - List waypoints = existingWaypointsByControlPoint.get(newDomainControlPoint.getA()); - Waypoint waypoint; - if (waypoints == null || waypoints.isEmpty()) { - // must be a new control point for which we don't have a waypoint yet - waypoint = baseDomainFactory.createWaypoint(newDomainControlPoint.getA(), newDomainControlPoint.getB()); - } else { - waypoint = waypoints.remove(0); // take the first from the list + for (Pair newDomainControlPoint : newControlPoints) { + List waypoints = existingWaypointsByControlPoint.get(newDomainControlPoint.getA()); + Waypoint waypoint; + if (waypoints == null || waypoints.isEmpty()) { + // must be a new control point for which we don't have a waypoint yet + waypoint = baseDomainFactory.createWaypoint(newDomainControlPoint.getA(), + newDomainControlPoint.getB()); + } else { + waypoint = waypoints.remove(0); // take the first from the list + } + newWaypointList.add(waypoint); } - newWaypointList.add(waypoint); + patch = DiffUtils.diff(courseWaypoints, newWaypointList); + } finally { + unlockAfterRead(); } - Patch patch = DiffUtils.diff(courseWaypoints, newWaypointList); - if (!patch.isEmpty()) { - logger.info("applying course update " + patch + " to course " + this); - CourseAsWaypointList courseAsWaypointList = new CourseAsWaypointList(this); - patch.applyToInPlace(courseAsWaypointList); + if (patch != null && !patch.isEmpty()) { + lockForWrite(); + try { + logger.info("applying course update " + patch + " to course " + this); + CourseAsWaypointList courseAsWaypointList = new CourseAsWaypointList(this); + patch.applyToInPlace(courseAsWaypointList); + } finally { + unlockAfterWrite(); + } } - } finally { - LockUtil.unlockAfterWrite(lock); } } - } 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 bcf436fa2db..ba0dc67f876 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 @@ -871,7 +871,7 @@ public class SailingServiceImpl extends ProxiedRemoteServiceServlet implements S LegEntryDTO legEntry; // We loop over a copy of the course's legs; during a course change, legs may become "stale," even with // regard to the leg/trackedLeg structures inside the tracked race which is updated by the course change - // immediately. Make sure we're tolerant against disappearing legs! See bug 794. + // immediately. That's why we've acquired a read lock for the course above. TrackedLegOfCompetitor trackedLeg = trackedRace.getTrackedLeg(competitor, leg); if (trackedLeg != null && trackedLeg.hasStartedLeg(timePoint)) { legEntry = createLegEntry(trackedLeg, timePoint, waitForLatestAnalyses, legRanksCache); diff --git a/java/com.sap.sailing.server.gateway.serialization/src/com/sap/sailing/server/gateway/serialization/racegroup/impl/RaceCellJsonSerializer.java b/java/com.sap.sailing.server.gateway.serialization/src/com/sap/sailing/server/gateway/serialization/racegroup/impl/RaceCellJsonSerializer.java index 637908b0859..e94b3367d67 100644 --- a/java/com.sap.sailing.server.gateway.serialization/src/com/sap/sailing/server/gateway/serialization/racegroup/impl/RaceCellJsonSerializer.java +++ b/java/com.sap.sailing.server.gateway.serialization/src/com/sap/sailing/server/gateway/serialization/racegroup/impl/RaceCellJsonSerializer.java @@ -1,9 +1,7 @@ package com.sap.sailing.server.gateway.serialization.racegroup.impl; -import org.json.simple.JSONArray; import org.json.simple.JSONObject; -import com.sap.sailing.domain.base.Competitor; import com.sap.sailing.domain.base.racegroup.RaceCell; import com.sap.sailing.domain.racelog.RaceLog; import com.sap.sailing.server.gateway.serialization.JsonSerializer; @@ -14,11 +12,9 @@ public class RaceCellJsonSerializer implements JsonSerializer { public static final String FIELD_COMPETITORS = "competitors"; private JsonSerializer logSerializer; - private JsonSerializer competitorSerializer; - public RaceCellJsonSerializer(JsonSerializer logSerializer, JsonSerializer competitorSerializer) { + public RaceCellJsonSerializer(JsonSerializer logSerializer) { this.logSerializer = logSerializer; - this.competitorSerializer = competitorSerializer; } @Override @@ -27,18 +23,8 @@ public class RaceCellJsonSerializer implements JsonSerializer { result.put(FIELD_NAME, object.getName()); result.put(FIELD_RACE_LOG, logSerializer.serialize(object.getRaceLog())); - JSONArray competitorArray = getJSONCompetitorArray(object); - result.put(FIELD_COMPETITORS, competitorArray); return result; } - private JSONArray getJSONCompetitorArray(RaceCell object) { - JSONArray competitorArray = new JSONArray(); - for (Competitor competitor : object.getCompetitors()) { - competitorArray.add(competitorSerializer.serialize(competitor)); - } - return competitorArray; - } - } diff --git a/java/com.sap.sailing.server.gateway/WEB-INF/web.xml b/java/com.sap.sailing.server.gateway/WEB-INF/web.xml index 6b4ebc8b031..4430dca51d6 100644 --- a/java/com.sap.sailing.server.gateway/WEB-INF/web.xml +++ b/java/com.sap.sailing.server.gateway/WEB-INF/web.xml @@ -50,6 +50,15 @@ /rc/currentcourse + + RCCompetitors + com.sap.sailing.server.gateway.impl.rc.CompetitorsJsonExportServlet + + + RCCompetitors + /rc/competitors + + diff --git a/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/impl/rc/CompetitorsJsonExportServlet.java b/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/impl/rc/CompetitorsJsonExportServlet.java new file mode 100644 index 00000000000..e87693f5f1b --- /dev/null +++ b/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/impl/rc/CompetitorsJsonExportServlet.java @@ -0,0 +1,86 @@ +package com.sap.sailing.server.gateway.impl.rc; + +import java.io.IOException; + +import javax.servlet.ServletException; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.json.simple.JSONArray; + +import com.sap.sailing.domain.base.Competitor; +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.tracking.TrackedRace; +import com.sap.sailing.server.RacingEventService; +import com.sap.sailing.server.gateway.AbstractJsonHttpServlet; +import com.sap.sailing.server.gateway.serialization.racegroup.impl.CompetitorJsonSerializer; + +public class CompetitorsJsonExportServlet extends AbstractJsonHttpServlet { + private static final long serialVersionUID = 4510175441769759252L; + + public static final String PARAMS_LEADERBOARD_NAME = "leaderboard"; + public static final String PARAMS_RACE_COLUMN_NAME = "raceColumn"; + public static final String PARAMS_RACE_FLEET_NAME = "fleet"; + + @Override + protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { + + String leaderboardName = request.getParameter(PARAMS_LEADERBOARD_NAME); + if (leaderboardName == null) { + response.sendError(HttpServletResponse.SC_BAD_REQUEST, + String.format("Missing parameter '%s'.", PARAMS_LEADERBOARD_NAME)); + return; + } + + String raceColumnName = request.getParameter(PARAMS_RACE_COLUMN_NAME); + if (raceColumnName == null) { + response.sendError(HttpServletResponse.SC_BAD_REQUEST, + String.format("Missing parameter '%s'.", PARAMS_RACE_COLUMN_NAME)); + return; + } + + String fleetName = request.getParameter(PARAMS_RACE_FLEET_NAME); + if (fleetName == null) { + response.sendError(HttpServletResponse.SC_BAD_REQUEST, + String.format("Missing parameter '%s'.", PARAMS_RACE_FLEET_NAME)); + return; + } + + RacingEventService service = getService(); + + Leaderboard leaderboard = service.getLeaderboardByName(leaderboardName); + if (leaderboard == null) { + response.sendError(HttpServletResponse.SC_NOT_FOUND, "No such leaderboard found."); + return; + } + + RaceColumn raceColumn = leaderboard.getRaceColumnByName(raceColumnName); + if (raceColumn == null) { + response.sendError(HttpServletResponse.SC_NOT_FOUND, "No such race column found."); + return; + } + + Fleet fleet = raceColumn.getFleetByName(fleetName); + if (fleet == null) { + response.sendError(HttpServletResponse.SC_NOT_FOUND, "No such fleet found."); + return; + } + + TrackedRace trackedRace = raceColumn.getTrackedRace(fleet); + + JSONArray result = new JSONArray(); + + if (trackedRace != null) { + CompetitorJsonSerializer serializer = new CompetitorJsonSerializer(); + + for (Competitor competitor : raceColumn.getRaceDefinition(fleet).getCompetitors()) { + result.add(serializer.serialize(competitor)); + } + } + + result.writeJSONString(response.getWriter()); + response.setContentType("application/json"); + } +} diff --git a/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/impl/rc/RaceGroupFactory.java b/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/impl/rc/RaceGroupFactory.java index 11d71582fd9..6a42cf54a19 100644 --- a/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/impl/rc/RaceGroupFactory.java +++ b/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/impl/rc/RaceGroupFactory.java @@ -8,7 +8,6 @@ import java.util.List; import java.util.Map; import com.sap.sailing.domain.base.BoatClass; -import com.sap.sailing.domain.base.Competitor; import com.sap.sailing.domain.base.CourseArea; import com.sap.sailing.domain.base.Fleet; import com.sap.sailing.domain.base.RaceColumn; @@ -24,7 +23,6 @@ import com.sap.sailing.domain.base.racegroup.impl.RaceGroupImpl; import com.sap.sailing.domain.base.racegroup.impl.RaceRowImpl; import com.sap.sailing.domain.base.racegroup.impl.SeriesWithRowsImpl; import com.sap.sailing.domain.common.LeaderboardNameConstants; -import com.sap.sailing.domain.common.impl.Util; import com.sap.sailing.domain.leaderboard.Leaderboard; import com.sap.sailing.domain.leaderboard.RegattaLeaderboard; @@ -79,11 +77,7 @@ public class RaceGroupFactory { Collection cells = new ArrayList<>(); for (RaceColumn raceColumn : raceColumns) { Fleet fleet = raceColumn.getFleetByName(fleetName); - Collection competitors = new ArrayList(); - if (raceColumn.getRaceDefinition(fleet) != null) { - Util.addAll(raceColumn.getRaceDefinition(fleet).getCompetitors(), competitors); - } - cells.add(new RaceCellImpl(raceColumn.getName(), raceColumn.getRaceLog(fleet), competitors)); + cells.add(new RaceCellImpl(raceColumn.getName(), raceColumn.getRaceLog(fleet))); } return cells; } diff --git a/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/impl/rc/RaceGroupJsonExportServlet.java b/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/impl/rc/RaceGroupJsonExportServlet.java index aaa618ef3a3..394ec968e64 100644 --- a/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/impl/rc/RaceGroupJsonExportServlet.java +++ b/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/impl/rc/RaceGroupJsonExportServlet.java @@ -81,7 +81,7 @@ public class RaceGroupJsonExportServlet extends AbstractJsonHttpServlet { return new RaceGroupJsonSerializer(new BoatClassJsonSerializer(), new CourseAreaJsonSerializer(), new SeriesWithRowsOfRaceGroupSerializer(new SeriesWithRowsJsonSerializer( new RaceRowsOfSeriesWithRowsSerializer(new RaceRowJsonSerializer(new FleetJsonSerializer( - new ColorJsonSerializer()), new RaceCellJsonSerializer(createRaceLogSerializer(), new CompetitorJsonSerializer())))))); + new ColorJsonSerializer()), new RaceCellJsonSerializer(createRaceLogSerializer())))))); } diff --git a/mobile/com.sap.sailing.racecommittee.app/src/com/sap/sailing/racecommittee/app/data/OfflineDataManager.java b/mobile/com.sap.sailing.racecommittee.app/src/com/sap/sailing/racecommittee/app/data/OfflineDataManager.java index c51ed554245..1bf59279267 100644 --- a/mobile/com.sap.sailing.racecommittee.app/src/com/sap/sailing/racecommittee/app/data/OfflineDataManager.java +++ b/mobile/com.sap.sailing.racecommittee.app/src/com/sap/sailing/racecommittee/app/data/OfflineDataManager.java @@ -89,7 +89,7 @@ public class OfflineDataManager extends DataManager { new FleetImpl("Default"), qualifying, raceGroup), - log, competitors); + log); log = new PassAwareRaceLogImpl(); /*log.add(factory.createStartTimeEvent( @@ -105,7 +105,7 @@ public class OfflineDataManager extends DataManager { new FleetImpl("Default"), qualifying, raceGroup), - log, competitors); + log); log = new PassAwareRaceLogImpl(); /*log.add(factory.createRaceStatusEvent( @@ -118,7 +118,7 @@ public class OfflineDataManager extends DataManager { new FleetImpl("Default"), qualifying, raceGroup), - log, competitors); + log); /*ManagedRace m1 = new ManagedRaceImpl( new ManagedRaceIdentifierImpl( "M1", @@ -164,4 +164,9 @@ public class OfflineDataManager extends DataManager { client.onLoadSucceded(managedRace.getCourseOnServer()); } + @Override + public void loadCompetitors(ManagedRace managedRace, LoadClient> client) { + client.onLoadSucceded((Collection) managedRace.getCompetitors()); + } + } 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 efe1c9adfd8..98b5fc557d5 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 @@ -10,6 +10,7 @@ import java.util.Collection; import android.content.Context; import com.sap.sailing.domain.base.BoatClass; +import com.sap.sailing.domain.base.Competitor; import com.sap.sailing.domain.base.CourseArea; import com.sap.sailing.domain.base.CourseBase; import com.sap.sailing.domain.base.EventBase; @@ -17,12 +18,14 @@ import com.sap.sailing.domain.base.Mark; import com.sap.sailing.domain.base.SharedDomainFactory; import com.sap.sailing.racecommittee.app.AppConstants; import com.sap.sailing.racecommittee.app.data.clients.LoadClient; +import com.sap.sailing.racecommittee.app.data.handlers.CompetitorsDataHandler; import com.sap.sailing.racecommittee.app.data.handlers.CourseDataHandler; import com.sap.sailing.racecommittee.app.data.handlers.DataHandler; import com.sap.sailing.racecommittee.app.data.handlers.EventsDataHandler; import com.sap.sailing.racecommittee.app.data.handlers.ManagedRacesDataHandler; import com.sap.sailing.racecommittee.app.data.handlers.MarksDataHandler; import com.sap.sailing.racecommittee.app.data.loaders.DataLoader; +import com.sap.sailing.racecommittee.app.data.parsers.CompetitorsDataParser; import com.sap.sailing.racecommittee.app.data.parsers.CourseDataParser; import com.sap.sailing.racecommittee.app.data.parsers.DataParser; import com.sap.sailing.racecommittee.app.data.parsers.EventsDataParser; @@ -142,7 +145,7 @@ public class OnlineDataManager extends DataManager { DataParser> parser = new ManagedRacesDataParser(new RaceGroupDeserializer( boatClassDeserializer, new SeriesWithRowsDeserializer(new RaceRowDeserializer(new FleetDeserializer( new ColorDeserializer()), new RaceCellDeserializer( - new RaceLogDeserializer(RaceLogEventDeserializer.create(domainFactory)), new CompetitorDeserializer(domainFactory)))))); + new RaceLogDeserializer(RaceLogEventDeserializer.create(domainFactory))))))); DataHandler> handler = new ManagedRacesDataHandler(this, client); try { @@ -215,4 +218,29 @@ public class OnlineDataManager extends DataManager { e.printStackTrace(); } } + + @Override + public void loadCompetitors(ManagedRace managedRace, LoadClient> client) { + SharedDomainFactory domainFactory = DomainFactoryImpl.INSTANCE; + JsonDeserializer competitorDeserializer = new CompetitorDeserializer(domainFactory); + DataParser> parser = new CompetitorsDataParser(competitorDeserializer); + DataHandler> handler = new CompetitorsDataHandler(this, client, managedRace); + + ManagedRaceIdentifier identifier = managedRace.getIdentifier(); + + String raceGroupName = URLEncoder.encode(identifier.getRaceGroup().getName()); + String raceColumnName = URLEncoder.encode(identifier.getRaceName()); + String fleetName = URLEncoder.encode(identifier.getFleet().getName()); + + try { + new DataLoader>(context, URI.create(AppConstants.getServerBaseURL(context) + + "/sailingserver/rc/competitors?leaderboard=" + raceGroupName + "&raceColumn=" + raceColumnName + + "&fleet=" + fleetName), parser, handler) + .forceLoad(); + } catch (MalformedURLException e) { + e.printStackTrace(); + } catch (IOException e) { + e.printStackTrace(); + } + } } diff --git a/mobile/com.sap.sailing.racecommittee.app/src/com/sap/sailing/racecommittee/app/data/ReadonlyDataManager.java b/mobile/com.sap.sailing.racecommittee.app/src/com/sap/sailing/racecommittee/app/data/ReadonlyDataManager.java index 79c64213f49..903837f9940 100644 --- a/mobile/com.sap.sailing.racecommittee.app/src/com/sap/sailing/racecommittee/app/data/ReadonlyDataManager.java +++ b/mobile/com.sap.sailing.racecommittee.app/src/com/sap/sailing/racecommittee/app/data/ReadonlyDataManager.java @@ -3,6 +3,7 @@ package com.sap.sailing.racecommittee.app.data; import java.io.Serializable; import java.util.Collection; +import com.sap.sailing.domain.base.Competitor; import com.sap.sailing.domain.base.CourseArea; import com.sap.sailing.domain.base.CourseBase; import com.sap.sailing.domain.base.EventBase; @@ -23,4 +24,6 @@ public interface ReadonlyDataManager { public void loadMarks(ManagedRace managedRace, LoadClient> client); public void loadCourse(ManagedRace managedRace, LoadClient client); + + public void loadCompetitors(ManagedRace managedRace, LoadClient> client); } diff --git a/mobile/com.sap.sailing.racecommittee.app/src/com/sap/sailing/racecommittee/app/data/handlers/CompetitorsDataHandler.java b/mobile/com.sap.sailing.racecommittee.app/src/com/sap/sailing/racecommittee/app/data/handlers/CompetitorsDataHandler.java new file mode 100644 index 00000000000..03cd7d7d7bf --- /dev/null +++ b/mobile/com.sap.sailing.racecommittee.app/src/com/sap/sailing/racecommittee/app/data/handlers/CompetitorsDataHandler.java @@ -0,0 +1,25 @@ +package com.sap.sailing.racecommittee.app.data.handlers; + +import java.util.Collection; + +import com.sap.sailing.domain.base.Competitor; +import com.sap.sailing.racecommittee.app.data.OnlineDataManager; +import com.sap.sailing.racecommittee.app.data.clients.LoadClient; +import com.sap.sailing.racecommittee.app.domain.ManagedRace; + +public class CompetitorsDataHandler extends DataHandler> { + + private ManagedRace race; + + public CompetitorsDataHandler(OnlineDataManager manager, LoadClient> client, ManagedRace managedRace) { + super(manager, client); + race = managedRace; + } + + @Override + public void onLoaded(Collection data) { + super.onLoaded(data); + race.setCompetitors(data); + } + +} diff --git a/mobile/com.sap.sailing.racecommittee.app/src/com/sap/sailing/racecommittee/app/data/parsers/CompetitorsDataParser.java b/mobile/com.sap.sailing.racecommittee.app/src/com/sap/sailing/racecommittee/app/data/parsers/CompetitorsDataParser.java new file mode 100644 index 00000000000..385de805049 --- /dev/null +++ b/mobile/com.sap.sailing.racecommittee.app/src/com/sap/sailing/racecommittee/app/data/parsers/CompetitorsDataParser.java @@ -0,0 +1,37 @@ +package com.sap.sailing.racecommittee.app.data.parsers; + +import java.io.Reader; +import java.util.ArrayList; +import java.util.Collection; + +import org.json.simple.JSONArray; +import org.json.simple.JSONObject; +import org.json.simple.JSONValue; + +import com.sap.sailing.domain.base.Competitor; +import com.sap.sailing.server.gateway.deserialization.JsonDeserializer; +import com.sap.sailing.server.gateway.deserialization.impl.Helpers; + +public class CompetitorsDataParser implements DataParser> { + + private JsonDeserializer deserializer; + + public CompetitorsDataParser(JsonDeserializer deserializer) { + this.deserializer = deserializer; + } + + public Collection parse(Reader reader) throws Exception { + Object parsedResult = JSONValue.parseWithException(reader); + JSONArray jsonArray = Helpers.toJSONArraySafe(parsedResult); + Collection competitors = new ArrayList(); + + for (Object element : jsonArray) { + JSONObject json = Helpers.toJSONObjectSafe(element); + Competitor competitor = deserializer.deserialize(json); + competitors.add(competitor); + } + + return competitors; + } + +} diff --git a/mobile/com.sap.sailing.racecommittee.app/src/com/sap/sailing/racecommittee/app/data/parsers/ManagedRacesDataParser.java b/mobile/com.sap.sailing.racecommittee.app/src/com/sap/sailing/racecommittee/app/data/parsers/ManagedRacesDataParser.java index 03287295282..e5346daae9a 100644 --- a/mobile/com.sap.sailing.racecommittee.app/src/com/sap/sailing/racecommittee/app/data/parsers/ManagedRacesDataParser.java +++ b/mobile/com.sap.sailing.racecommittee.app/src/com/sap/sailing/racecommittee/app/data/parsers/ManagedRacesDataParser.java @@ -8,7 +8,6 @@ import org.json.simple.JSONArray; import org.json.simple.JSONObject; import org.json.simple.JSONValue; -import com.sap.sailing.domain.base.Competitor; import com.sap.sailing.domain.base.Fleet; import com.sap.sailing.domain.base.racegroup.RaceCell; import com.sap.sailing.domain.base.racegroup.RaceGroup; @@ -60,8 +59,7 @@ public class ManagedRacesDataParser implements DataParser competitors) { + Fleet fleet, String name, PassAwareRaceLog raceLog) { return new ManagedRaceImpl( new ManagedRaceIdentifierImpl(name, new FleetIdentifierImpl(fleet, series, raceGroup)), - raceLog, competitors); + raceLog); } diff --git a/mobile/com.sap.sailing.racecommittee.app/src/com/sap/sailing/racecommittee/app/deserialization/impl/RaceCellDeserializer.java b/mobile/com.sap.sailing.racecommittee.app/src/com/sap/sailing/racecommittee/app/deserialization/impl/RaceCellDeserializer.java index f30a9f03498..e6e9d73c3e5 100644 --- a/mobile/com.sap.sailing.racecommittee.app/src/com/sap/sailing/racecommittee/app/deserialization/impl/RaceCellDeserializer.java +++ b/mobile/com.sap.sailing.racecommittee.app/src/com/sap/sailing/racecommittee/app/deserialization/impl/RaceCellDeserializer.java @@ -1,12 +1,7 @@ package com.sap.sailing.racecommittee.app.deserialization.impl; -import java.util.ArrayList; -import java.util.List; - -import org.json.simple.JSONArray; import org.json.simple.JSONObject; -import com.sap.sailing.domain.base.Competitor; import com.sap.sailing.domain.base.racegroup.RaceCell; import com.sap.sailing.domain.base.racegroup.impl.RaceCellImpl; import com.sap.sailing.domain.racelog.RaceLog; @@ -18,11 +13,9 @@ import com.sap.sailing.server.gateway.serialization.racegroup.impl.RaceCellJsonS public class RaceCellDeserializer implements JsonDeserializer { private JsonDeserializer logDeserializer; - private JsonDeserializer competitorDeserializer; - public RaceCellDeserializer(JsonDeserializer logDeserializer, JsonDeserializer competitorDeserializer) { + public RaceCellDeserializer(JsonDeserializer logDeserializer) { this.logDeserializer = logDeserializer; - this.competitorDeserializer = competitorDeserializer; } public RaceCell deserialize(JSONObject object) @@ -32,20 +25,8 @@ public class RaceCellDeserializer implements JsonDeserializer { JSONObject logJson = Helpers.getNestedObjectSafe(object, RaceCellJsonSerializer.FIELD_RACE_LOG); RaceLog log = logDeserializer.deserialize(logJson); - List competitors = deserializeCompetitorList(object); - return new RaceCellImpl(name, log, competitors); - } - - private List deserializeCompetitorList(JSONObject object) throws JsonDeserializationException { - List competitors = new ArrayList(); - JSONArray competitorsJson = Helpers.getNestedArraySafe(object, RaceCellJsonSerializer.FIELD_COMPETITORS); - for (Object competitorObject : competitorsJson) { - JSONObject jsonObject = (JSONObject) competitorObject; - Competitor competitor = competitorDeserializer.deserialize(jsonObject); - competitors.add(competitor); - } - return competitors; + return new RaceCellImpl(name, log); } } diff --git a/mobile/com.sap.sailing.racecommittee.app/src/com/sap/sailing/racecommittee/app/domain/ManagedRace.java b/mobile/com.sap.sailing.racecommittee.app/src/com/sap/sailing/racecommittee/app/domain/ManagedRace.java index 25141b8dd62..1b6175d403a 100644 --- a/mobile/com.sap.sailing.racecommittee.app/src/com/sap/sailing/racecommittee/app/domain/ManagedRace.java +++ b/mobile/com.sap.sailing.racecommittee.app/src/com/sap/sailing/racecommittee/app/domain/ManagedRace.java @@ -1,5 +1,7 @@ package com.sap.sailing.racecommittee.app.domain; +import java.util.Collection; + import com.sap.sailing.domain.base.Competitor; import com.sap.sailing.domain.base.CourseBase; import com.sap.sailing.domain.common.Named; @@ -44,10 +46,16 @@ public interface ManagedRace extends ManagedRaceIdentifier, Named, WithID { * returns the list of competitors for this race * @return list of competitors */ - public Iterable getCompetitors(); + public Collection getCompetitors(); public CourseBase getCourseOnServer(); public void setCourseOnServer(CourseBase course); + + /** + * sets the list of competitors for a race. As the competitors are retrieved later from the backend, the list of competitors has to be settable. + * @param competitors the retrieved list of competitors for this race + */ + public void setCompetitors(Collection competitors); } \ No newline at end of file diff --git a/mobile/com.sap.sailing.racecommittee.app/src/com/sap/sailing/racecommittee/app/domain/impl/ManagedRaceImpl.java b/mobile/com.sap.sailing.racecommittee.app/src/com/sap/sailing/racecommittee/app/domain/impl/ManagedRaceImpl.java index 1d9698d7876..1f262d8db9d 100644 --- a/mobile/com.sap.sailing.racecommittee.app/src/com/sap/sailing/racecommittee/app/domain/impl/ManagedRaceImpl.java +++ b/mobile/com.sap.sailing.racecommittee.app/src/com/sap/sailing/racecommittee/app/domain/impl/ManagedRaceImpl.java @@ -1,6 +1,8 @@ package com.sap.sailing.racecommittee.app.domain.impl; import java.io.Serializable; +import java.util.ArrayList; +import java.util.Collection; import com.sap.sailing.domain.base.Competitor; import com.sap.sailing.domain.base.CourseBase; @@ -23,20 +25,20 @@ public class ManagedRaceImpl implements ManagedRace { private ManagedRaceIdentifier identifier; private RaceState state; - private Iterable competitors; + private Collection competitors; private CourseBase courseOnServer; - public ManagedRaceImpl(ManagedRaceIdentifier identifier, PassAwareRaceLog raceLog, Iterable competitors) { + public ManagedRaceImpl(ManagedRaceIdentifier identifier, PassAwareRaceLog raceLog) { //TODO To be changed when the start procedure for a regatta/leaderboard can be selected in the GWT Admin Console on backend side - this(identifier, new RaceStateImpl(raceLog, new GateStartProcedure(raceLog)), competitors); + this(identifier, new RaceStateImpl(raceLog, new GateStartProcedure(raceLog))); } public ManagedRaceImpl( ManagedRaceIdentifier identifier, - RaceState state, Iterable competitors) { + RaceState state) { this.identifier = identifier; this.state = state; - this.competitors = competitors; + this.competitors = new ArrayList(); this.courseOnServer = null; } @@ -86,7 +88,7 @@ public class ManagedRaceImpl implements ManagedRace { } @Override - public Iterable getCompetitors() { + public Collection getCompetitors() { return competitors; } @@ -100,4 +102,9 @@ public class ManagedRaceImpl implements ManagedRace { courseOnServer = course; } + @Override + public void setCompetitors(Collection competitors) { + this.competitors = competitors; + } + } diff --git a/mobile/com.sap.sailing.racecommittee.app/src/com/sap/sailing/racecommittee/app/ui/fragments/raceinfo/FinishingRaceFragment.java b/mobile/com.sap.sailing.racecommittee.app/src/com/sap/sailing/racecommittee/app/ui/fragments/raceinfo/FinishingRaceFragment.java index 48343d00ea7..583daf49574 100644 --- a/mobile/com.sap.sailing.racecommittee.app/src/com/sap/sailing/racecommittee/app/ui/fragments/raceinfo/FinishingRaceFragment.java +++ b/mobile/com.sap.sailing.racecommittee.app/src/com/sap/sailing/racecommittee/app/ui/fragments/raceinfo/FinishingRaceFragment.java @@ -1,6 +1,7 @@ package com.sap.sailing.racecommittee.app.ui.fragments.raceinfo; import java.util.Date; + import android.app.AlertDialog; import android.app.FragmentManager; import android.content.DialogInterface; @@ -64,7 +65,7 @@ public class FinishingRaceFragment extends RaceFragment { }); } - + protected void setCountdownLabels(long millisecondsSinceStart) { setStarttimeCountupLabel(millisecondsSinceStart); } diff --git a/mobile/com.sap.sailing.racecommittee.app/src/com/sap/sailing/racecommittee/app/ui/fragments/raceinfo/PositioningFragment.java b/mobile/com.sap.sailing.racecommittee.app/src/com/sap/sailing/racecommittee/app/ui/fragments/raceinfo/PositioningFragment.java index ede7a678876..d74083db514 100644 --- a/mobile/com.sap.sailing.racecommittee.app/src/com/sap/sailing/racecommittee/app/ui/fragments/raceinfo/PositioningFragment.java +++ b/mobile/com.sap.sailing.racecommittee.app/src/com/sap/sailing/racecommittee/app/ui/fragments/raceinfo/PositioningFragment.java @@ -2,6 +2,7 @@ package com.sap.sailing.racecommittee.app.ui.fragments.raceinfo; import java.io.Serializable; import java.util.ArrayList; +import java.util.Collection; import java.util.Collections; import java.util.Comparator; import java.util.List; @@ -27,6 +28,8 @@ import com.sap.sailing.domain.common.Named; import com.sap.sailing.domain.common.impl.Util; import com.sap.sailing.domain.common.impl.Util.Triple; import com.sap.sailing.racecommittee.app.R; +import com.sap.sailing.racecommittee.app.data.OnlineDataManager; +import com.sap.sailing.racecommittee.app.data.clients.LoadClient; import com.sap.sailing.racecommittee.app.domain.impl.DomainFactoryImpl; import com.sap.sailing.racecommittee.app.logging.ExLog; import com.sap.sailing.racecommittee.app.ui.adapters.finishing.CompetitorPositioningListAdapter; @@ -87,6 +90,7 @@ public class PositioningFragment extends RaceDialogFragment { Collections.sort(competitors, competitorComparator); competitorsAdapter = new CompetitorsAdapter(getActivity(), R.layout.welter_grid_competitor_cell, competitors); + loadCompetitors(); positionedCompetitors = initializeFinishPositioningList(); deletePositionedCompetitorsFromUnpositionedList(); @@ -142,6 +146,12 @@ public class PositioningFragment extends RaceDialogFragment { }); } + @Override + public void onResume() { + super.onResume(); + onLoadCompetitorsSucceeded(getRace().getCompetitors()); + } + /** * Creates a DragSortController and thereby defines the behaviour of the drag sort list */ @@ -156,7 +166,32 @@ public class PositioningFragment extends RaceDialogFragment { controller.setBackgroundColor(getActivity().getResources().getColor(R.color.welter_medium_blue)); return controller; } - + + private void loadCompetitors() { + + OnlineDataManager.create(getActivity()).loadCompetitors(getRace(), new LoadClient>() { + + @Override + public void onLoadFailed(Exception reason) { + onLoadCompetitorsSucceeded(getRace().getCompetitors()); + } + + @Override + public void onLoadSucceded(Collection data) { + onLoadCompetitorsSucceeded(data); + } + + }); + } + + protected void onLoadCompetitorsSucceeded(Collection data) { + competitors.clear(); + competitors.addAll(data); + Collections.sort(competitors, competitorComparator); + deletePositionedCompetitorsFromUnpositionedList(); + competitorsAdapter.notifyDataSetChanged(); + } + private void deletePositionedCompetitorsFromUnpositionedList() { for (Triple positionedItem : positionedCompetitors) { Competitor competitor = DomainFactoryImpl.INSTANCE.getExistingCompetitorById(positionedItem.getA());