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 014d9f305d6..c50ad758f4a 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 @@ -257,7 +257,6 @@ import com.sap.sailing.gwt.ui.shared.WindDTO; import com.sap.sailing.gwt.ui.shared.WindInfoForRaceDTO; import com.sap.sailing.gwt.ui.shared.WindTrackInfoDTO; import com.sap.sailing.polars.PolarDataService; -import com.sap.sailing.polars.factory.PolarDataServiceFactory; import com.sap.sailing.resultimport.ResultUrlProvider; import com.sap.sailing.resultimport.ResultUrlRegistry; import com.sap.sailing.server.RacingEventService; @@ -369,9 +368,7 @@ public class SailingServiceImpl extends ProxiedRemoteServiceServlet implements S private final SwissTimingReplayService swissTimingReplayService; - private PolarDataService polarDataService; private final BundleContext context; - public SailingServiceImpl() { context = Activator.getDefault(); racingEventServiceTracker = createAndOpenRacingEventServiceTracker(context); @@ -414,7 +411,6 @@ public class SailingServiceImpl extends ProxiedRemoteServiceServlet implements S /* maximumPoolSize */ THREAD_POOL_SIZE, /* keepAliveTime */ 60, TimeUnit.SECONDS, /* workQueue */ new LinkedBlockingQueue()); - polarDataService = PolarDataServiceFactory.createStandardPolarDataService(); } protected SwissTimingReplayService getSwissTimingReplayService(BundleContext context) { @@ -3128,6 +3124,7 @@ public class SailingServiceImpl extends ProxiedRemoteServiceServlet implements S if (name == null || name.isEmpty()) { name = getCommonBoatClass(trackedRaces); } + PolarDataService polarDataService = service.getPolarDataService(); PolarSheetsData result = polarDataService.generatePolarSheet(trackedRaces, settings, executor); return new PolarSheetGenerationResponseImpl(id, name, result); } diff --git a/java/com.sap.sailing.mongodb.test/META-INF/MANIFEST.MF b/java/com.sap.sailing.mongodb.test/META-INF/MANIFEST.MF index d5eb223095b..c7cefcd62b9 100755 --- a/java/com.sap.sailing.mongodb.test/META-INF/MANIFEST.MF +++ b/java/com.sap.sailing.mongodb.test/META-INF/MANIFEST.MF @@ -17,8 +17,9 @@ Require-Bundle: com.sap.sailing.domain, org.json.simple;bundle-version="1.1.0", com.sap.sailing.domain.swisstimingadapter, org.objenesis;bundle-version="1.3.0", - org.junit4;bundle-version="4.8.2", + org.junit4;bundle-version="4.8.2", org.hamcrest;bundle-version="1.1.0", - org.mockito.mockito-core;bundle-version="1.9.5" + org.mockito.mockito-core;bundle-version="1.9.5", + com.sap.sailing.polars;bundle-version="1.0.0" Import-Package: com.sap.sailing.domain.common.impl diff --git a/java/com.sap.sailing.polars/src/com/sap/sailing/polars/PolarDataService.java b/java/com.sap.sailing.polars/src/com/sap/sailing/polars/PolarDataService.java index e93dc0f9924..2bb934d0589 100644 --- a/java/com.sap.sailing.polars/src/com/sap/sailing/polars/PolarDataService.java +++ b/java/com.sap.sailing.polars/src/com/sap/sailing/polars/PolarDataService.java @@ -95,4 +95,6 @@ public interface PolarDataService { PolarSheetsData generatePolarSheet(Set trackedRaces, PolarSheetGenerationSettings settings, Executor executor) throws InterruptedException, ExecutionException; + void newRaceFinishedTracking(TrackedRace trackedRace); + } diff --git a/java/com.sap.sailing.polars/src/com/sap/sailing/polars/caching/PolarFixCache.java b/java/com.sap.sailing.polars/src/com/sap/sailing/polars/caching/PolarFixCache.java index d06c1fdce3f..f066532dce5 100644 --- a/java/com.sap.sailing.polars/src/com/sap/sailing/polars/caching/PolarFixCache.java +++ b/java/com.sap.sailing.polars/src/com/sap/sailing/polars/caching/PolarFixCache.java @@ -2,17 +2,18 @@ package com.sap.sailing.polars.caching; import java.util.List; import java.util.Map; +import java.util.concurrent.Executor; import com.sap.sailing.domain.base.BoatClass; import com.sap.sailing.domain.common.RegattaAndRaceIdentifier; -import com.sap.sailing.polars.data.impl.PolarFixImpl; +import com.sap.sailing.polars.data.PolarFix; import com.sap.sailing.util.SmartFutureCache; public class PolarFixCache extends - SmartFutureCache>, PolarFixCacheRaceInterval> { + SmartFutureCache>, PolarFixCacheRaceInterval> { - public PolarFixCache() { - super(new PolarFixCacheUpdater(), "polarFixCache"); + public PolarFixCache(Executor executor) { + super(new PolarFixCacheUpdater(executor), "polarFixCache"); } } diff --git a/java/com.sap.sailing.polars/src/com/sap/sailing/polars/caching/PolarFixCacheRaceInterval.java b/java/com.sap.sailing.polars/src/com/sap/sailing/polars/caching/PolarFixCacheRaceInterval.java index 8a14fad2114..f26067ecda7 100644 --- a/java/com.sap.sailing.polars/src/com/sap/sailing/polars/caching/PolarFixCacheRaceInterval.java +++ b/java/com.sap.sailing.polars/src/com/sap/sailing/polars/caching/PolarFixCacheRaceInterval.java @@ -3,30 +3,26 @@ package com.sap.sailing.polars.caching; import java.util.HashSet; import java.util.Set; -import com.sap.sailing.domain.common.RegattaAndRaceIdentifier; +import com.sap.sailing.domain.tracking.TrackedRace; import com.sap.sailing.util.SmartFutureCache.UpdateInterval; public class PolarFixCacheRaceInterval implements UpdateInterval { - private final Set races; + private final Set races; - public PolarFixCacheRaceInterval(Set races) { + public PolarFixCacheRaceInterval(Set races) { this.races = races; } - public Set getRaces() { + public Set getRaces() { return races; } @Override public PolarFixCacheRaceInterval join(PolarFixCacheRaceInterval otherUpdateInterval) { - Set joined = new HashSet(); - for (RegattaAndRaceIdentifier race : races) { - joined.add(race); - } - for (RegattaAndRaceIdentifier race : otherUpdateInterval.getRaces()) { - joined.add(race); - } + Set joined = new HashSet(); + joined.addAll(races); + joined.addAll(otherUpdateInterval.getRaces()); return new PolarFixCacheRaceInterval(joined); } diff --git a/java/com.sap.sailing.polars/src/com/sap/sailing/polars/caching/PolarFixCacheUpdater.java b/java/com.sap.sailing.polars/src/com/sap/sailing/polars/caching/PolarFixCacheUpdater.java index 8ec0fdcdf3d..945802dcbd5 100644 --- a/java/com.sap.sailing.polars/src/com/sap/sailing/polars/caching/PolarFixCacheUpdater.java +++ b/java/com.sap.sailing.polars/src/com/sap/sailing/polars/caching/PolarFixCacheUpdater.java @@ -1,29 +1,65 @@ package com.sap.sailing.polars.caching; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.HashSet; import java.util.List; import java.util.Map; +import java.util.Map.Entry; +import java.util.Set; +import java.util.concurrent.Executor; import com.sap.sailing.domain.base.BoatClass; import com.sap.sailing.domain.common.RegattaAndRaceIdentifier; -import com.sap.sailing.polars.data.impl.PolarFixImpl; +import com.sap.sailing.domain.common.impl.PolarSheetGenerationSettingsImpl; +import com.sap.sailing.domain.tracking.TrackedRace; +import com.sap.sailing.polars.aggregation.PolarFixAggregator; +import com.sap.sailing.polars.data.PolarFix; import com.sap.sailing.util.SmartFutureCache.CacheUpdater; public class PolarFixCacheUpdater implements - CacheUpdater>, PolarFixCacheRaceInterval> { + CacheUpdater>, PolarFixCacheRaceInterval> { - @Override - public Map> computeCacheUpdate(BoatClass key, - PolarFixCacheRaceInterval updateInterval) throws Exception { - // TODO Auto-generated method stub - return null; + private final Executor executor; + + public PolarFixCacheUpdater(Executor executor) { + this.executor = executor; } @Override - public Map> provideNewCacheValue(BoatClass key, - Map> oldCacheValue, - Map> computedCacheUpdate, PolarFixCacheRaceInterval updateInterval) { - // TODO Auto-generated method stub - return null; + public Map> computeCacheUpdate(BoatClass key, + PolarFixCacheRaceInterval updateInterval) throws Exception { + Set races = updateInterval.getRaces(); + Map aggregators = new HashMap(); + for (TrackedRace trackedRace : races) { + Set trackedRaces = new HashSet(); + trackedRaces.add(trackedRace); + PolarFixAggregator aggregator = new PolarFixAggregator(trackedRaces, + PolarSheetGenerationSettingsImpl.createStandardPolarSettings(), executor); + aggregator.startPolarFixAggregation(); + aggregators.put(trackedRace.getRaceIdentifier(), aggregator); + } + Map> resultMap = new HashMap>(); + for (Entry entry : aggregators.entrySet()) { + PolarFixAggregator aggregator = entry.getValue(); + Set result = aggregator.get(); + List resultList = new ArrayList(result); + resultMap.put(entry.getKey(), resultList); + } + return resultMap; + + } + + @Override + public Map> provideNewCacheValue(BoatClass key, + Map> oldCacheValue, + Map> computedCacheUpdate, PolarFixCacheRaceInterval updateInterval) { + Map> newCacheValue = new HashMap>(); + newCacheValue.putAll(oldCacheValue); + for (Entry> newEntry : computedCacheUpdate.entrySet()) { + newCacheValue.put(newEntry.getKey(), newEntry.getValue()); + } + return newCacheValue; } } diff --git a/java/com.sap.sailing.polars/src/com/sap/sailing/polars/factory/PolarDataServiceFactory.java b/java/com.sap.sailing.polars/src/com/sap/sailing/polars/factory/PolarDataServiceFactory.java index 3247b032cc7..0b03c20a553 100644 --- a/java/com.sap.sailing.polars/src/com/sap/sailing/polars/factory/PolarDataServiceFactory.java +++ b/java/com.sap.sailing.polars/src/com/sap/sailing/polars/factory/PolarDataServiceFactory.java @@ -1,16 +1,18 @@ package com.sap.sailing.polars.factory; +import java.util.concurrent.Executor; + import com.sap.sailing.polars.PolarDataService; import com.sap.sailing.polars.factory.impl.PolarDataServiceImplFactory; public abstract class PolarDataServiceFactory { - public static PolarDataService createStandardPolarDataService() { + public static PolarDataService createStandardPolarDataService(Executor executor) { PolarDataServiceFactory factory = new PolarDataServiceImplFactory(); - return factory.createPolarDataService(); + return factory.createPolarDataService(executor); } - protected abstract PolarDataService createPolarDataService(); + protected abstract PolarDataService createPolarDataService(Executor executor); } diff --git a/java/com.sap.sailing.polars/src/com/sap/sailing/polars/factory/impl/PolarDataServiceImplFactory.java b/java/com.sap.sailing.polars/src/com/sap/sailing/polars/factory/impl/PolarDataServiceImplFactory.java index 2ea48ceb772..37af01d8343 100644 --- a/java/com.sap.sailing.polars/src/com/sap/sailing/polars/factory/impl/PolarDataServiceImplFactory.java +++ b/java/com.sap.sailing.polars/src/com/sap/sailing/polars/factory/impl/PolarDataServiceImplFactory.java @@ -1,5 +1,7 @@ package com.sap.sailing.polars.factory.impl; +import java.util.concurrent.Executor; + import com.sap.sailing.polars.PolarDataService; import com.sap.sailing.polars.factory.PolarDataServiceFactory; import com.sap.sailing.polars.impl.PolarDataServiceImpl; @@ -7,8 +9,8 @@ import com.sap.sailing.polars.impl.PolarDataServiceImpl; public class PolarDataServiceImplFactory extends PolarDataServiceFactory { @Override - public PolarDataService createPolarDataService() { - return new PolarDataServiceImpl(); + public PolarDataService createPolarDataService(Executor executor) { + return new PolarDataServiceImpl(executor); } } diff --git a/java/com.sap.sailing.polars/src/com/sap/sailing/polars/impl/PolarDataServiceImpl.java b/java/com.sap.sailing.polars/src/com/sap/sailing/polars/impl/PolarDataServiceImpl.java index d5a4c344b55..04bf28bfc76 100644 --- a/java/com.sap.sailing.polars/src/com/sap/sailing/polars/impl/PolarDataServiceImpl.java +++ b/java/com.sap.sailing.polars/src/com/sap/sailing/polars/impl/PolarDataServiceImpl.java @@ -1,5 +1,6 @@ package com.sap.sailing.polars.impl; +import java.util.HashSet; import java.util.Set; import java.util.concurrent.ExecutionException; import java.util.concurrent.Executor; @@ -13,11 +14,19 @@ import com.sap.sailing.domain.common.SpeedWithBearing; import com.sap.sailing.domain.tracking.TrackedRace; import com.sap.sailing.polars.PolarDataService; import com.sap.sailing.polars.aggregation.PolarFixAggregator; +import com.sap.sailing.polars.caching.PolarFixCache; +import com.sap.sailing.polars.caching.PolarFixCacheRaceInterval; import com.sap.sailing.polars.data.PolarFix; import com.sap.sailing.polars.generation.PolarSheetGenerator; public class PolarDataServiceImpl implements PolarDataService { + private final PolarFixCache polarFixCache; + + public PolarDataServiceImpl(Executor executor) { + this.polarFixCache = new PolarFixCache(executor); + } + @Override public SpeedWithBearing getOptimalUpwindSpeedWithBearingFor(BoatClass boatClass, Speed windSpeed) { // TODO Auto-generated method stub @@ -64,4 +73,11 @@ public class PolarDataServiceImpl implements PolarDataService { return generator.generate(); } + @Override + public void newRaceFinishedTracking(TrackedRace trackedRace) { + HashSet set = new HashSet(); + set.add(trackedRace); + polarFixCache.triggerUpdate(trackedRace.getRace().getBoatClass(), new PolarFixCacheRaceInterval(set)); + } + } diff --git a/java/com.sap.sailing.server.replication.test/META-INF/MANIFEST.MF b/java/com.sap.sailing.server.replication.test/META-INF/MANIFEST.MF index 1d08244f5d9..1213689ffcf 100644 --- a/java/com.sap.sailing.server.replication.test/META-INF/MANIFEST.MF +++ b/java/com.sap.sailing.server.replication.test/META-INF/MANIFEST.MF @@ -20,4 +20,5 @@ Require-Bundle: com.sap.sailing.server, com.sap.sailing.domain.swisstimingadapter, org.json.simple;bundle-version="1.1.0", org.junit4;bundle-version="4.8.2", - org.hamcrest;bundle-version="1.1.0" + org.hamcrest;bundle-version="1.1.0", + com.sap.sailing.polars;bundle-version="1.0.0" diff --git a/java/com.sap.sailing.server/META-INF/MANIFEST.MF b/java/com.sap.sailing.server/META-INF/MANIFEST.MF index b25247faa94..17d204a81ae 100755 --- a/java/com.sap.sailing.server/META-INF/MANIFEST.MF +++ b/java/com.sap.sailing.server/META-INF/MANIFEST.MF @@ -6,7 +6,9 @@ Bundle-Version: 1.0.0.qualifier Bundle-Activator: com.sap.sailing.server.impl.Activator Bundle-Vendor: SAP Bundle-RequiredExecutionEnvironment: JavaSE-1.7 -Import-Package: com.sap.sailing.server.gateway.deserialization, +Import-Package: com.sap.sailing.polars, + com.sap.sailing.polars.factory, + com.sap.sailing.server.gateway.deserialization, com.sap.sailing.server.gateway.deserialization.masterdata.impl, com.sap.sailing.server.gateway.serialization.masterdata.impl, org.json.simple, 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 6547f1420cb..343ba6a7acc 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 @@ -58,6 +58,7 @@ import com.sap.sailing.domain.tracking.TrackedRegatta; import com.sap.sailing.domain.tracking.TrackedRegattaRegistry; import com.sap.sailing.domain.tracking.TrackerManager; import com.sap.sailing.domain.tracking.WindStore; +import com.sap.sailing.polars.PolarDataService; /** * An OSGi service that can be used to track boat races using a TracTrac connector that pushes @@ -426,7 +427,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) @@ -471,11 +472,13 @@ public interface RacingEventService extends TrackedRegattaRegistry, RegattaFetch /** * Gets the start time and pass identifier for the queried race. */ - Pair getStartTime(String leaderboardName, String raceColumnName, String fleetName); + Pair getStartTime(String leaderboardName, String raceColumnName, String fleetName); MongoObjectFactory getMongoObjectFactory(); DomainObjectFactory getDomainObjectFactory(); WindStore getWindStore(); + + PolarDataService getPolarDataService(); } 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 4df52818506..32c18951af9 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 @@ -20,9 +20,12 @@ import java.util.Map.Entry; import java.util.Set; import java.util.UUID; import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.Executor; import java.util.concurrent.Executors; +import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.ScheduledFuture; +import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.TimeUnit; import java.util.logging.Level; import java.util.logging.Logger; @@ -61,6 +64,7 @@ import com.sap.sailing.domain.common.RegattaName; import com.sap.sailing.domain.common.Renamable; import com.sap.sailing.domain.common.ScoringSchemeType; import com.sap.sailing.domain.common.TimePoint; +import com.sap.sailing.domain.common.TrackedRaceStatusEnum; import com.sap.sailing.domain.common.WindSource; import com.sap.sailing.domain.common.dto.FleetDTO; import com.sap.sailing.domain.common.dto.RaceColumnDTO; @@ -115,9 +119,12 @@ import com.sap.sailing.domain.tracking.Wind; import com.sap.sailing.domain.tracking.WindStore; import com.sap.sailing.domain.tracking.WindTracker; import com.sap.sailing.domain.tracking.WindTrackerFactory; +import com.sap.sailing.domain.tracking.impl.AbstractRaceChangeListener; import com.sap.sailing.domain.tracking.impl.DynamicTrackedRegattaImpl; import com.sap.sailing.expeditionconnector.ExpeditionWindTrackerFactory; import com.sap.sailing.operationaltransformation.Operation; +import com.sap.sailing.polars.PolarDataService; +import com.sap.sailing.polars.factory.PolarDataServiceFactory; import com.sap.sailing.server.OperationExecutionListener; import com.sap.sailing.server.RacingEventService; import com.sap.sailing.server.RacingEventServiceOperation; @@ -222,6 +229,8 @@ public class RacingEventServiceImpl implements RacingEventService, RegattaListen private final WindStore windStore; + private final PolarDataService polarDataService; + /** * If this service runs in the context of an OSGi environment, the activator should {@link #setBundleContext set the bundle context} on this * object so that service lookups become possible. @@ -293,6 +302,13 @@ public class RacingEventServiceImpl implements RacingEventService, RegattaListen operationExecutionListeners = new ConcurrentHashMap(); courseListeners = new ConcurrentHashMap(); persistentRegattasForRaceIDs = new ConcurrentHashMap(); + final int THREAD_POOL_SIZE = Math.max(Runtime.getRuntime().availableProcessors(), 3); + // TODO find out how many executors we have on server side and how to manage them + Executor polarExecutor = new ThreadPoolExecutor(/* corePoolSize */THREAD_POOL_SIZE, + /* maximumPoolSize */THREAD_POOL_SIZE, + /* keepAliveTime */60, TimeUnit.SECONDS, + /* workQueue */new LinkedBlockingQueue()); + polarDataService = PolarDataServiceFactory.createStandardPolarDataService(polarExecutor); this.raceLogReplicator = new RaceLogReplicator(this); this.raceLogScoringReplicator = new RaceLogScoringReplicator(this); this.mediaDB = mediaDb; @@ -320,6 +336,11 @@ public class RacingEventServiceImpl implements RacingEventService, RegattaListen loadStoredDeviceConfigurations(); } + @Override + public PolarDataService getPolarDataService() { + return polarDataService; + } + @Override public com.sap.sailing.domain.base.DomainFactory getBaseDomainFactory() { return baseDomainFactory; @@ -1390,11 +1411,34 @@ public class RacingEventServiceImpl implements RacingEventService, RegattaListen replicate(new TrackRegatta(regatta.getRegattaIdentifier())); regattaTrackingCache.put(regatta, result); ensureRegattaIsObservedForDefaultLeaderboardAndAutoLeaderboardLinking(result); + addRaceTrackingFinishedListenerForPolarFixCache(result); } return result; } } + private void addRaceTrackingFinishedListenerForPolarFixCache(DynamicTrackedRegatta result) { + RaceListener raceListenerForPolarFixCacheUpdate = new RaceListener() { + @Override + public void raceRemoved(TrackedRace trackedRace) { + // TODO remove fixes from polar fix cache + } + + @Override + public void raceAdded(final TrackedRace trackedRace) { + trackedRace.addListener(new AbstractRaceChangeListener() { + @Override + public void statusChanged(TrackedRaceStatus newStatus) { + if (newStatus.getStatus() == TrackedRaceStatusEnum.FINISHED) { + polarDataService.newRaceFinishedTracking(trackedRace); + } + } + }); + } + }; + result.addRaceListener(raceListenerForPolarFixCacheUpdate); + } + @Override public DynamicTrackedRegatta getTrackedRegatta(com.sap.sailing.domain.base.Regatta regatta) { return regattaTrackingCache.get(regatta);