initial calculator

This commit is contained in:
Kai Boernert committed 2017-07-27 14:08:11 +02:00
1 parent 55ec7a124f
commit bfad7d0869
8 files changed
+184 -7

No files matched your search

@@ -1,4 +1,4 @@
package com.sap.sailing.server.gateway.serialization.impl;
package com.sap.sailing.domain.anniversary;
public class AnniversaryConflictResolver {
@@ -1,4 +1,4 @@
package com.sap.sailing.server.gateway.serialization.impl;
package com.sap.sailing.domain.anniversary;
import java.util.Date;
@@ -12,6 +12,8 @@ import javax.ws.rs.core.Response;
import org.json.simple.JSONArray;
import org.json.simple.JSONAware;
import com.sap.sailing.domain.anniversary.AnniversaryConflictResolver;
import com.sap.sailing.domain.anniversary.AnniversaryRaceInfo;
import com.sap.sailing.domain.base.Event;
import com.sap.sailing.domain.base.Fleet;
import com.sap.sailing.domain.base.RaceColumn;
@@ -20,8 +22,6 @@ import com.sap.sailing.domain.leaderboard.Leaderboard;
import com.sap.sailing.domain.leaderboard.LeaderboardGroup;
import com.sap.sailing.domain.tracking.TrackedRace;
import com.sap.sailing.server.gateway.jaxrs.AbstractSailingServerResource;
import com.sap.sailing.server.gateway.serialization.impl.AnniversaryConflictResolver;
import com.sap.sailing.server.gateway.serialization.impl.AnniversaryRaceInfo;
import com.sap.sailing.server.gateway.serialization.impl.AnniversaryRaceInfoJsonSerializer;
@Path("/v1/anniversary")
@@ -2,6 +2,7 @@ package com.sap.sailing.server.gateway.serialization.impl;
import org.json.simple.JSONObject;
import com.sap.sailing.domain.anniversary.AnniversaryRaceInfo;
import com.sap.sailing.server.gateway.serialization.JsonSerializer;
public class AnniversaryRaceInfoJsonSerializer implements JsonSerializer<AnniversaryRaceInfo> {
@@ -0,0 +1,93 @@
package com.sap.sailing.server.anniversary;
import java.util.Collection;
import java.util.HashMap;
import java.util.concurrent.CopyOnWriteArraySet;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import com.sap.sailing.domain.anniversary.AnniversaryConflictResolver;
import com.sap.sailing.domain.anniversary.AnniversaryRaceInfo;
import com.sap.sailing.domain.base.Event;
import com.sap.sailing.domain.base.Fleet;
import com.sap.sailing.domain.base.RaceColumn;
import com.sap.sailing.domain.common.RegattaAndRaceIdentifier;
import com.sap.sailing.domain.leaderboard.Leaderboard;
import com.sap.sailing.domain.leaderboard.LeaderboardGroup;
import com.sap.sailing.domain.tracking.TrackedRace;
import com.sap.sailing.server.RacingEventService;
public class AnniversaryCalculator implements Runnable {
private static final long INITIAL_DELAY = 1000;
private static final long DELAY = 5000;
private RacingEventService racingEventService;
private AnniversaryConflictResolver resolver = new AnniversaryConflictResolver();
private int lastAmount = -1;
private CopyOnWriteArraySet<ChangeListener> listeners = new CopyOnWriteArraySet<>();
interface ChangeListener{
void onChange(Collection<AnniversaryRaceInfo> collection);
}
public AnniversaryCalculator(ScheduledExecutorService scheduledExecutorService) {
scheduledExecutorService.scheduleWithFixedDelay(this,INITIAL_DELAY ,DELAY, TimeUnit.MILLISECONDS);
}
public void addListener(ChangeListener listener){
listeners.add(listener);
}
public void removeListener(ChangeListener listener){
listeners.remove(listener);
}
@Override
public void run() {
if(racingEventService==null || listeners.isEmpty()){
return;
}
HashMap<RegattaAndRaceIdentifier, AnniversaryRaceInfo> local = getLocalResults();
//add remotes with resolver checking
if(lastAmount < local.size()){
for(ChangeListener listener:listeners){
listener.onChange(local.values());
}
}
}
private HashMap<RegattaAndRaceIdentifier, AnniversaryRaceInfo> getLocalResults() {
HashMap<RegattaAndRaceIdentifier, AnniversaryRaceInfo> anniversaryRaceList = new HashMap<RegattaAndRaceIdentifier, AnniversaryRaceInfo>();
for (Event event : racingEventService.getAllEvents()) {
for (LeaderboardGroup group : event.getLeaderboardGroups()) {
for (Leaderboard leaderboard : group.getLeaderboards()) {
for (RaceColumn race : leaderboard.getRaceColumns()) {
for (Fleet fleet : race.getFleets()) {
TrackedRace trackedRace = race.getTrackedRace(fleet);
if (trackedRace != null) {
RegattaAndRaceIdentifier raceIdentifier = trackedRace.getRaceIdentifier();
AnniversaryRaceInfo current = anniversaryRaceList.get(raceIdentifier);
AnniversaryRaceInfo raceInfo = new AnniversaryRaceInfo(raceIdentifier,
leaderboard.getName(), trackedRace.getStartOfRace().asDate(),
event.getId().toString(),null);
if(current == null){
anniversaryRaceList.put(raceIdentifier, raceInfo);
}else{
AnniversaryRaceInfo prefered = resolver.resolve(current,raceInfo);
if(prefered != current){
anniversaryRaceList.put(prefered.getIdentifier(), prefered);
}
}
}
}
}
}
}
}
return anniversaryRaceList;
}
public void setRacingEventService(RacingEventService racingEventService) {
this.racingEventService = racingEventService;
}
}
@@ -0,0 +1,70 @@
package com.sap.sailing.server.anniversary;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import com.sap.sailing.domain.anniversary.AnniversaryRaceInfo;
import com.sap.sailing.server.anniversary.AnniversaryCalculator.ChangeListener;
public class AnniversaryDeterminator implements ChangeListener {
private static int[] anniversaries = new int[]{10,25, 50,75};
ConcurrentHashMap<Integer, AnniversaryRaceInfo> knownAnniversaries = new ConcurrentHashMap<>();
public AnniversaryDeterminator() {
knownAnniversaries.putAll(load());
}
@Override
public void onChange(Collection<AnniversaryRaceInfo> collection) {
ArrayList<AnniversaryRaceInfo> allRaces = new ArrayList<>(collection);
Collections.sort(allRaces,new Comparator<AnniversaryRaceInfo>() {
@Override
public int compare(AnniversaryRaceInfo o1, AnniversaryRaceInfo o2) {
return o1.getStartOfRace().compareTo(o2.getStartOfRace());
}
});
checkForAnnivesaries(allRaces);
}
private void checkForAnnivesaries(List<AnniversaryRaceInfo> collection) {
int newAmount = collection.size();
int factor = 1;
while(true){
for(int anniversary:anniversaries){
int anniversaryToCheck = anniversary*factor;
if(anniversaryToCheck > newAmount){
return;
}
if(newAmount<anniversaryToCheck){
onAnniversaryTraverse(anniversaryToCheck,collection.get(anniversaryToCheck));
}
}
}
}
private void onAnniversaryTraverse(int anniversaryToCheck, AnniversaryRaceInfo anniversaryRaceInfo) {
AnniversaryRaceInfo knownAnniversary = knownAnniversaries.get(anniversaryToCheck);
if(knownAnniversary != null){
System.out.println("Skipping anniversary " + anniversaryToCheck + " as it is already known");
}else{
System.out.println("New anniversary " + anniversaryToCheck + " " + anniversaryRaceInfo);
knownAnniversaries.put(anniversaryToCheck, anniversaryRaceInfo);
persist();
}
}
private void persist() {
// TODO Auto-generated method stub
}
private Map<Integer, AnniversaryRaceInfo> load() {
return Collections.emptyMap();
}
}
@@ -35,6 +35,8 @@ import com.sap.sailing.domain.polars.PolarDataService;
import com.sap.sailing.server.MasterDataImportClassLoaderService;
import com.sap.sailing.server.RacingEventService;
import com.sap.sailing.server.RacingEventServiceMXBean;
import com.sap.sailing.server.anniversary.AnniversaryCalculator;
import com.sap.sailing.server.anniversary.AnniversaryDeterminator;
import com.sap.sailing.server.impl.preferences.model.BoatClassNotificationPreferences;
import com.sap.sailing.server.impl.preferences.model.CompetitorNotificationPreferences;
import com.sap.sailing.server.notification.impl.SailingNotificationServiceImpl;
@@ -48,6 +50,7 @@ import com.sap.sse.replication.Replicable;
import com.sap.sse.security.PreferenceConverter;
import com.sap.sse.util.ClearStateTestSupport;
import com.sap.sse.util.ServiceTrackerFactory;
import com.sap.sse.util.ThreadPoolUtil;
public class Activator implements BundleActivator {
@@ -82,6 +85,8 @@ public class Activator implements BundleActivator {
private SailingNotificationServiceImpl notificationService;
private ServiceTracker<MailService, MailService> mailServiceTracker;
private AnniversaryCalculator anniversaryCalculator;
public Activator() {
clearPersistentCompetitors = Boolean
@@ -108,9 +113,12 @@ public class Activator implements BundleActivator {
// this code block is not run, and the test case can inject some other type of finder
// instead.
serviceFinderFactory = new CachedOsgiTypeBasedServiceFinderFactory(context);
anniversaryCalculator = new AnniversaryCalculator(ThreadPoolUtil.INSTANCE.getDefaultBackgroundTaskThreadPoolExecutor());
racingEventService = new RacingEventServiceImpl(clearPersistentCompetitors, serviceFinderFactory,
trackedRegattaListener, notificationService, restoreTrackedRaces);
trackedRegattaListener, notificationService, restoreTrackedRaces,anniversaryCalculator);
notificationService.setRacingEventService(racingEventService);
anniversaryCalculator.addListener(new AnniversaryDeterminator());
anniversaryCalculator.setRacingEventService(racingEventService);
masterDataImportClassLoaderServiceTracker = new ServiceTracker<MasterDataImportClassLoaderService, MasterDataImportClassLoaderService>(
context, MasterDataImportClassLoaderService.class,
@@ -175,6 +175,7 @@ import com.sap.sailing.domain.tracking.impl.TrackedRaceImpl;
import com.sap.sailing.expeditionconnector.ExpeditionWindTrackerFactory;
import com.sap.sailing.server.RacingEventService;
import com.sap.sailing.server.Replicator;
import com.sap.sailing.server.anniversary.AnniversaryCalculator;
import com.sap.sailing.server.gateway.deserialization.impl.CourseAreaJsonDeserializer;
import com.sap.sailing.server.gateway.deserialization.impl.EventBaseJsonDeserializer;
import com.sap.sailing.server.gateway.deserialization.impl.LeaderboardGroupBaseJsonDeserializer;
@@ -450,6 +451,8 @@ public class RacingEventServiceImpl implements RacingEventService, ClearStateTes
private transient final ConcurrentHashMap<RaceDefinition, RaceTrackingConnectivityParameters> connectivityParametersByRace;
private AnniversaryCalculator anniversaryCalculator;
/**
* Providing the constructor parameters for a new {@link RacingEventServiceImpl} instance is a bit tricky
* in some cases because containment and initialization order of some types is fairly tightly coupled.
@@ -489,7 +492,7 @@ public class RacingEventServiceImpl implements RacingEventService, ClearStateTes
}
public RacingEventServiceImpl(boolean clearPersistentCompetitorStore, final TypeBasedServiceFinderFactory serviceFinderFactory, boolean restoreTrackedRaces) {
this(clearPersistentCompetitorStore, serviceFinderFactory, null, /* sailingNotificationService */ null, restoreTrackedRaces);
this(clearPersistentCompetitorStore, serviceFinderFactory, null, /* sailingNotificationService */ null, restoreTrackedRaces,null);
}
/**
@@ -503,9 +506,10 @@ public class RacingEventServiceImpl implements RacingEventService, ClearStateTes
* @param sailingNotificationService
* a notification service to call upon events worth notifying users about, or {@code null} if no
* notification service is available, e.g., in test set-ups
* @param anniversaryCalculator
*/
public RacingEventServiceImpl(boolean clearPersistentCompetitorStore, final TypeBasedServiceFinderFactory serviceFinderFactory,
TrackedRegattaListener trackedRegattaListener, SailingNotificationService sailingNotificationService, boolean restoreTrackedRaces) {
TrackedRegattaListener trackedRegattaListener, SailingNotificationService sailingNotificationService, boolean restoreTrackedRaces, AnniversaryCalculator anniversaryCalculator) {
this((final RaceLogResolver raceLogResolver)-> {
return new ConstructorParameters() {
private final MongoObjectFactory mongoObjectFactory = PersistenceFactory.INSTANCE.getDefaultMongoObjectFactory(serviceFinderFactory);
@@ -519,6 +523,7 @@ public class RacingEventServiceImpl implements RacingEventService, ClearStateTes
@Override public CompetitorStore getCompetitorStore() { return competitorStore; }
};
}, MediaDBFactory.INSTANCE.getDefaultMediaDB(), null, null, serviceFinderFactory ,trackedRegattaListener, sailingNotificationService, restoreTrackedRaces);
this.anniversaryCalculator = anniversaryCalculator;
}
private RacingEventServiceImpl(final boolean clearPersistentCompetitorStore, WindStore windStore,