first working version of tracked race restoring with -Drestore.tracked.races=true;

Change-Id: I2c3968d772c7382589ada66c60874015f46f8996
This commit is contained in:
Axel Uhl committed 2016-12-29 17:18:42 +01:00
1 parent c20cf52f4d
commit 19d112115b
33 files changed
+208 -130

No files matched your search

@@ -7,6 +7,7 @@ import java.util.Collection;
import java.util.Map; import java.util.Map;
import java.util.Map.Entry; import java.util.Map.Entry;
import java.util.Set; import java.util.Set;
import java.util.function.Consumer;
import com.mongodb.DBObject; import com.mongodb.DBObject;
import com.sap.sailing.domain.abstractlog.race.RaceLog; import com.sap.sailing.domain.abstractlog.race.RaceLog;
@@ -37,6 +38,7 @@ import com.sap.sailing.domain.tracking.TrackedRace;
import com.sap.sailing.domain.tracking.TrackedRegatta; import com.sap.sailing.domain.tracking.TrackedRegatta;
import com.sap.sailing.domain.tracking.TrackedRegattaRegistry; import com.sap.sailing.domain.tracking.TrackedRegattaRegistry;
import com.sap.sailing.domain.tracking.WindTrack; import com.sap.sailing.domain.tracking.WindTrack;
import com.sap.sse.common.NoCorrespondingServiceRegisteredException;
import com.sap.sse.common.Util.Pair; import com.sap.sse.common.Util.Pair;
/** /**
@@ -146,14 +148,25 @@ public interface DomainObjectFactory {
/** /**
* Loads all {@link RaceTrackingConnectivityParameters} objects from the database telling how to re-load those races * Loads all {@link RaceTrackingConnectivityParameters} objects from the database telling how to re-load those races
* that were {@link MongoObjectFactory#addConnectivityParametersForRaceToRestore(RaceTrackingConnectivityParameters) * that were {@link MongoObjectFactory#addConnectivityParametersForRaceToRestore(RaceTrackingConnectivityParameters)
* marked as to be restored} before the server got re-started. Callers that would like to use the result to re-connect to * marked as to be restored} before the server got re-started. Callers that would like to use the result to
* those races should take care not to flood servers with requests. Instead, ideally, callers would monitor the * re-connect to those races should take care not to flood servers with requests. Instead, ideally, callers would
* loading {@link TrackedRace#getStatus() status} or the resulting {@link TrackedRace}s (see * monitor the loading {@link TrackedRace#getStatus() status} or the resulting {@link TrackedRace}s (see
* {@link RaceTracker#getRaceHandle()}, {@link RaceHandle#getRace(long)}, {@link RaceHandle#getTrackedRegatta()} * {@link RaceTracker#getRaceHandle()}, {@link RaceHandle#getRace(long)}, {@link RaceHandle#getTrackedRegatta()} and
* and {@link TrackedRegatta#getTrackedRace(RaceDefinition)}. * {@link TrackedRegatta#getTrackedRace(RaceDefinition)}.
*
* @param callback
* invoked for each connectivity params object successfully resolved; this pattern is preferred over
* a non-{@code void} return type because resolving the connectivity parameters objects itself happens
* through a callback pattern that may be triggered asynchronously by the services for handling the
* respective parameter types becoming available only later. For example, during the OSGi startup
* phase, when the {@code RacingEventService} is launched, not all persistence bundles will have run
* their activators; some may even depend on the {@code RacingEventService} and therefore won't start
* their activators before the activator of {@code RacingEventService} has completed. This would
* either result in a {@link NoCorrespondingServiceRegisteredException} or would have to be handled
* by not treating those connectivity parameter objects which defeats the whole purpose of this method.
* *
* @see MongoObjectFactory#addConnectivityParametersForRaceToRestore(RaceTrackingConnectivityParameters) * @see MongoObjectFactory#addConnectivityParametersForRaceToRestore(RaceTrackingConnectivityParameters)
* @see MongoObjectFactory#removeConnectivityParametersForRaceToRestore(RaceTrackingConnectivityParameters) * @see MongoObjectFactory#removeConnectivityParametersForRaceToRestore(RaceTrackingConnectivityParameters)
*/ */
Iterable<RaceTrackingConnectivityParameters> loadConnectivityParametersForRacesToRestore() throws MalformedURLException, URISyntaxException; void loadConnectivityParametersForRacesToRestore(Consumer<RaceTrackingConnectivityParameters> callback) throws MalformedURLException, URISyntaxException;
} }
@@ -153,7 +153,7 @@ public interface MongoObjectFactory {
/** /**
* Updates the database such that the next call to * Updates the database such that the next call to
* {@link DomainObjectFactory#loadConnectivityParametersForRacesToRestore()} won't return an object equivalent to * {@link DomainObjectFactory#loadConnectivityParametersForRacesToRestore(Consumer<RaceTrackingConnectivityParameter>)} won't return an object equivalent to
* {@code params} anymore; in other words, the race whose connectivity parameters are described by {@code params} * {@code params} anymore; in other words, the race whose connectivity parameters are described by {@code params}
* will no longer be considered as to be restored. * will no longer be considered as to be restored.
* *
@@ -163,7 +163,7 @@ public interface MongoObjectFactory {
/** /**
* Updates the database such that the next call to * Updates the database such that the next call to
* {@link DomainObjectFactory#loadConnectivityParametersForRacesToRestore()} will return an object equivalent to * {@link DomainObjectFactory#loadConnectivityParametersForRacesToRestore(Consumer<RaceTrackingConnectivityParameter>)} will return an object equivalent to
* {@code params}; in other words, the race whose connectivity parameters are described by {@code params} will be * {@code params}; in other words, the race whose connectivity parameters are described by {@code params} will be
* considered as to be restored. * considered as to be restored.
* *
@@ -174,7 +174,7 @@ public interface MongoObjectFactory {
/** /**
* Removes all {@link RaceTrackingConnectivityParameters} objects from those to restore; short for calling * Removes all {@link RaceTrackingConnectivityParameters} objects from those to restore; short for calling
* {@link #removeConnectivityParametersForRaceToRestore(RaceTrackingConnectivityParameters)} for all parameter * {@link #removeConnectivityParametersForRaceToRestore(RaceTrackingConnectivityParameters)} for all parameter
* objects obtained through {@link DomainObjectFactory#loadConnectivityParametersForRacesToRestore()}. * objects obtained through {@link DomainObjectFactory#loadConnectivityParametersForRacesToRestore(Consumer<RaceTrackingConnectivityParameter>)}.
*/ */
void removeAllConnectivityParametersForRacesToRestore(); void removeAllConnectivityParametersForRacesToRestore();
} }
@@ -15,6 +15,7 @@ import java.util.Map;
import java.util.Map.Entry; import java.util.Map.Entry;
import java.util.Set; import java.util.Set;
import java.util.UUID; import java.util.UUID;
import java.util.function.Consumer;
import java.util.logging.Level; import java.util.logging.Level;
import java.util.logging.Logger; import java.util.logging.Logger;
@@ -2284,22 +2285,24 @@ public class DomainObjectFactoryImpl implements DomainObjectFactory {
} }
@Override @Override
public Iterable<RaceTrackingConnectivityParameters> loadConnectivityParametersForRacesToRestore() throws MalformedURLException, URISyntaxException { public void loadConnectivityParametersForRacesToRestore(Consumer<RaceTrackingConnectivityParameters> callback) throws MalformedURLException, URISyntaxException {
Set<RaceTrackingConnectivityParameters> result = new HashSet<>();
final DBCollection collection = database.getCollection(CollectionNames.CONNECTIVITY_PARAMS_FOR_RACES_TO_BE_RESTORED.name()); final DBCollection collection = database.getCollection(CollectionNames.CONNECTIVITY_PARAMS_FOR_RACES_TO_BE_RESTORED.name());
for (final DBObject o : collection.find()) { for (final DBObject o : collection.find()) {
final String type = (String) o.get(TypeBasedServiceFinder.TYPE); final String type = (String) o.get(TypeBasedServiceFinder.TYPE);
final RaceTrackingConnectivityParametersHandler connectivityParamsPersistenceService = raceTrackingConnectivityParamsServiceFinder.findService(type); raceTrackingConnectivityParamsServiceFinder.applyServiceWhenAvailable(type, connectivityParamsPersistenceService -> {
if (connectivityParamsPersistenceService != null) {
final Map<String, Object> map = new HashMap<>(); final Map<String, Object> map = new HashMap<>();
for (final String key : o.keySet()) { for (final String key : o.keySet()) {
if (!key.equals(TypeBasedServiceFinder.TYPE)) { if (!key.equals(TypeBasedServiceFinder.TYPE)) {
map.put(key, o.get(key)); map.put(key, o.get(key));
} }
} }
result.add(connectivityParamsPersistenceService.mapTo(map)); try {
callback.accept(connectivityParamsPersistenceService.mapTo(map));
} catch (Exception e) {
logger.log(Level.SEVERE, "Exception trying to load race restore connectivity parameters "
+ o + " with handler " + connectivityParamsPersistenceService, e);
}
});
} }
} }
return result;
}
} }
@@ -1539,17 +1539,17 @@ public class MongoObjectFactoryImpl implements MongoObjectFactory {
@Override @Override
public void addConnectivityParametersForRaceToRestore(RaceTrackingConnectivityParameters params) { public void addConnectivityParametersForRaceToRestore(RaceTrackingConnectivityParameters params) {
final String typeIdentifier = params.getTypeIdentifier(); final String typeIdentifier = params.getTypeIdentifier();
try {
final RaceTrackingConnectivityParametersHandler paramsPersistenceService = raceTrackingConnectivityParamsServiceFinder.findService(typeIdentifier); final RaceTrackingConnectivityParametersHandler paramsPersistenceService = raceTrackingConnectivityParamsServiceFinder.findService(typeIdentifier);
if (paramsPersistenceService != null) {
final DBCollection collection = database.getCollection(CollectionNames.CONNECTIVITY_PARAMS_FOR_RACES_TO_BE_RESTORED.name()); final DBCollection collection = database.getCollection(CollectionNames.CONNECTIVITY_PARAMS_FOR_RACES_TO_BE_RESTORED.name());
DBObject key = new BasicDBObject(); DBObject key = new BasicDBObject();
key.putAll(paramsPersistenceService.getKey(params)); key.putAll(paramsPersistenceService.getKey(params));
DBObject dbObject = new BasicDBObject(); DBObject dbObject = new BasicDBObject();
dbObject.putAll(paramsPersistenceService.mapFrom(params)); dbObject.putAll(paramsPersistenceService.mapFrom(params));
collection.update(key, dbObject, /* upsert */ true, /* multi */ false, WriteConcern.SAFE); collection.update(key, dbObject, /* upsert */ true, /* multi */ false, WriteConcern.SAFE);
} else { } catch (NoCorrespondingServiceRegisteredException e) {
logger.warning("Couldn't find a persistence service for connectivity parameters of type "+typeIdentifier+ logger.log(Level.WARNING, "Couldn't find a persistence service for connectivity parameters of type "+typeIdentifier+
". Couldn't store race "+params.getTrackerID()+" for restoring."); ". Couldn't store race "+params.getTrackerID()+" for restoring.", e);
} }
} }
@@ -78,7 +78,7 @@ public class CreateAndTrackWithRaceLogTest {
@Before @Before
public void setup() { public void setup() {
service = new RacingEventServiceImpl(true, new MockSmartphoneImeiServiceFinderFactory()); service = new RacingEventServiceImpl(/* clearPersistentCompetitorStore */ true, new MockSmartphoneImeiServiceFinderFactory(), /* restoreTrackedRaces */ false);
sensorFixStore = service.getSensorFixStore(); sensorFixStore = service.getSensorFixStore();
service.getMongoObjectFactory().getDatabase().dropDatabase(); service.getMongoObjectFactory().getDatabase().dropDatabase();
author = service.getServerAuthor(); author = service.getServerAuthor();
@@ -4,9 +4,8 @@ import java.util.Collections;
import java.util.Set; import java.util.Set;
import com.sap.sse.common.NoCorrespondingServiceRegisteredException; import com.sap.sse.common.NoCorrespondingServiceRegisteredException;
import com.sap.sse.common.TypeBasedServiceFinder;
public class MockEmptyServiceFinder<ServiceType> implements TypeBasedServiceFinder<ServiceType> { public class MockEmptyServiceFinder<ServiceType> extends AbstractTypeBasedServiceFinder<ServiceType> {
private ServiceType fallback; private ServiceType fallback;
@Override @Override
@@ -15,9 +15,8 @@ import com.sap.sailing.domain.persistence.racelog.tracking.FixMongoHandler;
import com.sap.sailing.domain.persistence.racelog.tracking.impl.DoubleVectorFixMongoHandlerImpl; import com.sap.sailing.domain.persistence.racelog.tracking.impl.DoubleVectorFixMongoHandlerImpl;
import com.sap.sailing.domain.persistence.racelog.tracking.impl.GPSFixMongoHandlerImpl; import com.sap.sailing.domain.persistence.racelog.tracking.impl.GPSFixMongoHandlerImpl;
import com.sap.sailing.domain.persistence.racelog.tracking.impl.GPSFixMovingMongoHandlerImpl; import com.sap.sailing.domain.persistence.racelog.tracking.impl.GPSFixMovingMongoHandlerImpl;
import com.sap.sse.common.TypeBasedServiceFinder;
public class MockGPSFixMongoServiceFinder implements TypeBasedServiceFinder<FixMongoHandler<?>> { public class MockGPSFixMongoServiceFinder extends AbstractTypeBasedServiceFinder<FixMongoHandler<?>> {
private final MongoObjectFactoryImpl mof = new MongoObjectFactoryImpl(null); private final MongoObjectFactoryImpl mof = new MongoObjectFactoryImpl(null);
private final DomainObjectFactoryImpl dof = new DomainObjectFactoryImpl(null, null); private final DomainObjectFactoryImpl dof = new DomainObjectFactoryImpl(null, null);
private final FixMongoHandler<?> movingHandler = new GPSFixMovingMongoHandlerImpl(mof, dof); private final FixMongoHandler<?> movingHandler = new GPSFixMovingMongoHandlerImpl(mof, dof);
@@ -3,9 +3,7 @@ package com.sap.sailing.domain.racelog.tracking.test.mock;
import java.util.Collections; import java.util.Collections;
import java.util.Set; import java.util.Set;
import com.sap.sse.common.TypeBasedServiceFinder; public class MockServiceFinder<T> extends AbstractTypeBasedServiceFinder<T> {
public class MockServiceFinder<T> implements TypeBasedServiceFinder<T> {
private final T handler; private final T handler;
private T fallback; private T fallback;
@@ -47,7 +47,7 @@ public class SailingServiceImplMock extends SailingServiceImpl {
public SailingServiceImplMock() { public SailingServiceImplMock() {
super(); super();
service = new RacingEventServiceImpl(true, new MockSmartphoneImeiServiceFinderFactory()); service = new RacingEventServiceImpl(/* clearPersistentCompetitorStore */ true, new MockSmartphoneImeiServiceFinderFactory(), /* restoreTrackedRaces */ false);
try { try {
replicationService = new ReplicationServiceImpl("test exchange", "localhost", 0, replicationService = new ReplicationServiceImpl("test exchange", "localhost", 0,
new ReplicationInstancesManager(), new AbstractReplicablesProvider() { new ReplicationInstancesManager(), new AbstractReplicablesProvider() {
@@ -23,7 +23,7 @@ public abstract class AbstractConnectivityParamsLoadAndStoreTest extends Abstrac
@Before @Before
public void setUp() { public void setUp() {
serviceFinderFactory = new MockConnectivityParamsServiceFinderFactory(); serviceFinderFactory = new MockConnectivityParamsServiceFinderFactory();
racingEventService = new RacingEventServiceImpl(/* clearPersistentCompetitorStore */ true, serviceFinderFactory); racingEventService = new RacingEventServiceImpl(/* clearPersistentCompetitorStore */ true, serviceFinderFactory, /* restoreTrackedRaces */ false);
serviceFinderFactory.setRacingEventService(racingEventService); serviceFinderFactory.setRacingEventService(racingEventService);
mongoObjectFactory = racingEventService.getMongoObjectFactory(); mongoObjectFactory = racingEventService.getMongoObjectFactory();
domainObjectFactory = racingEventService.getDomainObjectFactory(); domainObjectFactory = racingEventService.getDomainObjectFactory();
@@ -11,6 +11,7 @@ import com.sap.sailing.domain.persistence.MongoRaceLogStoreFactory;
import com.sap.sailing.domain.persistence.MongoRegattaLogStoreFactory; import com.sap.sailing.domain.persistence.MongoRegattaLogStoreFactory;
import com.sap.sailing.domain.persistence.racelog.tracking.DeviceIdentifierMongoHandler; import com.sap.sailing.domain.persistence.racelog.tracking.DeviceIdentifierMongoHandler;
import com.sap.sailing.domain.persistence.racelog.tracking.impl.PlaceHolderDeviceIdentifierMongoHandler; import com.sap.sailing.domain.persistence.racelog.tracking.impl.PlaceHolderDeviceIdentifierMongoHandler;
import com.sap.sailing.domain.racelog.tracking.test.mock.AbstractTypeBasedServiceFinder;
import com.sap.sailing.domain.racelog.tracking.test.mock.SmartphoneImeiIdentifier; import com.sap.sailing.domain.racelog.tracking.test.mock.SmartphoneImeiIdentifier;
import com.sap.sailing.domain.racelogtracking.impl.RaceLogConnectivityParams; import com.sap.sailing.domain.racelogtracking.impl.RaceLogConnectivityParams;
import com.sap.sailing.domain.swisstimingadapter.DomainFactory; import com.sap.sailing.domain.swisstimingadapter.DomainFactory;
@@ -42,7 +43,7 @@ public class MockConnectivityParamsServiceFinderFactory implements TypeBasedServ
private RacingEventService racingEventService; private RacingEventService racingEventService;
public MockConnectivityParamsServiceFinderFactory() { public MockConnectivityParamsServiceFinderFactory() {
serviceFinders.put(RaceTrackingConnectivityParametersHandler.class, new TypeBasedServiceFinder<RaceTrackingConnectivityParametersHandler>() { serviceFinders.put(RaceTrackingConnectivityParametersHandler.class, new AbstractTypeBasedServiceFinder<RaceTrackingConnectivityParametersHandler>() {
@Override @Override
public RaceTrackingConnectivityParametersHandler findService(String type) public RaceTrackingConnectivityParametersHandler findService(String type)
throws NoCorrespondingServiceRegisteredException { throws NoCorrespondingServiceRegisteredException {
@@ -90,7 +91,7 @@ public class MockConnectivityParamsServiceFinderFactory implements TypeBasedServ
public void setFallbackService(RaceTrackingConnectivityParametersHandler fallback) { public void setFallbackService(RaceTrackingConnectivityParametersHandler fallback) {
} }
}); });
serviceFinders.put(DeviceIdentifierMongoHandler.class, new TypeBasedServiceFinder<DeviceIdentifierMongoHandler>() { serviceFinders.put(DeviceIdentifierMongoHandler.class, new AbstractTypeBasedServiceFinder<DeviceIdentifierMongoHandler>() {
@Override @Override
public DeviceIdentifierMongoHandler findService(String type) public DeviceIdentifierMongoHandler findService(String type)
throws NoCorrespondingServiceRegisteredException { throws NoCorrespondingServiceRegisteredException {
@@ -104,14 +105,11 @@ public class MockConnectivityParamsServiceFinderFactory implements TypeBasedServ
@Override @Override
public Set<DeviceIdentifierMongoHandler> findAllServices() { public Set<DeviceIdentifierMongoHandler> findAllServices() {
// TODO Auto-generated method stub
return null; return null;
} }
@Override @Override
public void setFallbackService(DeviceIdentifierMongoHandler fallback) { public void setFallbackService(DeviceIdentifierMongoHandler fallback) {
// TODO Auto-generated method stub
} }
}); });
} }
@@ -9,6 +9,8 @@ import java.net.URISyntaxException;
import java.net.UnknownHostException; import java.net.UnknownHostException;
import java.util.Arrays; import java.util.Arrays;
import java.util.Collections; import java.util.Collections;
import java.util.HashSet;
import java.util.Set;
import java.util.UUID; import java.util.UUID;
import org.junit.Test; import org.junit.Test;
@@ -58,7 +60,8 @@ public class RaceLogConnectivityParamsLoadAndStoreTest extends AbstractConnectiv
// store // store
mongoObjectFactory.addConnectivityParametersForRaceToRestore(rlParams); mongoObjectFactory.addConnectivityParametersForRaceToRestore(rlParams);
// load // load
final Iterable<RaceTrackingConnectivityParameters> connectivityParametersForRacesToRestore = domainObjectFactory.loadConnectivityParametersForRacesToRestore(); final Set<RaceTrackingConnectivityParameters> connectivityParametersForRacesToRestore = new HashSet<>();
domainObjectFactory.loadConnectivityParametersForRacesToRestore(params->connectivityParametersForRacesToRestore.add(params));
// compare // compare
assertEquals(1, Util.size(connectivityParametersForRacesToRestore)); assertEquals(1, Util.size(connectivityParametersForRacesToRestore));
final RaceTrackingConnectivityParameters paramsReadFromDB = connectivityParametersForRacesToRestore.iterator().next(); final RaceTrackingConnectivityParameters paramsReadFromDB = connectivityParametersForRacesToRestore.iterator().next();
@@ -71,6 +74,8 @@ public class RaceLogConnectivityParamsLoadAndStoreTest extends AbstractConnectiv
assertEquals(rlParams.getTrackerID(), raceLogParamsReadFromDB.getTrackerID()); assertEquals(rlParams.getTrackerID(), raceLogParamsReadFromDB.getTrackerID());
// remove again // remove again
mongoObjectFactory.removeConnectivityParametersForRaceToRestore(rlParams); mongoObjectFactory.removeConnectivityParametersForRaceToRestore(rlParams);
assertTrue(Util.isEmpty(domainObjectFactory.loadConnectivityParametersForRacesToRestore())); final Set<RaceTrackingConnectivityParameters> connectivityParametersForRacesToRestore2 = new HashSet<>();
domainObjectFactory.loadConnectivityParametersForRacesToRestore(params->connectivityParametersForRacesToRestore2.add(params));
assertTrue(connectivityParametersForRacesToRestore2.isEmpty());
} }
} }
@@ -7,6 +7,8 @@ import java.net.MalformedURLException;
import java.net.URISyntaxException; import java.net.URISyntaxException;
import java.net.UnknownHostException; import java.net.UnknownHostException;
import java.util.Arrays; import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;
import org.junit.Test; import org.junit.Test;
@@ -52,7 +54,8 @@ public class SwissTimingConnectivityParamsLoadAndStoreTest extends AbstractConne
// store // store
mongoObjectFactory.addConnectivityParametersForRaceToRestore(stParams); mongoObjectFactory.addConnectivityParametersForRaceToRestore(stParams);
// load // load
final Iterable<RaceTrackingConnectivityParameters> connectivityParametersForRacesToRestore = domainObjectFactory.loadConnectivityParametersForRacesToRestore(); final Set<RaceTrackingConnectivityParameters> connectivityParametersForRacesToRestore = new HashSet<>();
domainObjectFactory.loadConnectivityParametersForRacesToRestore(params->connectivityParametersForRacesToRestore.add(params));
// compare // compare
assertEquals(1, Util.size(connectivityParametersForRacesToRestore)); assertEquals(1, Util.size(connectivityParametersForRacesToRestore));
final RaceTrackingConnectivityParameters paramsReadFromDB = connectivityParametersForRacesToRestore.iterator().next(); final RaceTrackingConnectivityParameters paramsReadFromDB = connectivityParametersForRacesToRestore.iterator().next();
@@ -70,7 +73,9 @@ public class SwissTimingConnectivityParamsLoadAndStoreTest extends AbstractConne
assertEquals(stParams.getTrackerID(), stParamsReadFromDB.getTrackerID()); assertEquals(stParams.getTrackerID(), stParamsReadFromDB.getTrackerID());
// remove again // remove again
mongoObjectFactory.removeConnectivityParametersForRaceToRestore(stParams); mongoObjectFactory.removeConnectivityParametersForRaceToRestore(stParams);
assertTrue(Util.isEmpty(domainObjectFactory.loadConnectivityParametersForRacesToRestore())); final Set<RaceTrackingConnectivityParameters> connectivityParametersForRacesToRestore2 = new HashSet<>();
domainObjectFactory.loadConnectivityParametersForRacesToRestore(params->connectivityParametersForRacesToRestore2.add(params));
assertTrue(connectivityParametersForRacesToRestore2.isEmpty());
} }
@Test @Test
@@ -93,7 +98,8 @@ public class SwissTimingConnectivityParamsLoadAndStoreTest extends AbstractConne
// store // store
mongoObjectFactory.addConnectivityParametersForRaceToRestore(stParams); mongoObjectFactory.addConnectivityParametersForRaceToRestore(stParams);
// load // load
final Iterable<RaceTrackingConnectivityParameters> connectivityParametersForRacesToRestore = domainObjectFactory.loadConnectivityParametersForRacesToRestore(); final Set<RaceTrackingConnectivityParameters> connectivityParametersForRacesToRestore = new HashSet<>();
domainObjectFactory.loadConnectivityParametersForRacesToRestore(params->connectivityParametersForRacesToRestore.add(params));
// compare // compare
assertEquals(1, Util.size(connectivityParametersForRacesToRestore)); assertEquals(1, Util.size(connectivityParametersForRacesToRestore));
final RaceTrackingConnectivityParameters paramsReadFromDB = connectivityParametersForRacesToRestore.iterator().next(); final RaceTrackingConnectivityParameters paramsReadFromDB = connectivityParametersForRacesToRestore.iterator().next();
@@ -111,6 +117,8 @@ public class SwissTimingConnectivityParamsLoadAndStoreTest extends AbstractConne
assertEquals(stParams.getTrackerID(), stParamsReadFromDB.getTrackerID()); assertEquals(stParams.getTrackerID(), stParamsReadFromDB.getTrackerID());
// remove again // remove again
mongoObjectFactory.removeConnectivityParametersForRaceToRestore(stParams); mongoObjectFactory.removeConnectivityParametersForRaceToRestore(stParams);
assertTrue(Util.isEmpty(domainObjectFactory.loadConnectivityParametersForRacesToRestore())); final Set<RaceTrackingConnectivityParameters> connectivityParametersForRacesToRestore2 = new HashSet<>();
domainObjectFactory.loadConnectivityParametersForRacesToRestore(params->connectivityParametersForRacesToRestore2.add(params));
assertTrue(connectivityParametersForRacesToRestore2.isEmpty());
} }
} }
@@ -6,6 +6,8 @@ import static org.junit.Assert.assertTrue;
import java.net.MalformedURLException; import java.net.MalformedURLException;
import java.net.URISyntaxException; import java.net.URISyntaxException;
import java.net.UnknownHostException; import java.net.UnknownHostException;
import java.util.HashSet;
import java.util.Set;
import org.junit.Test; import org.junit.Test;
@@ -37,7 +39,8 @@ public class SwissTimingReplayConnectivityParamsLoadAndStoreTest extends Abstrac
// store // store
mongoObjectFactory.addConnectivityParametersForRaceToRestore(stParams); mongoObjectFactory.addConnectivityParametersForRaceToRestore(stParams);
// load // load
final Iterable<RaceTrackingConnectivityParameters> connectivityParametersForRacesToRestore = domainObjectFactory.loadConnectivityParametersForRacesToRestore(); final Set<RaceTrackingConnectivityParameters> connectivityParametersForRacesToRestore = new HashSet<>();
domainObjectFactory.loadConnectivityParametersForRacesToRestore(params->connectivityParametersForRacesToRestore.add(params));
// compare // compare
assertEquals(1, Util.size(connectivityParametersForRacesToRestore)); assertEquals(1, Util.size(connectivityParametersForRacesToRestore));
final RaceTrackingConnectivityParameters paramsReadFromDB = connectivityParametersForRacesToRestore.iterator().next(); final RaceTrackingConnectivityParameters paramsReadFromDB = connectivityParametersForRacesToRestore.iterator().next();
@@ -51,6 +54,8 @@ public class SwissTimingReplayConnectivityParamsLoadAndStoreTest extends Abstrac
assertEquals(useInternalMarkPassingAlgorithm, stParams.isUseInternalMarkPassingAlgorithm()); assertEquals(useInternalMarkPassingAlgorithm, stParams.isUseInternalMarkPassingAlgorithm());
// remove again // remove again
mongoObjectFactory.removeConnectivityParametersForRaceToRestore(stParams); mongoObjectFactory.removeConnectivityParametersForRaceToRestore(stParams);
assertTrue(Util.isEmpty(domainObjectFactory.loadConnectivityParametersForRacesToRestore())); final Set<RaceTrackingConnectivityParameters> connectivityParametersForRacesToRestore2 = new HashSet<>();
domainObjectFactory.loadConnectivityParametersForRacesToRestore(params->connectivityParametersForRacesToRestore2.add(params));
assertTrue(connectivityParametersForRacesToRestore2.isEmpty());
} }
} }
@@ -396,7 +396,7 @@ public class TestStoringAndLoadingEventsAndRegattas extends AbstractMongoDBTest
@Test @Test
public void testLoadStoreSimpleRegattaLeaderboard() { public void testLoadStoreSimpleRegattaLeaderboard() {
RacingEventService res = new RacingEventServiceImpl(PersistenceFactory.INSTANCE.getDomainObjectFactory(getMongoService(), DomainFactory.INSTANCE), PersistenceFactory.INSTANCE RacingEventService res = new RacingEventServiceImpl(PersistenceFactory.INSTANCE.getDomainObjectFactory(getMongoService(), DomainFactory.INSTANCE), PersistenceFactory.INSTANCE
.getMongoObjectFactory(getMongoService()), MediaDBFactory.INSTANCE.getMediaDB(getMongoService()), EmptyWindStore.INSTANCE, EmptySensorFixStore.INSTANCE); .getMongoObjectFactory(getMongoService()), MediaDBFactory.INSTANCE.getMediaDB(getMongoService()), EmptyWindStore.INSTANCE, EmptySensorFixStore.INSTANCE, /* restoreTrackedRaces */ false);
final int numberOfQualifyingRaces = 5; final int numberOfQualifyingRaces = 5;
final int numberOfFinalRaces = 7; final int numberOfFinalRaces = 7;
final String regattaBaseName = "Kieler Woche"; final String regattaBaseName = "Kieler Woche";
@@ -513,7 +513,7 @@ public class TestStoringAndLoadingEventsAndRegattas extends AbstractMongoDBTest
private RacingEventServiceImpl createRacingEventServiceWithOneMockedTrackedRace(final DynamicTrackedRace q2YellowTrackedRace) { private RacingEventServiceImpl createRacingEventServiceWithOneMockedTrackedRace(final DynamicTrackedRace q2YellowTrackedRace) {
return new RacingEventServiceImpl(PersistenceFactory.INSTANCE.getDomainObjectFactory(getMongoService(), DomainFactory.INSTANCE), PersistenceFactory.INSTANCE return new RacingEventServiceImpl(PersistenceFactory.INSTANCE.getDomainObjectFactory(getMongoService(), DomainFactory.INSTANCE), PersistenceFactory.INSTANCE
.getMongoObjectFactory(getMongoService()), MediaDBFactory.INSTANCE.getMediaDB(getMongoService()), EmptyWindStore.INSTANCE, EmptySensorFixStore.INSTANCE) { .getMongoObjectFactory(getMongoService()), MediaDBFactory.INSTANCE.getMediaDB(getMongoService()), EmptyWindStore.INSTANCE, EmptySensorFixStore.INSTANCE, /* restoreTrackedRaces */ false) {
@Override @Override
public DynamicTrackedRace getExistingTrackedRace(RegattaAndRaceIdentifier raceIdentifier) { public DynamicTrackedRace getExistingTrackedRace(RegattaAndRaceIdentifier raceIdentifier) {
return q2YellowTrackedRace; return q2YellowTrackedRace;
@@ -853,7 +853,7 @@ public class TestStoringAndLoadingEventsAndRegattas extends AbstractMongoDBTest
regatta.addRace(racedef); regatta.addRace(racedef);
RacingEventServiceImpl evs = new RacingEventServiceImpl(PersistenceFactory.INSTANCE.getDomainObjectFactory(getMongoService(), DomainFactory.INSTANCE), PersistenceFactory.INSTANCE RacingEventServiceImpl evs = new RacingEventServiceImpl(PersistenceFactory.INSTANCE.getDomainObjectFactory(getMongoService(), DomainFactory.INSTANCE), PersistenceFactory.INSTANCE
.getMongoObjectFactory(getMongoService()), MediaDBFactory.INSTANCE.getMediaDB(getMongoService()), EmptyWindStore.INSTANCE, EmptySensorFixStore.INSTANCE); .getMongoObjectFactory(getMongoService()), MediaDBFactory.INSTANCE.getMediaDB(getMongoService()), EmptyWindStore.INSTANCE, EmptySensorFixStore.INSTANCE, /* restoreTrackedRaces */ false);
assertNull(evs.getRememberedRegattaForRace(racedef.getId())); assertNull(evs.getRememberedRegattaForRace(racedef.getId()));
evs.raceAdded(regatta, racedef); evs.raceAdded(regatta, racedef);
assertNotNull(evs.getRememberedRegattaForRace(racedef.getId())); assertNotNull(evs.getRememberedRegattaForRace(racedef.getId()));
@@ -318,7 +318,7 @@ public class TestStoringAndRetrievingLeaderboardGroups extends AbstractMongoDBTe
// the leaderboard named leaderboardNames[2] occurs in both groups // the leaderboard named leaderboardNames[2] occurs in both groups
RacingEventService racingEventService = new RacingEventServiceImpl(PersistenceFactory.INSTANCE.getDomainObjectFactory(MongoDBService.INSTANCE, DomainFactory.INSTANCE), PersistenceFactory.INSTANCE RacingEventService racingEventService = new RacingEventServiceImpl(PersistenceFactory.INSTANCE.getDomainObjectFactory(MongoDBService.INSTANCE, DomainFactory.INSTANCE), PersistenceFactory.INSTANCE
.getMongoObjectFactory(MongoDBService.INSTANCE), MediaDBFactory.INSTANCE.getMediaDB(MongoDBService.INSTANCE), EmptyWindStore.INSTANCE, EmptySensorFixStore.INSTANCE); // expected to load leaderboard groups .getMongoObjectFactory(MongoDBService.INSTANCE), MediaDBFactory.INSTANCE.getMediaDB(MongoDBService.INSTANCE), EmptyWindStore.INSTANCE, EmptySensorFixStore.INSTANCE, /* restoreTrackedRaces */ false); // expected to load leaderboard groups
final LeaderboardGroup loadedLeaderboardGroup1 = racingEventService.getLeaderboardGroupByName(groupName1); final LeaderboardGroup loadedLeaderboardGroup1 = racingEventService.getLeaderboardGroupByName(groupName1);
final LeaderboardGroup loadedLeaderboardGroup2 = racingEventService.getLeaderboardGroupByName(groupName2); final LeaderboardGroup loadedLeaderboardGroup2 = racingEventService.getLeaderboardGroupByName(groupName2);
@@ -8,6 +8,8 @@ import java.net.URI;
import java.net.URISyntaxException; import java.net.URISyntaxException;
import java.net.URL; import java.net.URL;
import java.net.UnknownHostException; import java.net.UnknownHostException;
import java.util.HashSet;
import java.util.Set;
import org.junit.Test; import org.junit.Test;
@@ -49,7 +51,8 @@ public class TracTracConnectivityParamsLoadAndStoreTest extends AbstractConnecti
// store // store
mongoObjectFactory.addConnectivityParametersForRaceToRestore(tracTracParams); mongoObjectFactory.addConnectivityParametersForRaceToRestore(tracTracParams);
// load // load
final Iterable<RaceTrackingConnectivityParameters> connectivityParametersForRacesToRestore = domainObjectFactory.loadConnectivityParametersForRacesToRestore(); final Set<RaceTrackingConnectivityParameters> connectivityParametersForRacesToRestore = new HashSet<>();
domainObjectFactory.loadConnectivityParametersForRacesToRestore(params->connectivityParametersForRacesToRestore.add(params));
// compare // compare
assertEquals(1, Util.size(connectivityParametersForRacesToRestore)); assertEquals(1, Util.size(connectivityParametersForRacesToRestore));
final RaceTrackingConnectivityParameters paramsReadFromDB = connectivityParametersForRacesToRestore.iterator().next(); final RaceTrackingConnectivityParameters paramsReadFromDB = connectivityParametersForRacesToRestore.iterator().next();
@@ -70,6 +73,8 @@ public class TracTracConnectivityParamsLoadAndStoreTest extends AbstractConnecti
assertEquals(tracTracParams.getTrackerID(), tracTracParamsReadFromDB.getTrackerID()); assertEquals(tracTracParams.getTrackerID(), tracTracParamsReadFromDB.getTrackerID());
// remove again // remove again
mongoObjectFactory.removeConnectivityParametersForRaceToRestore(tracTracParams); mongoObjectFactory.removeConnectivityParametersForRaceToRestore(tracTracParams);
assertTrue(Util.isEmpty(domainObjectFactory.loadConnectivityParametersForRacesToRestore())); final Set<RaceTrackingConnectivityParameters> connectivityParametersForRacesToRestore2 = new HashSet<>();
domainObjectFactory.loadConnectivityParametersForRacesToRestore(params->connectivityParametersForRacesToRestore2.add(params));
assertTrue(connectivityParametersForRacesToRestore2.isEmpty());
} }
} }
@@ -1,45 +0,0 @@
package com.sap.sailing.server.gateway.serialization.racelog.tracking.impl;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;
import com.sap.sailing.domain.common.tracking.GPSFix;
import com.sap.sailing.domain.common.tracking.GPSFixMoving;
import com.sap.sailing.server.gateway.deserialization.impl.GPSFixJsonDeserializer;
import com.sap.sailing.server.gateway.deserialization.impl.GPSFixMovingJsonDeserializer;
import com.sap.sailing.server.gateway.serialization.impl.GPSFixJsonSerializer;
import com.sap.sailing.server.gateway.serialization.impl.GPSFixMovingJsonSerializer;
import com.sap.sailing.server.gateway.serialization.racelog.tracking.GPSFixJsonHandler;
import com.sap.sse.common.NoCorrespondingServiceRegisteredException;
import com.sap.sse.common.TypeBasedServiceFinder;
public class GPSFixJsonServiceFinder implements TypeBasedServiceFinder<GPSFixJsonHandler> {
private final GPSFixJsonHandler gpsFixHandler = new GPSFixJsonHandlerImpl<GPSFix>(new GPSFixJsonDeserializer(),
new GPSFixJsonSerializer());
private final GPSFixJsonHandler gpsFixMovingHandler = new GPSFixJsonHandlerImpl<GPSFixMoving>(
new GPSFixMovingJsonDeserializer(), new GPSFixMovingJsonSerializer());
@Override
public GPSFixJsonHandler findService(String type) throws NoCorrespondingServiceRegisteredException {
if (type.equals(GPSFixJsonDeserializer.TYPE)) {
return gpsFixHandler;
} else if (type.equals(GPSFixMovingJsonDeserializer.TYPE)) {
return gpsFixMovingHandler;
}
throw new NoCorrespondingServiceRegisteredException(
"Only handlers for GPSFix, GPSFixMoving, GPSFixNmeaDTO, GPSFixMovingNmeaDTO are registered", type,
GPSFixJsonHandler.class.getSimpleName());
}
@Override
public void setFallbackService(GPSFixJsonHandler fallback) {
}
@Override
public Set<GPSFixJsonHandler> findAllServices() {
return new HashSet<GPSFixJsonHandler>(Arrays.asList(gpsFixHandler, gpsFixMovingHandler));
}
}
@@ -40,8 +40,7 @@ public abstract class AbstractJaxRsApiTest {
public void setUp() { public void setUp() {
service = MongoDBConfiguration.getDefaultTestConfiguration().getService(); service = MongoDBConfiguration.getDefaultTestConfiguration().getService();
service.getDB().dropDatabase(); service.getDB().dropDatabase();
racingEventService = new RacingEventServiceImpl(/* clearPersistentCompetitorStore */ true, new MockSmartphoneUuidServiceFinderFactory(), /* restoreTrackedRaces */ false);
racingEventService = new RacingEventServiceImpl(true, new MockSmartphoneUuidServiceFinderFactory());
} }
protected <T extends AbstractSailingServerResource> T spyResource(T resource) { protected <T extends AbstractSailingServerResource> T spyResource(T resource) {
@@ -45,7 +45,7 @@ public class GPSFixesResourceTest {
@Before @Before
public void setup() { public void setup() {
service = new RacingEventServiceImpl(true, new MockSmartphoneUuidServiceFinderFactory()); service = new RacingEventServiceImpl(/* clearPersistentCompetitorStore */ true, new MockSmartphoneUuidServiceFinderFactory(), /* restoreTrackedRaces */ false);
service.getMongoObjectFactory().getDatabase().dropDatabase(); service.getMongoObjectFactory().getDatabase().dropDatabase();
} }
@@ -55,7 +55,7 @@ public abstract class AbstractServerReplicationTest extends com.sap.sse.replicat
@Override public DomainFactory getBaseDomainFactory() { return baseDomainFactory; } @Override public DomainFactory getBaseDomainFactory() { return baseDomainFactory; }
@Override public CompetitorStore getCompetitorStore() { return getBaseDomainFactory().getCompetitorStore(); } @Override public CompetitorStore getCompetitorStore() { return getBaseDomainFactory().getCompetitorStore(); }
}; };
}, MediaDBFactory.INSTANCE.getMediaDB(mongoDBService), EmptyWindStore.INSTANCE, EmptySensorFixStore.INSTANCE, null, null, /* sailingNotificationService */ null); }, MediaDBFactory.INSTANCE.getMediaDB(mongoDBService), EmptyWindStore.INSTANCE, EmptySensorFixStore.INSTANCE, null, null, /* sailingNotificationService */ null, /* restoreTrackedRaces */ false);
} }
@Override @Override
@@ -74,7 +74,7 @@ public abstract class AbstractServerReplicationTest extends com.sap.sse.replicat
@Override public CompetitorStore getCompetitorStore() { return getBaseDomainFactory().getCompetitorStore(); } @Override public CompetitorStore getCompetitorStore() { return getBaseDomainFactory().getCompetitorStore(); }
}; };
}, MediaDBFactory.INSTANCE.getMediaDB(mongoDBService), EmptyWindStore.INSTANCE, EmptySensorFixStore.INSTANCE, }, MediaDBFactory.INSTANCE.getMediaDB(mongoDBService), EmptyWindStore.INSTANCE, EmptySensorFixStore.INSTANCE,
/* serviceFinderFactory */ null, null, /* sailingNotificationService */ null); /* serviceFinderFactory */ null, null, /* sailingNotificationService */ null, /* restoreTrackedRaces */ false);
} }
} }
} }
@@ -164,7 +164,7 @@ public class DelayedLeaderboardCorrectionsReplicationTest extends AbstractServer
private RacingEventServiceImpl createRacingEventServiceWithOneMockedTrackedRace(final DynamicTrackedRace q2YellowTrackedRace, private RacingEventServiceImpl createRacingEventServiceWithOneMockedTrackedRace(final DynamicTrackedRace q2YellowTrackedRace,
DomainFactory domainFactory) { DomainFactory domainFactory) {
return new RacingEventServiceImpl(PersistenceFactory.INSTANCE.getDomainObjectFactory(MongoDBService.INSTANCE, domainFactory), PersistenceFactory.INSTANCE return new RacingEventServiceImpl(PersistenceFactory.INSTANCE.getDomainObjectFactory(MongoDBService.INSTANCE, domainFactory), PersistenceFactory.INSTANCE
.getMongoObjectFactory(MongoDBService.INSTANCE), MediaDBFactory.INSTANCE.getMediaDB(MongoDBService.INSTANCE), EmptyWindStore.INSTANCE, EmptySensorFixStore.INSTANCE) { .getMongoObjectFactory(MongoDBService.INSTANCE), MediaDBFactory.INSTANCE.getMediaDB(MongoDBService.INSTANCE), EmptyWindStore.INSTANCE, EmptySensorFixStore.INSTANCE, /* restoreTrackedRaces */ false) {
@Override @Override
public DynamicTrackedRace getExistingTrackedRace(RegattaAndRaceIdentifier raceIdentifier) { public DynamicTrackedRace getExistingTrackedRace(RegattaAndRaceIdentifier raceIdentifier) {
return q2YellowTrackedRace; return q2YellowTrackedRace;
@@ -88,9 +88,9 @@ public class InitialLoadReplicationObjectIdentityTest extends AbstractServerRepl
public void setUp() throws Exception { public void setUp() throws Exception {
persistenceSetUp(/* dropDB */ true); persistenceSetUp(/* dropDB */ true);
this.master = new RacingEventServiceImpl(PersistenceFactory.INSTANCE.getDomainObjectFactory(testSetUp.mongoDBService, DomainFactory.INSTANCE), PersistenceFactory.INSTANCE this.master = new RacingEventServiceImpl(PersistenceFactory.INSTANCE.getDomainObjectFactory(testSetUp.mongoDBService, DomainFactory.INSTANCE), PersistenceFactory.INSTANCE
.getMongoObjectFactory(testSetUp.mongoDBService), MediaDBFactory.INSTANCE.getMediaDB(testSetUp.mongoDBService), EmptyWindStore.INSTANCE, EmptySensorFixStore.INSTANCE); .getMongoObjectFactory(testSetUp.mongoDBService), MediaDBFactory.INSTANCE.getMediaDB(testSetUp.mongoDBService), EmptyWindStore.INSTANCE, EmptySensorFixStore.INSTANCE, /* restoreTrackedRaces */ false);
this.replica = new RacingEventServiceImpl(PersistenceFactory.INSTANCE.getDomainObjectFactory(testSetUp.mongoDBService, DomainFactory.INSTANCE), PersistenceFactory.INSTANCE this.replica = new RacingEventServiceImpl(PersistenceFactory.INSTANCE.getDomainObjectFactory(testSetUp.mongoDBService, DomainFactory.INSTANCE), PersistenceFactory.INSTANCE
.getMongoObjectFactory(testSetUp.mongoDBService), MediaDBFactory.INSTANCE.getMediaDB(testSetUp.mongoDBService), EmptyWindStore.INSTANCE, EmptySensorFixStore.INSTANCE); .getMongoObjectFactory(testSetUp.mongoDBService), MediaDBFactory.INSTANCE.getMediaDB(testSetUp.mongoDBService), EmptyWindStore.INSTANCE, EmptySensorFixStore.INSTANCE, /* restoreTrackedRaces */ false);
} }
private void performReplicationSetup() throws Exception { private void performReplicationSetup() throws Exception {
@@ -62,7 +62,7 @@ public class MasterDataImporterMediaTest {
when(mediaDb.loadAllMediaTracks()).thenReturn(Arrays.asList(existingDbMediaTracks)); when(mediaDb.loadAllMediaTracks()).thenReturn(Arrays.asList(existingDbMediaTracks));
racingEventService = spy(new RacingEventServiceImpl(domainObjectFactory, mongoObjectFactory, mediaDb, racingEventService = spy(new RacingEventServiceImpl(domainObjectFactory, mongoObjectFactory, mediaDb,
windStore, sensorFixStore)); windStore, sensorFixStore, /* restoreTrackedRaces */ false));
} }
@Test @Test
@@ -808,7 +808,7 @@ public class MasterDataImportTest {
RacingEventService sourceService = new RacingEventServiceImpl( RacingEventService sourceService = new RacingEventServiceImpl(
PersistenceFactory.INSTANCE.getDomainObjectFactory(MongoDBService.INSTANCE, sourceDomainFactory), PersistenceFactory.INSTANCE.getDomainObjectFactory(MongoDBService.INSTANCE, sourceDomainFactory),
PersistenceFactory.INSTANCE.getMongoObjectFactory(MongoDBService.INSTANCE), PersistenceFactory.INSTANCE.getMongoObjectFactory(MongoDBService.INSTANCE),
MediaDBFactory.INSTANCE.getDefaultMediaDB(), EmptyWindStore.INSTANCE, EmptySensorFixStore.INSTANCE); MediaDBFactory.INSTANCE.getDefaultMediaDB(), EmptyWindStore.INSTANCE, EmptySensorFixStore.INSTANCE, /* restoreTrackedRaces */ false);
Event event = sourceService.addEvent(TEST_EVENT_NAME, /* eventDescription */null, eventStartDate, eventEndDate, Event event = sourceService.addEvent(TEST_EVENT_NAME, /* eventDescription */null, eventStartDate, eventEndDate,
"testVenue", false, eventUUID); "testVenue", false, eventUUID);
UUID courseAreaUUID = UUID.randomUUID(); UUID courseAreaUUID = UUID.randomUUID();
@@ -23,7 +23,7 @@ public abstract class RacingEventServiceImplMock extends RacingEventServiceImpl
private DataImportLockWithProgress lock; private DataImportLockWithProgress lock;
public RacingEventServiceImplMock() { public RacingEventServiceImplMock() {
super(false, null); super(/* clearPersistentCompetitorStore */ false, null, /* restoreTrackedRaces */ false);
} }
public RacingEventServiceImplMock(DataImportProgressImpl dataImportProgressImpl, TypeBasedServiceFinderFactory serviceFinderFactory) { public RacingEventServiceImplMock(DataImportProgressImpl dataImportProgressImpl, TypeBasedServiceFinderFactory serviceFinderFactory) {
@@ -22,7 +22,7 @@
<stringAttribute key="org.eclipse.jdt.launching.JRE_CONTAINER" value="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8"/> <stringAttribute key="org.eclipse.jdt.launching.JRE_CONTAINER" value="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8"/>
<stringAttribute key="org.eclipse.jdt.launching.PROGRAM_ARGUMENTS" value="-os ${target.os} -ws ${target.ws} -arch ${target.arch} -nl ${target.nl} -consoleLog -console -clean"/> <stringAttribute key="org.eclipse.jdt.launching.PROGRAM_ARGUMENTS" value="-os ${target.os} -ws ${target.ws} -arch ${target.arch} -nl ${target.nl} -consoleLog -console -clean"/>
<stringAttribute key="org.eclipse.jdt.launching.SOURCE_PATH_PROVIDER" value="org.eclipse.pde.ui.workbenchClasspathProvider"/> <stringAttribute key="org.eclipse.jdt.launching.SOURCE_PATH_PROVIDER" value="org.eclipse.pde.ui.workbenchClasspathProvider"/>
<stringAttribute key="org.eclipse.jdt.launching.VM_ARGUMENTS" value="-ea -Declipse.ignoreApp=true -Dosgi.noShutdown=true -Dfile.encoding=cp1252 -Dexpedition.udp.port=2010 -Xmx6000m -XX:+UseG1GC -Dhttp.proxyHost=proxy -Dhttp.proxyPort=8080 -Dhttps.proxyHost=proxy -Dhttps.proxyPort=8080 -Djetty.home=${project_loc:com.sap.sailing.server}/../target/configuration/jetty -Djava.util.logging.config.file=${project_loc:com.sap.sailing.server}/../target/configuration/logging_debug.properties -Dkiwo.results=${project_loc:com.sap.sailing.kiworesultimport.test}/resources -Dpersistentcompetitors.clear=false -XX:+UseMembar -Digtimi.client.id=7fcdd217e0aa16090edb4ad55b09ec43b2021090e209541fc9b7003c2a2b70c6 -Digtimi.client.secret=aa569cf4909bdc7b0e04b11873f3c4ea20687421e010fcc25b771cca9e6f3f9a -Digtimi.client.redirecturi=http://127.0.0.1:8888/igtimi/oauth/v1/authorizationcallback -Dpolardata.source.url=https://dev.sapsailing.com"/> <stringAttribute key="org.eclipse.jdt.launching.VM_ARGUMENTS" value="-ea -Declipse.ignoreApp=true -Dosgi.noShutdown=true -Dfile.encoding=cp1252 -Dexpedition.udp.port=2010 -Xmx6000m -XX:+UseG1GC -Dhttp.proxyHost=proxy -Dhttp.proxyPort=8080 -Dhttps.proxyHost=proxy -Dhttps.proxyPort=8080 -Djetty.home=${project_loc:com.sap.sailing.server}/../target/configuration/jetty -Djava.util.logging.config.file=${project_loc:com.sap.sailing.server}/../target/configuration/logging_debug.properties -Dkiwo.results=${project_loc:com.sap.sailing.kiworesultimport.test}/resources -Dpersistentcompetitors.clear=false -XX:+UseMembar -Digtimi.client.id=7fcdd217e0aa16090edb4ad55b09ec43b2021090e209541fc9b7003c2a2b70c6 -Digtimi.client.secret=aa569cf4909bdc7b0e04b11873f3c4ea20687421e010fcc25b771cca9e6f3f9a -Digtimi.client.redirecturi=http://127.0.0.1:8888/igtimi/oauth/v1/authorizationcallback -Dpolardata.source.url=https://dev.sapsailing.com -Drestore.tracked.races=true"/>
<stringAttribute key="org.eclipse.jdt.launching.WORKING_DIRECTORY" value="${workspace_loc}"/> <stringAttribute key="org.eclipse.jdt.launching.WORKING_DIRECTORY" value="${workspace_loc}"/>
<stringAttribute key="pde.version" value="3.3"/> <stringAttribute key="pde.version" value="3.3"/>
<stringAttribute key="profilingTraceType-ALLOCATION_TRACE" value="KEY_APPLICATION_FILTER%CTX_KEY%*%CTX_ENTRY%KEY_INC_LINE_NRS%CTX_KEY%true%CTX_ENTRY%KEY_MAX_SIZE%CTX_KEY%65536%CTX_ENTRY%INCREASE_COUNT%CTX_KEY%8192%CTX_ENTRY%KEY_USER_FILTER%CTX_KEY%*%CTX_ENTRY%KEY_ID%CTX_KEY%false%CTX_ENTRY%KEY_MIN_SIZE%CTX_KEY%32%CTX_ENTRY%KEY_SESSION_FILTER%CTX_KEY%*%CTX_ENTRY%KEY_ENABLEMENT%CTX_KEY%false%CTX_ENTRY%CLASS_FILTER%CTX_KEY%*%CTX_ENTRY%KEY_REQUEST_FILTER%CTX_KEY%*%CTX_ENTRY%KEY_ADAPTIVE%CTX_KEY%false%CTX_ENTRY%KEY_JRUBY_SUPPORT%CTX_KEY%false%CTX_ENTRY%"/> <stringAttribute key="profilingTraceType-ALLOCATION_TRACE" value="KEY_APPLICATION_FILTER%CTX_KEY%*%CTX_ENTRY%KEY_INC_LINE_NRS%CTX_KEY%true%CTX_ENTRY%KEY_MAX_SIZE%CTX_KEY%65536%CTX_ENTRY%INCREASE_COUNT%CTX_KEY%8192%CTX_ENTRY%KEY_USER_FILTER%CTX_KEY%*%CTX_ENTRY%KEY_ID%CTX_KEY%false%CTX_ENTRY%KEY_MIN_SIZE%CTX_KEY%32%CTX_ENTRY%KEY_SESSION_FILTER%CTX_KEY%*%CTX_ENTRY%KEY_ENABLEMENT%CTX_KEY%false%CTX_ENTRY%CLASS_FILTER%CTX_KEY%*%CTX_ENTRY%KEY_REQUEST_FILTER%CTX_KEY%*%CTX_ENTRY%KEY_ADAPTIVE%CTX_KEY%false%CTX_ENTRY%KEY_JRUBY_SUPPORT%CTX_KEY%false%CTX_ENTRY%"/>
@@ -55,6 +55,8 @@ public class Activator implements BundleActivator {
private static final String CLEAR_PERSISTENT_COMPETITORS_PROPERTY_NAME = "persistentcompetitors.clear"; private static final String CLEAR_PERSISTENT_COMPETITORS_PROPERTY_NAME = "persistentcompetitors.clear";
private static final String RESTORE_TRACKED_RACES_PROPERTY_NAME = "restore.tracked.races";
private static ExtenderBundleTracker extenderBundleTracker; private static ExtenderBundleTracker extenderBundleTracker;
private CachedOsgiTypeBasedServiceFinderFactory serviceFinderFactory; private CachedOsgiTypeBasedServiceFinderFactory serviceFinderFactory;
@@ -63,6 +65,8 @@ public class Activator implements BundleActivator {
private final boolean clearPersistentCompetitors; private final boolean clearPersistentCompetitors;
private final boolean restoreTrackedRaces;
private Set<ServiceRegistration<?>> registrations = new HashSet<>(); private Set<ServiceRegistration<?>> registrations = new HashSet<>();
private ObjectName mBeanName; private ObjectName mBeanName;
@@ -82,6 +86,8 @@ public class Activator implements BundleActivator {
public Activator() { public Activator() {
clearPersistentCompetitors = Boolean clearPersistentCompetitors = Boolean
.valueOf(System.getProperty(CLEAR_PERSISTENT_COMPETITORS_PROPERTY_NAME, "" + false)); .valueOf(System.getProperty(CLEAR_PERSISTENT_COMPETITORS_PROPERTY_NAME, "" + false));
restoreTrackedRaces = Boolean
.valueOf(System.getProperty(RESTORE_TRACKED_RACES_PROPERTY_NAME, "" + false));
logger.log(Level.INFO, logger.log(Level.INFO,
"setting " + CLEAR_PERSISTENT_COMPETITORS_PROPERTY_NAME + " to " + clearPersistentCompetitors); "setting " + CLEAR_PERSISTENT_COMPETITORS_PROPERTY_NAME + " to " + clearPersistentCompetitors);
// there is exactly one instance of the racingEventService in the whole server // there is exactly one instance of the racingEventService in the whole server
@@ -103,7 +109,7 @@ public class Activator implements BundleActivator {
// instead. // instead.
serviceFinderFactory = new CachedOsgiTypeBasedServiceFinderFactory(context); serviceFinderFactory = new CachedOsgiTypeBasedServiceFinderFactory(context);
racingEventService = new RacingEventServiceImpl(clearPersistentCompetitors, serviceFinderFactory, racingEventService = new RacingEventServiceImpl(clearPersistentCompetitors, serviceFinderFactory,
trackedRegattaListener, notificationService); trackedRegattaListener, notificationService, restoreTrackedRaces);
notificationService.setRacingEventService(racingEventService); notificationService.setRacingEventService(racingEventService);
masterDataImportClassLoaderServiceTracker = new ServiceTracker<MasterDataImportClassLoaderService, MasterDataImportClassLoaderService>( masterDataImportClassLoaderServiceTracker = new ServiceTracker<MasterDataImportClassLoaderService, MasterDataImportClassLoaderService>(
@@ -9,6 +9,7 @@ import java.io.ObjectOutputStream;
import java.io.Serializable; import java.io.Serializable;
import java.net.MalformedURLException; import java.net.MalformedURLException;
import java.net.SocketException; import java.net.SocketException;
import java.net.URISyntaxException;
import java.net.URL; import java.net.URL;
import java.net.URLConnection; import java.net.URLConnection;
import java.net.URLEncoder; import java.net.URLEncoder;
@@ -465,20 +466,21 @@ public class RacingEventServiceImpl implements RacingEventService, ClearStateTes
* compatibility with prior releases that did not support a persistent competitor collection. * compatibility with prior releases that did not support a persistent competitor collection.
*/ */
public RacingEventServiceImpl() { public RacingEventServiceImpl() {
this(true, /* serviceFinderFactory */ null); this(/* clearPersistentCompetitorStore */ true, /* serviceFinderFactory */ null, /* restoreTrackedRaces */ false);
} }
public RacingEventServiceImpl(WindStore windStore, SensorFixStore sensorFixStore, public RacingEventServiceImpl(WindStore windStore, SensorFixStore sensorFixStore,
TypeBasedServiceFinderFactory serviceFinderFactory) { TypeBasedServiceFinderFactory serviceFinderFactory) {
this(true, windStore, sensorFixStore, serviceFinderFactory, /* sailingNotificationService */ null); this(/* clearPersistentCompetitorStore */ true, windStore, sensorFixStore, serviceFinderFactory,
/* sailingNotificationService */ null, /* restoreTrackedRaces */ false);
} }
void setBundleContext(BundleContext bundleContext) { void setBundleContext(BundleContext bundleContext) {
this.bundleContext = bundleContext; this.bundleContext = bundleContext;
} }
public RacingEventServiceImpl(boolean clearPersistentCompetitorStore, final TypeBasedServiceFinderFactory serviceFinderFactory) { public RacingEventServiceImpl(boolean clearPersistentCompetitorStore, final TypeBasedServiceFinderFactory serviceFinderFactory, boolean restoreTrackedRaces) {
this(clearPersistentCompetitorStore, serviceFinderFactory, null, /* sailingNotificationService */ null); this(clearPersistentCompetitorStore, serviceFinderFactory, null, /* sailingNotificationService */ null, restoreTrackedRaces);
} }
/** /**
@@ -494,7 +496,7 @@ public class RacingEventServiceImpl implements RacingEventService, ClearStateTes
* notification service is available, e.g., in test set-ups * notification service is available, e.g., in test set-ups
*/ */
public RacingEventServiceImpl(boolean clearPersistentCompetitorStore, final TypeBasedServiceFinderFactory serviceFinderFactory, public RacingEventServiceImpl(boolean clearPersistentCompetitorStore, final TypeBasedServiceFinderFactory serviceFinderFactory,
TrackedRegattaListener trackedRegattaListener, SailingNotificationService sailingNotificationService) { TrackedRegattaListener trackedRegattaListener, SailingNotificationService sailingNotificationService, boolean restoreTrackedRaces) {
this((final RaceLogResolver raceLogResolver)-> { this((final RaceLogResolver raceLogResolver)-> {
return new ConstructorParameters() { return new ConstructorParameters() {
private final MongoObjectFactory mongoObjectFactory = PersistenceFactory.INSTANCE.getDefaultMongoObjectFactory(serviceFinderFactory); private final MongoObjectFactory mongoObjectFactory = PersistenceFactory.INSTANCE.getDefaultMongoObjectFactory(serviceFinderFactory);
@@ -507,11 +509,12 @@ public class RacingEventServiceImpl implements RacingEventService, ClearStateTes
@Override public DomainFactory getBaseDomainFactory() { return competitorStore.getBaseDomainFactory(); } @Override public DomainFactory getBaseDomainFactory() { return competitorStore.getBaseDomainFactory(); }
@Override public CompetitorStore getCompetitorStore() { return competitorStore; } @Override public CompetitorStore getCompetitorStore() { return competitorStore; }
}; };
}, MediaDBFactory.INSTANCE.getDefaultMediaDB(), null, null, serviceFinderFactory ,trackedRegattaListener, sailingNotificationService); }, MediaDBFactory.INSTANCE.getDefaultMediaDB(), null, null, serviceFinderFactory ,trackedRegattaListener, sailingNotificationService, restoreTrackedRaces);
} }
private RacingEventServiceImpl(final boolean clearPersistentCompetitorStore, WindStore windStore, private RacingEventServiceImpl(final boolean clearPersistentCompetitorStore, WindStore windStore,
SensorFixStore sensorFixStore, final TypeBasedServiceFinderFactory serviceFinderFactory, SailingNotificationService sailingNotificationService) { SensorFixStore sensorFixStore, final TypeBasedServiceFinderFactory serviceFinderFactory,
SailingNotificationService sailingNotificationService, boolean restoreTrackedRaces) {
this((final RaceLogResolver raceLogResolver)-> { this((final RaceLogResolver raceLogResolver)-> {
return new ConstructorParameters() { return new ConstructorParameters() {
private final MongoObjectFactory mongoObjectFactory = PersistenceFactory.INSTANCE.getDefaultMongoObjectFactory(serviceFinderFactory); private final MongoObjectFactory mongoObjectFactory = PersistenceFactory.INSTANCE.getDefaultMongoObjectFactory(serviceFinderFactory);
@@ -524,11 +527,11 @@ public class RacingEventServiceImpl implements RacingEventService, ClearStateTes
@Override public DomainFactory getBaseDomainFactory() { return competitorStore.getBaseDomainFactory(); } @Override public DomainFactory getBaseDomainFactory() { return competitorStore.getBaseDomainFactory(); }
@Override public CompetitorStore getCompetitorStore() { return competitorStore; } @Override public CompetitorStore getCompetitorStore() { return competitorStore; }
}; };
}, MediaDBFactory.INSTANCE.getDefaultMediaDB(), windStore, sensorFixStore, serviceFinderFactory, null, sailingNotificationService); }, MediaDBFactory.INSTANCE.getDefaultMediaDB(), windStore, sensorFixStore, serviceFinderFactory, null, sailingNotificationService, restoreTrackedRaces);
} }
public RacingEventServiceImpl(final DomainObjectFactory domainObjectFactory, MongoObjectFactory mongoObjectFactory, public RacingEventServiceImpl(final DomainObjectFactory domainObjectFactory, MongoObjectFactory mongoObjectFactory,
MediaDB mediaDB, WindStore windStore, SensorFixStore sensorFixStore) { MediaDB mediaDB, WindStore windStore, SensorFixStore sensorFixStore, boolean restoreTrackedRaces) {
this((final RaceLogResolver raceLogResolver)-> { this((final RaceLogResolver raceLogResolver)-> {
return new ConstructorParameters() { return new ConstructorParameters() {
@Override public DomainObjectFactory getDomainObjectFactory() { return domainObjectFactory; } @Override public DomainObjectFactory getDomainObjectFactory() { return domainObjectFactory; }
@@ -536,7 +539,7 @@ public class RacingEventServiceImpl implements RacingEventService, ClearStateTes
@Override public DomainFactory getBaseDomainFactory() { return domainObjectFactory.getBaseDomainFactory(); } @Override public DomainFactory getBaseDomainFactory() { return domainObjectFactory.getBaseDomainFactory(); }
@Override public CompetitorStore getCompetitorStore() { return getBaseDomainFactory().getCompetitorStore(); } @Override public CompetitorStore getCompetitorStore() { return getBaseDomainFactory().getCompetitorStore(); }
}; };
}, mediaDB, windStore, sensorFixStore, null, null, /* sailingNotificationService */ null); }, mediaDB, windStore, sensorFixStore, null, null, /* sailingNotificationService */ null, restoreTrackedRaces);
} }
/** /**
@@ -550,10 +553,19 @@ public class RacingEventServiceImpl implements RacingEventService, ClearStateTes
* @param sailingNotificationService * @param sailingNotificationService
* a notification service to call upon events worth notifying users about, or {@code null} if no * 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 * notification service is available, e.g., in test set-ups
* @param restoreTrackedRaces
* if {@code true}, the tracking connectivity parameters for the races last loaded in the server are
* {@link DomainObjectFactory#loadConnectivityParametersForRacesToRestore(Consumer<RaceTrackingConnectivityParameter>) obtained} from the database,
* and {@link RaceTracker}s are
* {@link #addRace(RegattaIdentifier, RaceTrackingConnectivityParameters, long) created} for those,
* effectively restoring the server state to what it was last according to the database. If {@code false},
* all restore information is
* {@link MongoObjectFactory#removeAllConnectivityParametersForRacesToRestore() cleared} from the
* database, and the server starts out with an empty list of tracked races.
*/ */
public RacingEventServiceImpl(Function<RaceLogResolver, ConstructorParameters> constructorParametersProvider, MediaDB mediaDb, public RacingEventServiceImpl(Function<RaceLogResolver, ConstructorParameters> constructorParametersProvider, MediaDB mediaDb,
final WindStore windStore, final SensorFixStore sensorFixStore, TypeBasedServiceFinderFactory serviceFinderFactory, final WindStore windStore, final SensorFixStore sensorFixStore, TypeBasedServiceFinderFactory serviceFinderFactory,
TrackedRegattaListener trackedRegattaListener, SailingNotificationService sailingNotificationService) { TrackedRegattaListener trackedRegattaListener, SailingNotificationService sailingNotificationService, boolean restoreTrackedRaces) {
logger.info("Created " + this); logger.info("Created " + this);
this.scoreCorrectionListenersByLeaderboard = new ConcurrentHashMap<>(); this.scoreCorrectionListenersByLeaderboard = new ConcurrentHashMap<>();
this.notificationService = sailingNotificationService; this.notificationService = sailingNotificationService;
@@ -616,15 +628,12 @@ public class RacingEventServiceImpl implements RacingEventService, ClearStateTes
this.sensorFixStore = sensorFixStore == null ? MongoSensorFixStoreFactory.INSTANCE.getMongoGPSFixStore( this.sensorFixStore = sensorFixStore == null ? MongoSensorFixStoreFactory.INSTANCE.getMongoGPSFixStore(
mongoObjectFactory, domainObjectFactory, serviceFinderFactory) : sensorFixStore; mongoObjectFactory, domainObjectFactory, serviceFinderFactory) : sensorFixStore;
} catch (Exception e) { } catch (Exception e) {
e.printStackTrace(); logger.log(Level.SEVERE, "Exception trying to obtain MongoDB sensor fix store", e);
throw new RuntimeException(e); throw new RuntimeException(e);
} }
this.configurationMap = new DeviceConfigurationMapImpl(); this.configurationMap = new DeviceConfigurationMapImpl();
this.serviceFinderFactory = serviceFinderFactory; this.serviceFinderFactory = serviceFinderFactory;
this.trackedRegattaListener = trackedRegattaListener == null ? EmptyTrackedRegattaListener.INSTANCE : trackedRegattaListener; this.trackedRegattaListener = trackedRegattaListener == null ? EmptyTrackedRegattaListener.INSTANCE : trackedRegattaListener;
sailingServerConfiguration = domainObjectFactory.loadServerConfiguration(); sailingServerConfiguration = domainObjectFactory.loadServerConfiguration();
final Iterable<Pair<Event, Boolean>> loadedEventsWithRequireStoreFlag = loadStoredEvents(); final Iterable<Pair<Event, Boolean>> loadedEventsWithRequireStoreFlag = loadStoredEvents();
loadStoredRegattas(); loadStoredRegattas();
@@ -634,7 +643,6 @@ public class RacingEventServiceImpl implements RacingEventService, ClearStateTes
loadMediaLibary(); loadMediaLibary();
loadStoredDeviceConfigurations(); loadStoredDeviceConfigurations();
loadAllRemoteSailingServersAndSchedulePeriodicEventCacheRefresh(); loadAllRemoteSailingServersAndSchedulePeriodicEventCacheRefresh();
// Stores all events which run through a data migration // Stores all events which run through a data migration
// Remark: must be called after loadLinksFromEventsToLeaderboardGroups(), otherwise would loose the Event -> LeaderboardGroup relation // Remark: must be called after loadLinksFromEventsToLeaderboardGroups(), otherwise would loose the Event -> LeaderboardGroup relation
for (Pair<Event, Boolean> eventAndRequireStoreFlag : loadedEventsWithRequireStoreFlag) { for (Pair<Event, Boolean> eventAndRequireStoreFlag : loadedEventsWithRequireStoreFlag) {
@@ -642,7 +650,28 @@ public class RacingEventServiceImpl implements RacingEventService, ClearStateTes
mongoObjectFactory.storeEvent(eventAndRequireStoreFlag.getA()); mongoObjectFactory.storeEvent(eventAndRequireStoreFlag.getA());
} }
} }
// TODO bug 2: decide whether to call getMongoObjectFactory().removeAllConnectivityParametersForRacesToRestore() or getDomainObjectFactory().loadConnectivityParametersForRacesToRestore() to restore last set of tracked races if (restoreTrackedRaces) {
restoreTrackedRaces();
} else {
getMongoObjectFactory().removeAllConnectivityParametersForRacesToRestore();
}
}
private void restoreTrackedRaces() {
final ScheduledExecutorService backgroundExecutor = ThreadPoolUtil.INSTANCE.getDefaultBackgroundTaskThreadPoolExecutor();
try {
getDomainObjectFactory().loadConnectivityParametersForRacesToRestore(params -> {
backgroundExecutor.execute(()->{
try {
addRace(/* addToRegatta==null means "default regatta" */ null, params, RaceTracker.TIMEOUT_FOR_RECEIVING_RACE_DEFINITION_IN_MILLISECONDS);
} catch (Exception e) {
logger.log(Level.SEVERE, "Exception trying to restore race"+params, e);
}
});
});
} catch (MalformedURLException | URISyntaxException e) {
logger.log(Level.SEVERE, "Exception trying to obtain connectivity parameters for restoring tracked races", e);
}
} }
@Override @Override
@@ -22,6 +22,10 @@ import java.util.Set;
public interface TypeBasedServiceFinder<ServiceType> { public interface TypeBasedServiceFinder<ServiceType> {
public static final String TYPE = "type"; public static final String TYPE = "type";
public interface Callback<ServiceType> {
void withService(ServiceType service);
}
/** /**
* Find a service that implements the <ServiceType> interface for the specified {@code type} of object (e.g. type of * Find a service that implements the <ServiceType> interface for the specified {@code type} of object (e.g. type of
* a {@link GPSFix}). * a {@link GPSFix}).
@@ -33,6 +37,16 @@ public interface TypeBasedServiceFinder<ServiceType> {
*/ */
ServiceType findService(String type) throws NoCorrespondingServiceRegisteredException; ServiceType findService(String type) throws NoCorrespondingServiceRegisteredException;
/**
* Similar to {@link #findService(String)}; when the service for {@code type} is already available,
* the {@code callback} is immediately {@link Callback#withService(Object) invoked} with the service
* found. If the service is not found, instead of throwing a {@link NoCorrespondingServiceRegisteredException},
* the {@code callback} is recorded by this finder; when at a later point in time a service with {@code type}
* becomes available, all callbacks recorded this way will be {@link Callback#withService(Object) invoked}
* with the service that became available.
*/
void applyServiceWhenAvailable(String type, Callback<ServiceType> callback);
Set<ServiceType> findAllServices(); Set<ServiceType> findAllServices();
/** /**
@@ -40,6 +40,14 @@ TypeBasedServiceFinder<ServiceType> {
throw new NoCorrespondingServiceRegisteredException("Only one service registered", type, service.getClass().getSimpleName()); throw new NoCorrespondingServiceRegisteredException("Only one service registered", type, service.getClass().getSimpleName());
} }
@Override
public void applyServiceWhenAvailable(String type, Callback<ServiceType> callback) {
final ServiceType service = findService(type);
if (service != null) {
callback.withService(service);
}
}
@Override @Override
public void setFallbackService(ServiceType fallback) { public void setFallbackService(ServiceType fallback) {
this.fallback = fallback; this.fallback = fallback;
@@ -4,6 +4,8 @@ import java.util.HashMap;
import java.util.HashSet; import java.util.HashSet;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.osgi.framework.BundleContext; import org.osgi.framework.BundleContext;
import org.osgi.framework.ServiceReference; import org.osgi.framework.ServiceReference;
@@ -12,6 +14,7 @@ import org.osgi.util.tracker.ServiceTrackerCustomizer;
import com.sap.sse.common.NoCorrespondingServiceRegisteredException; import com.sap.sse.common.NoCorrespondingServiceRegisteredException;
import com.sap.sse.common.TypeBasedServiceFinder; import com.sap.sse.common.TypeBasedServiceFinder;
import com.sap.sse.common.Util;
/** /**
* Caches OSGI services of a certain type, based on their {@link TypeBasedServiceFinder#TYPE} * Caches OSGI services of a certain type, based on their {@link TypeBasedServiceFinder#TYPE}
@@ -30,18 +33,22 @@ import com.sap.sse.common.TypeBasedServiceFinder;
*/ */
public class CachedOsgiTypeBasedServiceFinder<ServiceT> implements ServiceTrackerCustomizer<ServiceT, ServiceT>, public class CachedOsgiTypeBasedServiceFinder<ServiceT> implements ServiceTrackerCustomizer<ServiceT, ServiceT>,
TypeBasedServiceFinder<ServiceT> { TypeBasedServiceFinder<ServiceT> {
private static final Logger logger = Logger.getLogger(CachedOsgiTypeBasedServiceFinder.class.getName());
private final Map<String, ServiceT> services = new HashMap<>(); private final Map<String, ServiceT> services = new HashMap<>();
private final BundleContext context; private final BundleContext context;
private Class<ServiceT> serviceType; private final Class<ServiceT> serviceType;
private ServiceT fallback; private ServiceT fallback;
private final Map<String, Set<Callback<ServiceT>>> callbacks;
public CachedOsgiTypeBasedServiceFinder(Class<ServiceT> serviceType, BundleContext context) { public CachedOsgiTypeBasedServiceFinder(Class<ServiceT> serviceType, BundleContext context) {
this.serviceType = serviceType; this.serviceType = serviceType;
this.context = context; this.context = context;
this.callbacks = new HashMap<>();
} }
@Override @Override
public ServiceT findService(String type) { public ServiceT findService(String type) {
synchronized (services) {
ServiceT service = services.get(type); ServiceT service = services.get(type);
if (service == null) { if (service == null) {
if (fallback != null) { if (fallback != null) {
@@ -52,12 +59,39 @@ public class CachedOsgiTypeBasedServiceFinder<ServiceT> implements ServiceTracke
} }
return service; return service;
} }
}
@Override
public void applyServiceWhenAvailable(String type, Callback<ServiceT> callback) {
synchronized (services) {
ServiceT service = services.get(type);
if (service != null) {
callback.withService(service);
} else {
Util.addToValueSet(callbacks, type, callback);
}
}
}
@Override @Override
public ServiceT addingService(ServiceReference<ServiceT> reference) { public ServiceT addingService(ServiceReference<ServiceT> reference) {
String type = (String) reference.getProperty(TypeBasedServiceFinder.TYPE); String type = (String) reference.getProperty(TypeBasedServiceFinder.TYPE);
ServiceT service = context.getService(reference); ServiceT service = context.getService(reference);
Set<Callback<ServiceT>> callbacksToNotify;
synchronized (services) {
services.put(type, service); services.put(type, service);
callbacksToNotify = callbacks.remove(type);
}
if (callbacksToNotify != null) {
callbacksToNotify.forEach(c -> {
try {
c.withService(service);
} catch (Exception e) {
logger.log(Level.SEVERE,
"Exception trying to inform " + c + " about the availability of service " + service,e);
}
});
}
return service; return service;
} }
@@ -69,8 +103,10 @@ public class CachedOsgiTypeBasedServiceFinder<ServiceT> implements ServiceTracke
@Override @Override
public void removedService(ServiceReference<ServiceT> reference, ServiceT service) { public void removedService(ServiceReference<ServiceT> reference, ServiceT service) {
String type = (String) reference.getProperty(TypeBasedServiceFinder.TYPE); String type = (String) reference.getProperty(TypeBasedServiceFinder.TYPE);
synchronized (services) {
services.remove(type); services.remove(type);
} }
}
@Override @Override
public void setFallbackService(ServiceT fallback) { public void setFallbackService(ServiceT fallback) {
@@ -79,6 +115,8 @@ public class CachedOsgiTypeBasedServiceFinder<ServiceT> implements ServiceTracke
@Override @Override
public Set<ServiceT> findAllServices() { public Set<ServiceT> findAllServices() {
synchronized (services) {
return new HashSet<ServiceT>(services.values()); return new HashSet<ServiceT>(services.values());
} }
} }
}
@@ -38,18 +38,14 @@ public class CachedOsgiTypeBasedServiceFinderFactory implements TypeBasedService
@Override @Override
public <ServiceT> TypeBasedServiceFinder<ServiceT> createServiceFinder(Class<ServiceT> clazz) { public <ServiceT> TypeBasedServiceFinder<ServiceT> createServiceFinder(Class<ServiceT> clazz) {
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
CachedOsgiTypeBasedServiceFinder<ServiceT> finder = (CachedOsgiTypeBasedServiceFinder<ServiceT>) serviceFinders CachedOsgiTypeBasedServiceFinder<ServiceT> finder = (CachedOsgiTypeBasedServiceFinder<ServiceT>) serviceFinders.get(clazz);
.get(clazz);
if (finder == null) { if (finder == null) {
finder = new CachedOsgiTypeBasedServiceFinder<>(clazz, context); finder = new CachedOsgiTypeBasedServiceFinder<>(clazz, context);
ServiceTracker<ServiceT, ServiceT> tracker = new ServiceTracker<ServiceT, ServiceT>(context, clazz, finder); ServiceTracker<ServiceT, ServiceT> tracker = new ServiceTracker<ServiceT, ServiceT>(context, clazz, finder);
serviceFinders.put(clazz, finder); serviceFinders.put(clazz, finder);
serviceTrackers.add(tracker); serviceTrackers.add(tracker);
tracker.open(); tracker.open();
} }
return finder; return finder;
} }