Implemented the polar fix cache updater

This commit is contained in:
Frederik Petersen committed 2013-12-18 12:00:24 +01:00
1 parent 64fe82c2d8
commit e25aeb5daf
13 files changed
+145 -42

No files matched your search

@@ -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<Runnable>());
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);
}
@@ -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
@@ -95,4 +95,6 @@ public interface PolarDataService {
PolarSheetsData generatePolarSheet(Set<TrackedRace> trackedRaces, PolarSheetGenerationSettings settings,
Executor executor) throws InterruptedException, ExecutionException;
void newRaceFinishedTracking(TrackedRace trackedRace);
}
@@ -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<BoatClass, Map<RegattaAndRaceIdentifier, List<PolarFixImpl>>, PolarFixCacheRaceInterval> {
SmartFutureCache<BoatClass, Map<RegattaAndRaceIdentifier, List<PolarFix>>, PolarFixCacheRaceInterval> {
public PolarFixCache() {
super(new PolarFixCacheUpdater(), "polarFixCache");
public PolarFixCache(Executor executor) {
super(new PolarFixCacheUpdater(executor), "polarFixCache");
}
}
@@ -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<PolarFixCacheRaceInterval> {
private final Set<RegattaAndRaceIdentifier> races;
private final Set<TrackedRace> races;
public PolarFixCacheRaceInterval(Set<RegattaAndRaceIdentifier> races) {
public PolarFixCacheRaceInterval(Set<TrackedRace> races) {
this.races = races;
}
public Set<RegattaAndRaceIdentifier> getRaces() {
public Set<TrackedRace> getRaces() {
return races;
}
@Override
public PolarFixCacheRaceInterval join(PolarFixCacheRaceInterval otherUpdateInterval) {
Set<RegattaAndRaceIdentifier> joined = new HashSet<RegattaAndRaceIdentifier>();
for (RegattaAndRaceIdentifier race : races) {
joined.add(race);
}
for (RegattaAndRaceIdentifier race : otherUpdateInterval.getRaces()) {
joined.add(race);
}
Set<TrackedRace> joined = new HashSet<TrackedRace>();
joined.addAll(races);
joined.addAll(otherUpdateInterval.getRaces());
return new PolarFixCacheRaceInterval(joined);
}
@@ -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<BoatClass, Map<RegattaAndRaceIdentifier, List<PolarFixImpl>>, PolarFixCacheRaceInterval> {
CacheUpdater<BoatClass, Map<RegattaAndRaceIdentifier, List<PolarFix>>, PolarFixCacheRaceInterval> {
@Override
public Map<RegattaAndRaceIdentifier, List<PolarFixImpl>> 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<RegattaAndRaceIdentifier, List<PolarFixImpl>> provideNewCacheValue(BoatClass key,
Map<RegattaAndRaceIdentifier, List<PolarFixImpl>> oldCacheValue,
Map<RegattaAndRaceIdentifier, List<PolarFixImpl>> computedCacheUpdate, PolarFixCacheRaceInterval updateInterval) {
// TODO Auto-generated method stub
return null;
public Map<RegattaAndRaceIdentifier, List<PolarFix>> computeCacheUpdate(BoatClass key,
PolarFixCacheRaceInterval updateInterval) throws Exception {
Set<TrackedRace> races = updateInterval.getRaces();
Map<RegattaAndRaceIdentifier, PolarFixAggregator> aggregators = new HashMap<RegattaAndRaceIdentifier, PolarFixAggregator>();
for (TrackedRace trackedRace : races) {
Set<TrackedRace> trackedRaces = new HashSet<TrackedRace>();
trackedRaces.add(trackedRace);
PolarFixAggregator aggregator = new PolarFixAggregator(trackedRaces,
PolarSheetGenerationSettingsImpl.createStandardPolarSettings(), executor);
aggregator.startPolarFixAggregation();
aggregators.put(trackedRace.getRaceIdentifier(), aggregator);
}
Map<RegattaAndRaceIdentifier, List<PolarFix>> resultMap = new HashMap<RegattaAndRaceIdentifier, List<PolarFix>>();
for (Entry<RegattaAndRaceIdentifier, PolarFixAggregator> entry : aggregators.entrySet()) {
PolarFixAggregator aggregator = entry.getValue();
Set<PolarFix> result = aggregator.get();
List<PolarFix> resultList = new ArrayList<PolarFix>(result);
resultMap.put(entry.getKey(), resultList);
}
return resultMap;
}
@Override
public Map<RegattaAndRaceIdentifier, List<PolarFix>> provideNewCacheValue(BoatClass key,
Map<RegattaAndRaceIdentifier, List<PolarFix>> oldCacheValue,
Map<RegattaAndRaceIdentifier, List<PolarFix>> computedCacheUpdate, PolarFixCacheRaceInterval updateInterval) {
Map<RegattaAndRaceIdentifier, List<PolarFix>> newCacheValue = new HashMap<RegattaAndRaceIdentifier, List<PolarFix>>();
newCacheValue.putAll(oldCacheValue);
for (Entry<RegattaAndRaceIdentifier, List<PolarFix>> newEntry : computedCacheUpdate.entrySet()) {
newCacheValue.put(newEntry.getKey(), newEntry.getValue());
}
return newCacheValue;
}
}
@@ -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);
}
@@ -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);
}
}
@@ -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<TrackedRace> set = new HashSet<TrackedRace>();
set.add(trackedRace);
polarFixCache.triggerUpdate(trackedRace.getRace().getBoatClass(), new PolarFixCacheRaceInterval(set));
}
}
@@ -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"
@@ -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,
@@ -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<TimePoint, Integer> getStartTime(String leaderboardName, String raceColumnName, String fleetName);
Pair<TimePoint, Integer> getStartTime(String leaderboardName, String raceColumnName, String fleetName);
MongoObjectFactory getMongoObjectFactory();
DomainObjectFactory getDomainObjectFactory();
WindStore getWindStore();
PolarDataService getPolarDataService();
}
@@ -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<OperationExecutionListener, OperationExecutionListener>();
courseListeners = new ConcurrentHashMap<RaceDefinition, CourseChangeReplicator>();
persistentRegattasForRaceIDs = new ConcurrentHashMap<String, Regatta>();
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<Runnable>());
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);