Merge remote-tracking branch 'server/bug4006'

This commit is contained in:
Axel Uhl committed 2020-03-17 17:40:19 +01:00
commit eec641bb78
52 files changed
+574 -303

No files matched your search

@@ -23,7 +23,8 @@ Require-Bundle: com.sap.sailing.domain,
com.sap.sse.gwt.adminconsole,
org.apache.commons.math;bundle-version="2.1.0",
com.sap.sse.security.ui,
com.sap.sse
com.sap.sse,
com.sap.sse.replication.interfaces
Bundle-ActivationPolicy: lazy
Import-Package: com.sap.sse.security.shared.dto,
javax.servlet;version="3.1.0",
@@ -15,31 +15,44 @@ import com.sap.sse.gwt.dispatch.client.transport.gwtrpc.RequestWrapper;
import com.sap.sse.gwt.dispatch.servlets.AbstractDispatchServlet;
import com.sap.sse.gwt.dispatch.shared.commands.Action;
import com.sap.sse.gwt.dispatch.shared.commands.Result;
import com.sap.sse.replication.FullyInitializedReplicableTracker;
import com.sap.sse.replication.ReplicationService;
import com.sap.sse.util.ServiceTrackerFactory;
public class DashboardDispatchServlet extends AbstractDispatchServlet<DashboardDispatchContext> {
private static final long serialVersionUID = -245230476512348999L;
private final ServiceTracker<RacingEventService, RacingEventService> racingEventServiceTracker;
private final FullyInitializedReplicableTracker<RacingEventService> racingEventServiceTracker;
private final PolarDataService polarDataService;
private final DashboardLiveRaceProvider dashboardLiveRaceProvider;
private final MovingAveragesCache movingAveragesCache;
public DashboardDispatchServlet() {
final BundleContext context = Activator.getDefault();
racingEventServiceTracker = ServiceTrackerFactory.createAndOpen(context, RacingEventService.class);
final ServiceTracker<ReplicationService, ReplicationService> replicationServiceTracker =
ServiceTrackerFactory.createAndOpen(context, ReplicationService.class);
racingEventServiceTracker = new FullyInitializedReplicableTracker<>(context, RacingEventService.class,
/* customizer */ null, replicationServiceTracker);
racingEventServiceTracker.open();
polarDataService = getPolarDataService();
dashboardLiveRaceProvider = new DashboardLiveRaceProvider(racingEventServiceTracker.getService());
try {
dashboardLiveRaceProvider = new DashboardLiveRaceProvider(racingEventServiceTracker.getInitializedService(0));
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
movingAveragesCache = new MovingAveragesCache();
}
@Override
protected <R extends Result, A extends Action<R, DashboardDispatchContext>> DashboardDispatchContext createDispatchContextFor(
RequestWrapper<R, A, DashboardDispatchContext> request) {
return new DashboardDispatchContextImpl(request.getCurrentClientTime(),
racingEventServiceTracker.getService(),
polarDataService, dashboardLiveRaceProvider, movingAveragesCache, request.getClientLocaleName(),
getThreadLocalRequest());
try {
return new DashboardDispatchContextImpl(request.getCurrentClientTime(), racingEventServiceTracker.getInitializedService(0),
polarDataService, dashboardLiveRaceProvider, movingAveragesCache, request.getClientLocaleName(),
getThreadLocalRequest());
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
private PolarDataService getPolarDataService() {
@@ -25,7 +25,8 @@ Require-Bundle: org.json.simple;bundle-version="1.1.0",
com.sap.sse.security.common,
com.sap.sse.security.interface,
org.apache.shiro.core,
org.apache.shiro.web
org.apache.shiro.web,
com.sap.sse.replication
Import-Package: com.sap.sse.security.shared,
javax.ws.rs;version="1.1.1",
javax.ws.rs.core;version="1.1.1",
@@ -10,6 +10,8 @@ import org.osgi.util.tracker.ServiceTracker;
import com.sap.sailing.domain.igtimiadapter.Client;
import com.sap.sailing.domain.igtimiadapter.IgtimiConnectionFactory;
import com.sap.sse.replication.FullyInitializedReplicableTracker;
import com.sap.sse.replication.ReplicationService;
import com.sap.sse.security.SecurityService;
import com.sap.sse.util.ServiceTrackerFactory;
@@ -26,7 +28,7 @@ import com.sap.sse.util.ServiceTrackerFactory;
public class Activator implements BundleActivator {
private static Activator INSTANCE;
private ServiceTracker<IgtimiConnectionFactory, IgtimiConnectionFactory> igtimiConnectionFactoryTracker;
private ServiceTracker<SecurityService, SecurityService> securityServiceTracker;
private FullyInitializedReplicableTracker<SecurityService> securityServiceTracker;
public Activator() throws ClientProtocolException, IllegalStateException, IOException, ParseException {
}
@@ -34,11 +36,11 @@ public class Activator implements BundleActivator {
@Override
public void start(final BundleContext context) throws Exception {
INSTANCE = this;
igtimiConnectionFactoryTracker = ServiceTrackerFactory
.createAndOpen(context, IgtimiConnectionFactory.class);
securityServiceTracker = ServiceTrackerFactory.createAndOpen(context, SecurityService.class);
securityServiceTracker = new FullyInitializedReplicableTracker<>(context, SecurityService.class,
/* customizer */ null, ServiceTrackerFactory.createAndOpen(context, ReplicationService.class));
securityServiceTracker.open();
}
public static Activator getInstance() throws ClientProtocolException, IllegalStateException, IOException, ParseException {
@@ -53,7 +55,11 @@ public class Activator implements BundleActivator {
}
public SecurityService getSecurityService() {
return securityServiceTracker.getService();
try {
return securityServiceTracker.getInitializedService(0);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
@Override
@@ -13,7 +13,6 @@ import org.apache.http.client.ClientProtocolException;
import org.json.simple.parser.ParseException;
import org.osgi.framework.BundleActivator;
import org.osgi.framework.BundleContext;
import org.osgi.util.tracker.ServiceTracker;
import com.sap.sailing.domain.common.security.SecuredDomainType;
import com.sap.sailing.domain.igtimiadapter.Account;
@@ -23,6 +22,8 @@ import com.sap.sailing.domain.igtimiadapter.persistence.DomainObjectFactory;
import com.sap.sailing.domain.igtimiadapter.persistence.MongoObjectFactory;
import com.sap.sailing.domain.igtimiadapter.persistence.PersistenceFactory;
import com.sap.sailing.domain.tracking.WindTrackerFactory;
import com.sap.sse.replication.FullyInitializedReplicableTracker;
import com.sap.sse.replication.ReplicationService;
import com.sap.sse.security.SecurityService;
import com.sap.sse.util.ClearStateTestSupport;
import com.sap.sse.util.ServiceTrackerFactory;
@@ -55,7 +56,7 @@ public class Activator implements BundleActivator {
private static final String CLIENT_REDIRECT_PORT_PROPERTY_NAME = "igtimi.client.redirect.port";
private final Future<IgtimiConnectionFactoryImpl> connectionFactory;
private final Future<IgtimiWindTrackerFactory> windTrackerFactory;
private ServiceTracker<SecurityService, SecurityService> securityServiceServiceTracker;
private FullyInitializedReplicableTracker<SecurityService> securityServiceServiceTracker;
private final ExecutorService executor = Executors.newSingleThreadExecutor(new ThreadFactoryWithPriority(Thread.NORM_PRIORITY, /* daemon */ true));
private SecurityService securityServiceTest;
@@ -106,10 +107,12 @@ public class Activator implements BundleActivator {
}
}
});
securityServiceServiceTracker = ServiceTrackerFactory.createAndOpen(context, SecurityService.class);
securityServiceServiceTracker = new FullyInitializedReplicableTracker<>(context, SecurityService.class,
/* customizer */ null, ServiceTrackerFactory.createAndOpen(context, ReplicationService.class));
securityServiceServiceTracker.open();
new Thread(() -> {
try {
final SecurityService securityService = securityServiceServiceTracker.waitForService(0);
final SecurityService securityService = securityServiceServiceTracker.getInitializedService(0);
IgtimiConnectionFactoryImpl igtimiConnectionFactory = connectionFactory.get();
for (Account account : igtimiConnectionFactory.getAllAccounts()) {
securityService.migrateOwnership(account);
@@ -144,7 +147,11 @@ public class Activator implements BundleActivator {
}
public SecurityService getSecurityService() {
return securityServiceTest == null ? securityServiceServiceTracker.getService() : securityServiceTest;
try {
return securityServiceTest == null ? securityServiceServiceTracker.getInitializedService(0) : securityServiceTest;
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
public IgtimiWindTrackerFactory getWindTrackerFactory() {
@@ -36,14 +36,16 @@ import com.sap.sailing.server.interfaces.RacingEventService;
import com.sap.sailing.shared.persistence.device.DeviceIdentifierMongoHandler;
import com.sap.sse.MasterDataImportClassLoaderService;
import com.sap.sse.common.TypeBasedServiceFinder;
import com.sap.sse.replication.FullyInitializedReplicableTracker;
import com.sap.sse.replication.Replicable;
import com.sap.sse.replication.ReplicationService;
import com.sap.sse.util.ServiceTrackerFactory;
public class Activator implements BundleActivator {
private static final Logger logger = Logger.getLogger(Activator.class.getName());
private static BundleContext context;
private ServiceTracker<RacingEventService, RacingEventService> racingEventServiceTracker;
private FullyInitializedReplicableTracker<RacingEventService> racingEventServiceTracker;
private ServiceTracker<SensorFixMapper<?, ?, ?>, SensorFixMapper<?, ?, ?>> sensorFixMapperTracker;
public static BundleContext getContext() {
@@ -84,13 +86,18 @@ public class Activator implements BundleActivator {
registrations.add(context.registerService(SensorFixMapper.class, new BravoExtendedDataFixMapper(), null));
registrations.add(context.registerService(SensorFixMapper.class, new ExpeditionExtendedDataFixMapper(), null));
sensorFixMapperTracker = createSensorFixMapperServiceTracker(context);
racingEventServiceTracker = ServiceTrackerFactory.createAndOpen(context, RacingEventService.class);
racingEventServiceTracker = new FullyInitializedReplicableTracker<>(context, RacingEventService.class,
/* customizer */ null, ServiceTrackerFactory.createAndOpen(context, ReplicationService.class));
racingEventServiceTracker.open();
RegattaLogFixTrackerRegattaListener regattaLogSensorDataTrackerTrackedRegattaListener = new RegattaLogFixTrackerRegattaListener(
racingEventServiceTracker, new SensorFixMapperFactoryImpl(sensorFixMapperTracker));
registrations.add(context.registerService(TrackedRegattaListener.class,
regattaLogSensorDataTrackerTrackedRegattaListener, null));
final Dictionary<String, String> replicableServiceProperties = new Hashtable<>();
replicableServiceProperties.put(Replicable.OSGi_Service_Registry_ID_Property_Name,
regattaLogSensorDataTrackerTrackedRegattaListener.getId().toString());
registrations.add(context.registerService(Replicable.class,
regattaLogSensorDataTrackerTrackedRegattaListener, null));
regattaLogSensorDataTrackerTrackedRegattaListener, replicableServiceProperties));
new Thread(()->{
try {
registrations.add(context.registerService(RaceTrackingConnectivityParametersHandler.class,
@@ -12,8 +12,6 @@ import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.logging.Logger;
import org.osgi.util.tracker.ServiceTracker;
import com.sap.sailing.domain.common.RegattaAndRaceIdentifier;
import com.sap.sailing.domain.racelog.tracking.SensorFixStore;
import com.sap.sailing.domain.racelogsensortracking.SensorFixMapperFactory;
@@ -24,14 +22,15 @@ import com.sap.sailing.domain.tracking.RaceTracker;
import com.sap.sailing.domain.tracking.TrackedRegatta;
import com.sap.sailing.domain.tracking.TrackedRegattaListener;
import com.sap.sailing.server.interfaces.RacingEventService;
import com.sap.sse.replication.FullyInitializedReplicableTracker;
import com.sap.sse.replication.OperationExecutionListener;
import com.sap.sse.replication.OperationWithResult;
import com.sap.sse.replication.OperationWithResultWithIdWrapper;
import com.sap.sse.replication.OperationsToMasterSender;
import com.sap.sse.replication.OperationsToMasterSendingQueue;
import com.sap.sse.replication.ReplicableWithObjectInputStream;
import com.sap.sse.replication.ReplicationMasterDescriptor;
import com.sap.sse.replication.ReplicationService;
import com.sap.sse.replication.OperationsToMasterSendingQueue;
/**
* This is the main entry point of the {@link SensorFixStore} based fix tracking.
@@ -51,7 +50,7 @@ public class RegattaLogFixTrackerRegattaListener extends AbstractTrackedRegattaA
private static final Logger log = Logger.getLogger(RegattaLogFixTrackerRegattaListener.class.getName());
private final Map<RegattaAndRaceIdentifier, RaceLogFixTrackerManager> dataTrackers = new ConcurrentHashMap<>();
private final ServiceTracker<RacingEventService, RacingEventService> racingEventServiceTracker;
private final FullyInitializedReplicableTracker<RacingEventService> racingEventServiceTracker;
private final SensorFixMapperFactory sensorFixMapperFactory;
/**
@@ -63,10 +62,11 @@ public class RegattaLogFixTrackerRegattaListener extends AbstractTrackedRegattaA
private OperationsToMasterSendingQueue unsentOperationsToMasterSender;
public RegattaLogFixTrackerRegattaListener(
ServiceTracker<RacingEventService, RacingEventService> racingEventServiceTracker,
FullyInitializedReplicableTracker<RacingEventService> racingEventServiceTracker,
SensorFixMapperFactory sensorFixMapperFactory) {
this.racingEventServiceTracker = racingEventServiceTracker;
this.sensorFixMapperFactory = sensorFixMapperFactory;
this.currentlyFillingFromInitialLoad = false;
}
@Override
@@ -81,30 +81,38 @@ public class RegattaLogFixTrackerRegattaListener extends AbstractTrackedRegattaA
@Override
protected void onRaceAdded(RegattaAndRaceIdentifier raceIdentifier, DynamicTrackedRegatta trackedRegatta,
DynamicTrackedRace trackedRace) {
racingEventServiceTracker.getService().getRaceTrackerByRegattaAndRaceIdentifier(raceIdentifier, (raceTracker) -> {
if (raceTracker != null) {
boolean added = raceTracker.add(new RaceTracker.Listener() {
@Override
public void onTrackerWillStop(boolean preemptive, boolean willBeRemoved) {
raceTracker.remove(this);
removeRaceLogSensorDataTracker(raceIdentifier, preemptive, willBeRemoved);
try {
racingEventServiceTracker.getInitializedService(0).getRaceTrackerByRegattaAndRaceIdentifier(raceIdentifier, (raceTracker) -> {
try {
if (raceTracker != null) {
boolean added = raceTracker.add(new RaceTracker.Listener() {
@Override
public void onTrackerWillStop(boolean preemptive, boolean willBeRemoved) {
raceTracker.remove(this);
removeRaceLogSensorDataTracker(raceIdentifier, preemptive, willBeRemoved);
}
});
// if !added, the RaceTracker is already stopped, so we are not allowed to start fix tracking
if (added) {
RaceLogFixTrackerManager trackerManager = new RaceLogFixTrackerManager(
(DynamicTrackedRace) trackedRace, racingEventServiceTracker.getInitializedService(0).getSensorFixStore(),
sensorFixMapperFactory);
RaceLogFixTrackerManager oldInstance = null;
synchronized (this) {
oldInstance = dataTrackers.put(raceIdentifier, trackerManager);
}
if (oldInstance != null) {
oldInstance.stop(/* preemptive */ true, /* willBeRemoved */ false);
}
}
}
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
});
// if !added, the RaceTracker is already stopped, so we are not allowed to start fix tracking
if (added) {
RaceLogFixTrackerManager trackerManager = new RaceLogFixTrackerManager(
(DynamicTrackedRace) trackedRace, racingEventServiceTracker.getService().getSensorFixStore(),
sensorFixMapperFactory);
RaceLogFixTrackerManager oldInstance = null;
synchronized (this) {
oldInstance = dataTrackers.put(raceIdentifier, trackerManager);
}
if (oldInstance != null) {
oldInstance.stop(/* preemptive */ true, /* willBeRemoved */ false);
}
}
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
});
}
@Override
@@ -130,7 +138,7 @@ public class RegattaLogFixTrackerRegattaListener extends AbstractTrackedRegattaA
// Replication related methods and fields
private final ConcurrentHashMap<OperationExecutionListener<RegattaLogFixTrackerRegattaListener>, OperationExecutionListener<RegattaLogFixTrackerRegattaListener>> operationExecutionListeners = new ConcurrentHashMap<>();
private ThreadLocal<Boolean> currentlyFillingFromInitialLoad = ThreadLocal.withInitial(() -> false);
private volatile boolean currentlyFillingFromInitialLoad;
private ThreadLocal<Boolean> currentlyApplyingOperationReceivedFromMaster = ThreadLocal.withInitial(() -> false);
private final Set<OperationWithResultWithIdWrapper<RegattaLogFixTrackerRegattaListener, ?>> operationsSentToMasterForReplication = new HashSet<>();
private ReplicationMasterDescriptor master;
@@ -174,12 +182,12 @@ public class RegattaLogFixTrackerRegattaListener extends AbstractTrackedRegattaA
@Override
public boolean isCurrentlyFillingFromInitialLoad() {
return currentlyFillingFromInitialLoad.get();
return currentlyFillingFromInitialLoad;
}
@Override
public void setCurrentlyFillingFromInitialLoad(boolean currentlyFillingFromInitialLoad) {
this.currentlyFillingFromInitialLoad.set(currentlyFillingFromInitialLoad);
this.currentlyFillingFromInitialLoad = currentlyFillingFromInitialLoad;
}
@Override
@@ -14,7 +14,8 @@ Require-Bundle: com.sap.sailing.domain.swisstimingadapter,
com.sap.sailing.domain.persistence,
com.sap.sse,
org.mongodb.mongo-java-driver;bundle-version="3.6.4",
com.sap.sse.security.common
com.sap.sse.security.common,
com.sap.sse.replication.interfaces
Export-Package: com.sap.sailing.domain.swisstimingadapter.persistence,
com.sap.sailing.domain.swisstimingadapter.persistence.impl;x-friends:="com.sap.sailing.domain.swisstimingadapter.test,com.sap.sailing.mongodb.test"
Import-Package: com.sap.sse.security,
@@ -22,6 +22,8 @@ import com.sap.sailing.domain.swisstimingadapter.persistence.SwissTimingAdapterP
import com.sap.sailing.domain.tracking.RaceTrackingConnectivityParametersHandler;
import com.sap.sse.common.TypeBasedServiceFinder;
import com.sap.sse.mongodb.MongoDBService;
import com.sap.sse.replication.FullyInitializedReplicableTracker;
import com.sap.sse.replication.ReplicationService;
import com.sap.sse.security.SecurityService;
import com.sap.sse.util.ServiceTrackerFactory;
@@ -34,8 +36,9 @@ public class Activator implements BundleActivator {
MongoDBService.INSTANCE.registerExclusively(CollectionNames.class, name.name());
}
new Thread(() -> {
final ServiceTracker<SecurityService, SecurityService> securityServiceServiceTracker = ServiceTrackerFactory
.createAndOpen(context, SecurityService.class);
final FullyInitializedReplicableTracker<SecurityService> securityServiceServiceTracker = new FullyInitializedReplicableTracker<>(context, SecurityService.class,
/* customizer */ null, ServiceTrackerFactory.createAndOpen(context, ReplicationService.class));
securityServiceServiceTracker.open();
final ServiceTracker<MongoObjectFactory, MongoObjectFactory> mongoObjectFactoryServiceTracker = ServiceTrackerFactory.createAndOpen(context, MongoObjectFactory.class);
final ServiceTracker<DomainObjectFactory, DomainObjectFactory> domainObjectFactoryServiceTracker = ServiceTrackerFactory.createAndOpen(context, DomainObjectFactory.class);
final ServiceTracker<SwissTimingAdapterFactory, SwissTimingAdapterFactory> swissTimingAdapterFactoryServiceTracker = ServiceTrackerFactory.createAndOpen(context, SwissTimingAdapterFactory.class);
@@ -43,7 +46,7 @@ public class Activator implements BundleActivator {
final MongoObjectFactory mongoObjectFactory = mongoObjectFactoryServiceTracker.waitForService(0);
final DomainObjectFactory domainObjectFactory = domainObjectFactoryServiceTracker.waitForService(0);
final SwissTimingAdapterFactory swissTimingAdapterFactory = swissTimingAdapterFactoryServiceTracker.waitForService(0);
final SecurityService securityService = securityServiceServiceTracker.waitForService(0);
final SecurityService securityService = securityServiceServiceTracker.getInitializedService(0);
final Dictionary<String, Object> properties = new Hashtable<String, Object>();
final com.sap.sailing.domain.swisstimingadapter.DomainFactory domainFactory = swissTimingAdapterFactory.getOrCreateSwissTimingAdapter(
domainObjectFactory.getBaseDomainFactory()).getSwissTimingDomainFactory();
@@ -53,21 +56,17 @@ public class Activator implements BundleActivator {
domainFactory);
properties.put(TypeBasedServiceFinder.TYPE, SwissTimingTrackingConnectivityParameters.TYPE);
context.registerService(RaceTrackingConnectivityParametersHandler.class, paramsHandler, properties);
for (SwissTimingArchiveConfiguration swissTimingArchive : SwissTimingAdapterPersistence.INSTANCE
.getSwissTimingArchiveConfigurations()) {
securityService.migrateOwnership(swissTimingArchive);
}
for (SwissTimingConfiguration swissTiming : SwissTimingAdapterPersistence.INSTANCE
.getSwissTimingConfigurations()) {
securityService.migrateOwnership(swissTiming);
}
// we do not necessarily have swisstiming configs, so ensure that migration is marked as done
securityService.assumeOwnershipMigrated(SecuredDomainType.SWISS_TIMING_ACCOUNT.getName());
securityService.assumeOwnershipMigrated(SecuredDomainType.SWISS_TIMING_ARCHIVE_ACCOUNT.getName());
} catch (Exception e) {
logger.log(Level.SEVERE, "Exception trying to register SwissTiming RaceTrackingConnectivityParametersHandler implementation", e);
}
@@ -14,7 +14,6 @@ import java.util.function.Consumer;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.Timeout;
import org.osgi.util.tracker.ServiceTracker;
import com.sap.sailing.domain.base.Course;
import com.sap.sailing.domain.base.RaceDefinition;
@@ -35,6 +34,7 @@ import com.sap.sailing.domain.tracking.impl.DynamicTrackedRaceImpl;
import com.sap.sailing.domain.tracking.impl.DynamicTrackedRegattaImpl;
import com.sap.sailing.server.impl.RacingEventServiceImpl;
import com.sap.sailing.server.interfaces.RacingEventService;
import com.sap.sse.replication.FullyInitializedReplicableTracker;
import com.sap.sse.util.ThreadLocalTransporter;
public class TestDeadlockInRegattaListener {
@@ -46,8 +46,8 @@ public class TestDeadlockInRegattaListener {
CyclicBarrier latch = new CyclicBarrier(2);
CyclicBarrier monitorOnRegattaListenerLatch = new CyclicBarrier(2);
@SuppressWarnings("unchecked")
ServiceTracker<RacingEventService, RacingEventService> racingEventServiceTracker =
(ServiceTracker<RacingEventService, RacingEventService>) mock(ServiceTracker.class);
FullyInitializedReplicableTracker<RacingEventService> racingEventServiceTracker =
(FullyInitializedReplicableTracker<RacingEventService>) mock(FullyInitializedReplicableTracker.class);
final String regattaName = "Test Regatta";
final RegattaImpl regatta = new RegattaImpl(
/* raceLogStore */ null, EmptyRegattaLogStore.INSTANCE, regattaName,
@@ -102,7 +102,7 @@ public class TestDeadlockInRegattaListener {
}
}
};
when(racingEventServiceTracker.getService()).thenReturn(racingEventService);
when(racingEventServiceTracker.getInitializedService(0)).thenReturn(racingEventService);
RegattaLogFixTrackerRegattaListener listener = new RegattaLogFixTrackerRegattaListener(
racingEventServiceTracker, null);
@@ -14,7 +14,8 @@ Require-Bundle: com.sap.sse.mongodb,
com.sap.sailing.domain.persistence,
com.sap.sse,
org.mongodb.mongo-java-driver;bundle-version="3.6.4",
com.sap.sse.security.common
com.sap.sse.security.common,
com.sap.sse.replication.interfaces
Export-Package: com.sap.sailing.domain.tractracadapter.persistence,
com.sap.sailing.domain.tractracadapter.persistence.impl;x-friends:="com.sap.sailing.mongodb.test"
Import-Package: com.sap.sse.security,
@@ -23,18 +23,20 @@ import com.sap.sailing.domain.tractracadapter.TracTracConfiguration;
import com.sap.sailing.domain.tractracadapter.impl.RaceTrackingConnectivityParametersImpl;
import com.sap.sse.common.TypeBasedServiceFinder;
import com.sap.sse.mongodb.MongoDBService;
import com.sap.sse.replication.FullyInitializedReplicableTracker;
import com.sap.sse.replication.ReplicationService;
import com.sap.sse.security.SecurityService;
import com.sap.sse.util.ClearStateTestSupport;
import com.sap.sse.util.ServiceTrackerFactory;
public class Activator implements BundleActivator {
private static final Logger logger = Logger.getLogger(Activator.class.getName());
/**
* Requires a base {@link DomainFactory} as well as a {@link RaceLogStore} and a {@link RegattaLogStore}. In order
* to instantiate those two stores, the method requires a {@link MongoObjectFactory} and a {@link DomainObjectFactory}
* which are waited for as services from the OSGi registry. This happens in a separate thread that the {@link #start(BundleContext)}
* method launches.
* to instantiate those two stores, the method requires a {@link MongoObjectFactory} and a
* {@link DomainObjectFactory} which are waited for as services from the OSGi registry. This happens in a separate
* thread that the {@link #start(BundleContext)} method launches.
*/
@Override
public void start(BundleContext context) throws Exception {
@@ -42,22 +44,29 @@ public class Activator implements BundleActivator {
MongoDBService.INSTANCE.registerExclusively(CollectionNames.class, name.name());
}
new Thread(() -> {
final ServiceTracker<MongoObjectFactory, MongoObjectFactory> mongoObjectFactoryServiceTracker = ServiceTrackerFactory.createAndOpen(context, MongoObjectFactory.class);
final ServiceTracker<DomainObjectFactory, DomainObjectFactory> domainObjectFactoryServiceTracker = ServiceTrackerFactory.createAndOpen(context, DomainObjectFactory.class);
final ServiceTracker<SecurityService, SecurityService> securityServiceServiceTracker = ServiceTrackerFactory
.createAndOpen(context, SecurityService.class);
final ServiceTracker<TracTracAdapterFactory, TracTracAdapterFactory> tractracAdapterFactoryTracker = ServiceTrackerFactory.createAndOpen(context, TracTracAdapterFactory.class);
final ServiceTracker<MongoObjectFactory, MongoObjectFactory> mongoObjectFactoryServiceTracker = ServiceTrackerFactory
.createAndOpen(context, MongoObjectFactory.class);
final ServiceTracker<DomainObjectFactory, DomainObjectFactory> domainObjectFactoryServiceTracker = ServiceTrackerFactory
.createAndOpen(context, DomainObjectFactory.class);
final FullyInitializedReplicableTracker<SecurityService> securityServiceServiceTracker = new FullyInitializedReplicableTracker<>(
context, SecurityService.class, /* customizer */ null,
ServiceTrackerFactory.createAndOpen(context, ReplicationService.class));
securityServiceServiceTracker.open();
final ServiceTracker<TracTracAdapterFactory, TracTracAdapterFactory> tractracAdapterFactoryTracker = ServiceTrackerFactory
.createAndOpen(context, TracTracAdapterFactory.class);
try {
final MongoObjectFactory mongoObjectFactory = mongoObjectFactoryServiceTracker.waitForService(0);
final DomainObjectFactory domainObjectFactory = domainObjectFactoryServiceTracker.waitForService(0);
final SecurityService securityService = securityServiceServiceTracker.waitForService(0);
final SecurityService securityService = securityServiceServiceTracker.getInitializedService(0);
final TracTracAdapterFactory tractracAdapterFactory = tractracAdapterFactoryTracker.waitForService(0);
final Dictionary<String, Object> properties = new Hashtable<String, Object>();
final com.sap.sailing.domain.tractracadapter.DomainFactory domainFactory = tractracAdapterFactory.getOrCreateTracTracAdapter(
domainObjectFactory.getBaseDomainFactory()).getTracTracDomainFactory();
final com.sap.sailing.domain.tractracadapter.DomainFactory domainFactory = tractracAdapterFactory
.getOrCreateTracTracAdapter(domainObjectFactory.getBaseDomainFactory())
.getTracTracDomainFactory();
final TracTracConnectivityParamsHandler paramsHandler = new TracTracConnectivityParamsHandler(
MongoRaceLogStoreFactory.INSTANCE.getMongoRaceLogStore(mongoObjectFactory, domainObjectFactory),
MongoRegattaLogStoreFactory.INSTANCE.getMongoRegattaLogStore(mongoObjectFactory, domainObjectFactory),
MongoRegattaLogStoreFactory.INSTANCE.getMongoRegattaLogStore(mongoObjectFactory,
domainObjectFactory),
domainFactory);
com.sap.sailing.domain.tractracadapter.persistence.DomainObjectFactory tractracDomainObjectFactory = com.sap.sailing.domain.tractracadapter.persistence.PersistenceFactory.INSTANCE
@@ -79,7 +88,9 @@ public class Activator implements BundleActivator {
}
}, null);
} catch (Exception e) {
logger.log(Level.SEVERE, "Exception trying to register TracTrac RaceTrackingConnectivityParametersHandler implementation", e);
logger.log(Level.SEVERE,
"Exception trying to register TracTrac RaceTrackingConnectivityParametersHandler implementation",
e);
}
}, getClass().getName() + " registering connectivity handler").start();
}
@@ -30,7 +30,6 @@ Export-Package: com.sap.sailing.domain.base,
com.sap.sailing.domain.regattalog,
com.sap.sailing.domain.regattalog.impl,
com.sap.sailing.domain.sharding,
com.sap.sailing.domain.sharedsailingdata,
com.sap.sailing.domain.trackfiles,
com.sap.sailing.domain.trackimport,
com.sap.sailing.domain.tracking,
@@ -12,7 +12,6 @@ import java.util.logging.Logger;
import org.osgi.framework.BundleActivator;
import org.osgi.framework.BundleContext;
import org.osgi.framework.ServiceRegistration;
import org.osgi.util.tracker.ServiceTracker;
import com.sap.sailing.domain.common.security.SecuredDomainType;
import com.sap.sailing.domain.racelogtracking.DeviceIdentifierStringSerializationHandler;
@@ -28,6 +27,8 @@ import com.sap.sailing.expeditionconnector.persistence.PersistenceFactory;
import com.sap.sailing.server.gateway.serialization.racelog.tracking.DeviceIdentifierJsonHandler;
import com.sap.sse.ServerInfo;
import com.sap.sse.common.TypeBasedServiceFinder;
import com.sap.sse.replication.FullyInitializedReplicableTracker;
import com.sap.sse.replication.ReplicationService;
import com.sap.sse.security.SecurityService;
import com.sap.sse.security.shared.QualifiedObjectIdentifier;
import com.sap.sse.security.shared.impl.WildcardPermissionEncoder;
@@ -91,10 +92,11 @@ public class Activator implements BundleActivator {
registrations.add(context.registerService(DeviceIdentifierStringSerializationHandler.class, new ExpeditionSensorStringSerializationHandler(), getDict(ExpeditionSensorDeviceIdentifier.TYPE)));
new Thread(() -> {
final ServiceTracker<SecurityService, SecurityService> securityServiceServiceTracker = ServiceTrackerFactory
.createAndOpen(context, SecurityService.class);
final FullyInitializedReplicableTracker<SecurityService> securityServiceServiceTracker = new FullyInitializedReplicableTracker<>(
context, SecurityService.class, /* customizer */ null, ServiceTrackerFactory.createAndOpen(context, ReplicationService.class));
securityServiceServiceTracker.open();
try {
final SecurityService securityService = securityServiceServiceTracker.waitForService(0);
final SecurityService securityService = securityServiceServiceTracker.getInitializedService(0);
final WildcardPermissionEncoder permissionEncoder = new WildcardPermissionEncoder();
for (ExpeditionDeviceConfiguration deviceConfiguration : expeditionTrackerFactory
.getDeviceConfigurations()) {
@@ -23,35 +23,47 @@ import com.sap.sse.gwt.dispatch.client.transport.gwtrpc.RequestWrapper;
import com.sap.sse.gwt.dispatch.servlets.AbstractDispatchServlet;
import com.sap.sse.gwt.dispatch.shared.commands.Action;
import com.sap.sse.gwt.dispatch.shared.commands.Result;
import com.sap.sse.replication.FullyInitializedReplicableTracker;
import com.sap.sse.replication.ReplicationService;
import com.sap.sse.security.SecurityService;
import com.sap.sse.util.ServiceTrackerFactory;
public class SailingDispatchServlet extends AbstractDispatchServlet<SailingDispatchContext> {
private static final long serialVersionUID = -245230476512348999L;
private final ServiceTracker<RacingEventService, RacingEventService> racingEventServiceTracker;
private final FullyInitializedReplicableTracker<RacingEventService> racingEventServiceTracker;
private final ServiceTracker<WindFinderTrackerFactory, WindFinderTrackerFactory> windFinderTrackerFactory;
private final ServiceTracker<EventNewsService, EventNewsService> eventNewsServiceTracker;
private final ServiceTracker<SecurityService, SecurityService> securityServiceTracker;
private final FullyInitializedReplicableTracker<SecurityService> securityServiceTracker;
private final ServiceTracker<TrackedRaceStatisticsCache, TrackedRaceStatisticsCache> trackedRaceStatisticsCacheTracker;
public SailingDispatchServlet() {
final BundleContext context = Activator.getDefault();
racingEventServiceTracker = ServiceTrackerFactory.createAndOpen(context, RacingEventService.class);
final ServiceTracker<ReplicationService, ReplicationService> replicationServiceTracker =
ServiceTrackerFactory.createAndOpen(context, ReplicationService.class);
racingEventServiceTracker = new FullyInitializedReplicableTracker<>(context, RacingEventService.class,
/* customizer */ null, replicationServiceTracker);
racingEventServiceTracker.open();
windFinderTrackerFactory = ServiceTrackerFactory.createAndOpen(context, WindFinderTrackerFactory.class);
eventNewsServiceTracker = ServiceTrackerFactory.createAndOpen(context, EventNewsService.class);
securityServiceTracker = ServiceTrackerFactory.createAndOpen(context, SecurityService.class);
securityServiceTracker = new FullyInitializedReplicableTracker<>(context, SecurityService.class,
/* customizer */ null, replicationServiceTracker);
securityServiceTracker.open();
trackedRaceStatisticsCacheTracker = ServiceTrackerFactory.createAndOpen(context, TrackedRaceStatisticsCache.class);
}
@Override
protected <R extends Result, A extends Action<R, SailingDispatchContext>> SailingDispatchContext createDispatchContextFor(
RequestWrapper<R, A, SailingDispatchContext> request) {
return new SailingDispatchContextImpl(request.getCurrentClientTime(), racingEventServiceTracker.getService(),
windFinderTrackerFactory.getService(),
eventNewsServiceTracker.getService(), securityServiceTracker.getService(),
trackedRaceStatisticsCacheTracker.getService(),
request.getClientLocaleName(), getThreadLocalRequest());
try {
return new SailingDispatchContextImpl(request.getCurrentClientTime(), racingEventServiceTracker.getInitializedService(0),
windFinderTrackerFactory.getService(),
eventNewsServiceTracker.getService(), securityServiceTracker.getInitializedService(0),
trackedRaceStatisticsCacheTracker.getService(),
request.getClientLocaleName(), getThreadLocalRequest());
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
@Override
@@ -1,12 +1,13 @@
package com.sap.sailing.gwt.server;
import org.osgi.framework.BundleContext;
import org.osgi.util.tracker.ServiceTracker;
import com.sap.sailing.gwt.ui.client.ServerConfigurationService;
import com.sap.sailing.gwt.ui.server.Activator;
import com.sap.sailing.server.interfaces.RacingEventService;
import com.sap.sse.gwt.server.ProxiedRemoteServiceServlet;
import com.sap.sse.replication.FullyInitializedReplicableTracker;
import com.sap.sse.replication.ReplicationService;
import com.sap.sse.util.ServiceTrackerFactory;
/**
@@ -15,15 +16,21 @@ import com.sap.sse.util.ServiceTrackerFactory;
public class ServerConfigurationServiceImpl extends ProxiedRemoteServiceServlet implements ServerConfigurationService {
private static final long serialVersionUID = 2571063542941630865L;
private final ServiceTracker<RacingEventService, RacingEventService> racingEventServiceTracker;
private final FullyInitializedReplicableTracker<RacingEventService> racingEventServiceTracker;
public ServerConfigurationServiceImpl() {
BundleContext context = Activator.getDefault();
racingEventServiceTracker = ServiceTrackerFactory.createAndOpen(context, RacingEventService.class);
racingEventServiceTracker = new FullyInitializedReplicableTracker<>(context, RacingEventService.class,
/* customizer */ null, ServiceTrackerFactory.createAndOpen(context, ReplicationService.class));
racingEventServiceTracker.open();
}
protected RacingEventService getService() {
return racingEventServiceTracker.getService();
try {
return racingEventServiceTracker.getInitializedService(0);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
@Override
@@ -49,6 +49,8 @@ import com.sap.sse.datamining.shared.impl.dto.StoredDataMiningQueryDTOImpl;
import com.sap.sse.datamining.ui.client.DataMiningService;
import com.sap.sse.gwt.server.ProxiedRemoteServiceServlet;
import com.sap.sse.i18n.ResourceBundleStringMessages;
import com.sap.sse.replication.FullyInitializedReplicableTracker;
import com.sap.sse.replication.ReplicationService;
import com.sap.sse.security.SecurityService;
import com.sap.sse.security.shared.impl.SecuredSecurityTypes.ServerActions;
import com.sap.sse.util.ServiceTrackerFactory;
@@ -58,14 +60,16 @@ public class DataMiningServiceImpl extends ProxiedRemoteServiceServlet implement
private final BundleContext context;
private final ServiceTracker<DataMiningServer, DataMiningServer> dataMiningServerTracker;
private final ServiceTracker<SecurityService, SecurityService> securityServiceTracker;
private final FullyInitializedReplicableTracker<SecurityService> securityServiceTracker;
private final StoredDataMiningQueryPersister storedDataMiningQueryPersistor;
private final DataMiningDTOFactory dtoFactory;
public DataMiningServiceImpl() {
context = Activator.getDefault();
dataMiningServerTracker = createAndOpenDataMiningServerTracker(context);
securityServiceTracker = ServiceTrackerFactory.createAndOpen(context, SecurityService.class);
securityServiceTracker = new FullyInitializedReplicableTracker<>(context, SecurityService.class,
/* customizer */ null, ServiceTrackerFactory.createAndOpen(context, ReplicationService.class));
securityServiceTracker.open();
storedDataMiningQueryPersistor = new StoredDataMiningQueryPersisterImpl(getSecurityService(),
dataMiningServerTracker);
dtoFactory = new DataMiningDTOFactory();
@@ -84,7 +88,11 @@ public class DataMiningServiceImpl extends ProxiedRemoteServiceServlet implement
}
private SecurityService getSecurityService() {
return securityServiceTracker.getService();
try {
return securityServiceTracker.getInitializedService(0);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
@Override
@@ -394,7 +394,6 @@ import com.sap.sailing.domain.regattalike.LeaderboardThatHasRegattaLike;
import com.sap.sailing.domain.regattalog.RegattaLogStore;
import com.sap.sailing.domain.resultimport.ResultUrlProvider;
import com.sap.sailing.domain.sharding.ShardingContext;
import com.sap.sailing.domain.sharedsailingdata.SharedSailingData;
import com.sap.sailing.domain.swisstimingadapter.StartList;
import com.sap.sailing.domain.swisstimingadapter.SwissTimingAdapter;
import com.sap.sailing.domain.swisstimingadapter.SwissTimingAdapterFactory;
@@ -601,6 +600,7 @@ import com.sap.sailing.server.operationaltransformation.UpdateSpecificRegatta;
import com.sap.sailing.server.security.PermissionAwareRaceTrackingHandler;
import com.sap.sailing.server.security.SailingViewerRole;
import com.sap.sailing.server.util.WaitForTrackedRaceUtil;
import com.sap.sailing.shared.server.SharedSailingData;
import com.sap.sailing.simulator.Path;
import com.sap.sailing.simulator.PolarDiagram;
import com.sap.sailing.simulator.SimulationResults;
@@ -658,6 +658,7 @@ import com.sap.sse.pairinglist.PairingList;
import com.sap.sse.pairinglist.PairingListTemplate;
import com.sap.sse.pairinglist.impl.PairingListTemplateImpl;
import com.sap.sse.qrcode.QRCodeGenerationUtil;
import com.sap.sse.replication.FullyInitializedReplicableTracker;
import com.sap.sse.replication.OperationWithResult;
import com.sap.sse.replication.ReplicaDescriptor;
import com.sap.sse.replication.Replicable;
@@ -706,7 +707,7 @@ public class SailingServiceImpl extends ResultCachingProxiedRemoteServiceServlet
private static final long serialVersionUID = 9031688830194537489L;
private final ServiceTracker<RacingEventService, RacingEventService> racingEventServiceTracker;
private final FullyInitializedReplicableTracker<RacingEventService> racingEventServiceTracker;
private final ServiceTracker<ReplicationService, ReplicationService> replicationServiceTracker;
@@ -733,9 +734,9 @@ public class SailingServiceImpl extends ResultCachingProxiedRemoteServiceServlet
private final ServiceTracker<DeviceIdentifierStringSerializationHandler, DeviceIdentifierStringSerializationHandler>
deviceIdentifierStringSerializationHandlerTracker;
private final ServiceTracker<SecurityService, SecurityService> securityServiceTracker;
private final FullyInitializedReplicableTracker<SecurityService> securityServiceTracker;
private final ServiceTracker<SharedSailingData, SharedSailingData> sharedSailingDataTracker;
private final FullyInitializedReplicableTracker<SharedSailingData> sharedSailingDataTracker;
private final com.sap.sailing.domain.tractracadapter.persistence.MongoObjectFactory tractracMongoObjectFactory;
@@ -778,17 +779,23 @@ public class SailingServiceImpl extends ResultCachingProxiedRemoteServiceServlet
BundleContext context = Activator.getDefault();
Activator activator = Activator.getInstance();
quickRanksLiveCache = new QuickRanksLiveCache(this);
racingEventServiceTracker = ServiceTrackerFactory.createAndOpen(context, RacingEventService.class);
sharedSailingDataTracker = ServiceTrackerFactory.createAndOpen(context, SharedSailingData.class);
windFinderTrackerFactoryServiceTracker = ServiceTrackerFactory.createAndOpen(context, WindFinderTrackerFactory.class);
replicationServiceTracker = ServiceTrackerFactory.createAndOpen(context, ReplicationService.class);
racingEventServiceTracker = new FullyInitializedReplicableTracker<>(context, RacingEventService.class,
/* customizer */ null, replicationServiceTracker);
racingEventServiceTracker.open();
sharedSailingDataTracker = new FullyInitializedReplicableTracker<>(context, SharedSailingData.class,
/* service tracker customizer */ null, replicationServiceTracker);
sharedSailingDataTracker.open();
windFinderTrackerFactoryServiceTracker = ServiceTrackerFactory.createAndOpen(context, WindFinderTrackerFactory.class);
swissTimingAdapterTracker = ServiceTrackerFactory.createAndOpen(context, SwissTimingAdapterFactory.class);
tractracAdapterTracker = ServiceTrackerFactory.createAndOpen(context, TracTracAdapterFactory.class);
raceLogTrackingAdapterTracker = ServiceTrackerFactory.createAndOpen(context,
RaceLogTrackingAdapterFactory.class);
deviceIdentifierStringSerializationHandlerTracker = ServiceTrackerFactory.createAndOpen(context,
DeviceIdentifierStringSerializationHandler.class);
securityServiceTracker = ServiceTrackerFactory.createAndOpen(context, SecurityService.class);
securityServiceTracker = new FullyInitializedReplicableTracker<>(context, SecurityService.class,
/* service tracker customizer */ null, replicationServiceTracker);
securityServiceTracker.open();
igtimiAdapterTracker = ServiceTrackerFactory.createAndOpen(context, IgtimiConnectionFactory.class);
baseDomainFactory = getService().getBaseDomainFactory();
mongoObjectFactory = getService().getMongoObjectFactory();
@@ -2776,7 +2783,7 @@ public class SailingServiceImpl extends ResultCachingProxiedRemoteServiceServlet
protected RacingEventService getService() {
try {
return racingEventServiceTracker.waitForService(0);
return racingEventServiceTracker.getInitializedService(0);
} catch (InterruptedException e) {
throw new RuntimeException(e);
} // grab the service
@@ -2784,7 +2791,7 @@ public class SailingServiceImpl extends ResultCachingProxiedRemoteServiceServlet
protected SharedSailingData getSharedSailingData() {
try {
return sharedSailingDataTracker.waitForService(0);
return sharedSailingDataTracker.getInitializedService(0);
} catch (InterruptedException e) {
throw new RuntimeException(e);
} // grab the service
@@ -2800,7 +2807,7 @@ public class SailingServiceImpl extends ResultCachingProxiedRemoteServiceServlet
protected SecurityService getSecurityService() {
try {
return securityServiceTracker.waitForService(0);
return securityServiceTracker.getInitializedService(0);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
@@ -4467,12 +4474,17 @@ public class SailingServiceImpl extends ResultCachingProxiedRemoteServiceServlet
// The queue name must always be the same for this server. In order to achieve
// this we're using the unique server identifier
final ReplicationService replicationService = getReplicationService();
replicationService.startToReplicateFrom(replicationService.createReplicationMasterDescriptor(messagingHost,
masterHostName, exchangeName, servletPort, messagingPort,
/* use local server identifier as queue name */ replicationService.getServerIdentifier().toString(),
RemoteServerUtil.resolveBearerTokenForRemoteServer(masterHostName, servletPort, usernameOrNull,
passwordOrNull),
replicationService.getAllReplicables()));
replicationService.setReplicationStarting(true);
try {
replicationService.startToReplicateFrom(replicationService.createReplicationMasterDescriptor(messagingHost,
masterHostName, exchangeName, servletPort, messagingPort,
/* use local server identifier as queue name */ replicationService.getServerIdentifier().toString(),
RemoteServerUtil.resolveBearerTokenForRemoteServer(masterHostName, servletPort, usernameOrNull,
passwordOrNull),
replicationService.getAllReplicables()));
} finally {
replicationService.setReplicationStarting(false);
}
}
@Override
@@ -5324,15 +5336,15 @@ public class SailingServiceImpl extends ResultCachingProxiedRemoteServiceServlet
@Override
public List<UrlDTO> getResultImportUrls(String resultProviderName) {
final List<UrlDTO> result = new ArrayList<>();
SecurityService securityService = getSecurityService();
SecurityService securityService = getSecurityService();
Iterable<URL> allUrlsReadableBySubject = getService().getResultImportUrls(resultProviderName);
for (URL url : allUrlsReadableBySubject) {
QualifiedObjectIdentifier objId = SecuredDomainType.RESULT_IMPORT_URL.getQualifiedObjectIdentifier(
for (URL url : allUrlsReadableBySubject) {
QualifiedObjectIdentifier objId = SecuredDomainType.RESULT_IMPORT_URL.getQualifiedObjectIdentifier(
new TypeRelativeObjectIdentifier(resultProviderName, url.toString()));
UrlDTO urlDTO = new UrlDTO(url.toString());
SecurityDTOUtil.addSecurityInformation(securityService, urlDTO, objId);
result.add(urlDTO);
}
UrlDTO urlDTO = new UrlDTO(url.toString());
SecurityDTOUtil.addSecurityInformation(securityService, urlDTO, objId);
result.add(urlDTO);
}
return result;
}
@@ -5345,12 +5357,12 @@ public class SailingServiceImpl extends ResultCachingProxiedRemoteServiceServlet
return new URL(urlDto.getUrl());
} catch (MalformedURLException e) {
return null;
}
}
})
.filter(url -> url != null)
.collect(Collectors.toSet());
racingEventService.removeResultImportURLs(resultProviderName, urlsToRemove);
}
}
@Override
public void addResultImportUrl(String resultProviderName, UrlDTO urlDTO) throws Exception {
@@ -5359,7 +5371,7 @@ public class SailingServiceImpl extends ResultCachingProxiedRemoteServiceServlet
.orElseThrow(() -> new IllegalStateException("ResultUrlProvider not found: " + resultProviderName));
final URL url = resultUrlProvider.resolveUrl(urlDTO.getUrl());
racingEventService.addResultImportUrl(resultProviderName, url);
}
}
@Override
public String validateResultImportUrl(String resultProviderName, UrlDTO urlDTO) {
@@ -84,7 +84,7 @@ public class PolarDataServiceImpl implements ReplicablePolarService, ClearStateT
private final Set<OperationWithResult<PolarDataService, ?>> operationsSentToMasterForReplication;
private ThreadLocal<Boolean> currentlyFillingFromInitialLoad = ThreadLocal.withInitial(() -> false);
private volatile boolean currentlyFillingFromInitialLoad;
private ThreadLocal<Boolean> currentlyApplyingOperationReceivedFromMaster = ThreadLocal.withInitial(() -> false);
@@ -103,6 +103,7 @@ public class PolarDataServiceImpl implements ReplicablePolarService, ClearStateT
*/
public PolarDataServiceImpl() {
resetState();
this.currentlyFillingFromInitialLoad = false;
this.operationsSentToMasterForReplication = new HashSet<>();
this.operationExecutionListeners = new ConcurrentHashMap<>();
}
@@ -322,12 +323,12 @@ public class PolarDataServiceImpl implements ReplicablePolarService, ClearStateT
@Override
public boolean isCurrentlyFillingFromInitialLoad() {
return currentlyFillingFromInitialLoad.get();
return currentlyFillingFromInitialLoad;
}
@Override
public void setCurrentlyFillingFromInitialLoad(boolean currentlyFillingFromInitialLoad) {
this.currentlyFillingFromInitialLoad.set(currentlyFillingFromInitialLoad);
this.currentlyFillingFromInitialLoad = currentlyFillingFromInitialLoad;
}
@Override
@@ -15,7 +15,8 @@ Require-Bundle: com.sap.sailing.domain.common,
com.sap.sailing.server.gateway.serialization.shared.android,
com.sap.sse.security,
com.sap.sse.security.common,
com.sap.sse.replication
com.sap.sse.replication,
com.sap.sailing.shared.server
Export-Package: com.sap.sailing.server.gateway.deserialization.impl,
com.sap.sailing.server.gateway.serialization,
com.sap.sailing.server.gateway.serialization.impl,
@@ -52,9 +52,9 @@ import com.sap.sailing.domain.coursetemplate.impl.MarkTemplateBasedMarkConfigura
import com.sap.sailing.domain.coursetemplate.impl.RegattaMarkConfigurationImpl;
import com.sap.sailing.domain.coursetemplate.impl.WaypointWithMarkConfigurationImpl;
import com.sap.sailing.domain.racelogtracking.DeviceMappingWithRegattaLogEvent;
import com.sap.sailing.domain.sharedsailingdata.SharedSailingData;
import com.sap.sailing.domain.tracking.GPSFixTrack;
import com.sap.sailing.domain.tracking.TrackedRace;
import com.sap.sailing.shared.server.SharedSailingData;
import com.sap.sse.common.TimeRange;
import com.sap.sse.common.Util.Triple;
import com.sap.sse.common.WithID;
@@ -22,10 +22,10 @@ import com.sap.sailing.domain.coursetemplate.MarkConfigurationRequestAnnotation.
import com.sap.sailing.domain.coursetemplate.Positioning;
import com.sap.sailing.domain.coursetemplate.RepeatablePart;
import com.sap.sailing.domain.coursetemplate.impl.MarkConfigurationRequestAnnotationImpl.MarkRoleCreationRequestImpl;
import com.sap.sailing.domain.sharedsailingdata.SharedSailingData;
import com.sap.sailing.server.gateway.deserialization.JsonDeserializationException;
import com.sap.sailing.server.gateway.deserialization.JsonDeserializer;
import com.sap.sailing.server.gateway.serialization.impl.CourseConfigurationJsonSerializer;
import com.sap.sailing.shared.server.SharedSailingData;
public class CourseConfigurationJsonDeserializer implements JsonDeserializer<CourseConfiguration<MarkConfigurationRequestAnnotation>> {
@@ -20,10 +20,10 @@ import com.sap.sailing.domain.base.Regatta;
import com.sap.sailing.domain.common.ScoreCorrectionProvider;
import com.sap.sailing.domain.racelogtracking.RaceLogTrackingAdapter;
import com.sap.sailing.domain.racelogtracking.RaceLogTrackingAdapterFactory;
import com.sap.sailing.domain.sharedsailingdata.SharedSailingData;
import com.sap.sailing.domain.tracking.DynamicTrackedRegatta;
import com.sap.sailing.domain.tracking.TrackedRace;
import com.sap.sailing.server.interfaces.RacingEventService;
import com.sap.sailing.shared.server.SharedSailingData;
import com.sap.sse.InvalidDateException;
import com.sap.sse.common.TimePoint;
import com.sap.sse.common.TypeBasedServiceFinderFactory;
@@ -7,8 +7,8 @@ import javax.ws.rs.core.Application;
import org.osgi.framework.BundleContext;
import org.osgi.util.tracker.ServiceTracker;
import com.sap.sailing.domain.sharedsailingdata.SharedSailingData;
import com.sap.sailing.server.interfaces.RacingEventService;
import com.sap.sailing.shared.server.SharedSailingData;
import com.sap.sse.datamining.DataMiningServer;
import com.sap.sse.replication.ReplicationService;
import com.sap.sse.security.SecurityService;
@@ -37,5 +37,6 @@ Require-Bundle: com.sap.sailing.server,
com.sun.jersey;bundle-version="1.17.0",
com.sap.sse.security.testsupport,
com.sap.sailing.domain.racelogtrackingadapter,
com.sap.sailing.resultimport;bundle-version="1.0.0"
com.sap.sailing.shared.server,
com.sap.sailing.resultimport
Automatic-Module-Name: com.sap.sailing.server.replication.test
@@ -55,8 +55,10 @@ public abstract class AbstractServerReplicationTest extends com.sap.sse.replicat
@Override public DomainFactory getBaseDomainFactory() { return baseDomainFactory; }
@Override public CompetitorAndBoatStore getCompetitorAndBoatStore() { return getBaseDomainFactory().getCompetitorAndBoatStore(); }
};
}, MediaDBFactory.INSTANCE.getMediaDB(mongoDBService), EmptyWindStore.INSTANCE, EmptySensorFixStore.INSTANCE, null, null, /* sailingNotificationService */ null,
/* trackedRaceStatisticsCache */ null, /* restoreTrackedRaces */ false, null, /* sharedSailingData */ null,
}, MediaDBFactory.INSTANCE.getMediaDB(mongoDBService), EmptyWindStore.INSTANCE,
EmptySensorFixStore.INSTANCE, null, null, /* sailingNotificationService */ null,
/* trackedRaceStatisticsCache */ null, /* restoreTrackedRaces */ false,
/* security service tracker */ null, /* sharedSailingData */ null, /* replicationServiceTracker */ null,
/* scoreCorrectionProviderServiceTracker */ null, /* resultUrlRegistryServiceTracker */ null);
}
@@ -75,9 +77,10 @@ public abstract class AbstractServerReplicationTest extends com.sap.sse.replicat
@Override public DomainFactory getBaseDomainFactory() { return domainObjectFactory.getBaseDomainFactory(); }
@Override public CompetitorAndBoatStore getCompetitorAndBoatStore() { return getBaseDomainFactory().getCompetitorAndBoatStore(); }
};
}, MediaDBFactory.INSTANCE.getMediaDB(mongoDBService), EmptyWindStore.INSTANCE, EmptySensorFixStore.INSTANCE,
/* serviceFinderFactory */ null, null, /* sailingNotificationService */ null,
/* trackedRaceStatisticsCache */ null, /* restoreTrackedRaces */ false, null, /* sharedSailingData */ null,
}, MediaDBFactory.INSTANCE.getMediaDB(mongoDBService), EmptyWindStore.INSTANCE,
EmptySensorFixStore.INSTANCE, /* serviceFinderFactory */ null, null,
/* sailingNotificationService */ null, /* trackedRaceStatisticsCache */ null,
/* restoreTrackedRaces */ false, /* security service tracker */ null, /* sharedSailingData */ null, /* replicationServiceTracker */ null,
/* scoreCorrectionProviderServiceTracker */ null, /* resultUrlRegistryServiceTracker */ null);
}
}
@@ -42,6 +42,7 @@ Require-Bundle: com.sap.sailing.domain,
com.sap.sailing.server.interface,
org.mongodb.mongo-java-driver;bundle-version="3.6.4",
com.sap.sse.security.common,
com.sap.sailing.shared.server,
com.sap.sailing.resultimport
Bundle-ClassPath: .
Export-Package: com.sap.sailing.server,
@@ -41,7 +41,6 @@ import com.sap.sailing.domain.persistence.racelog.tracking.impl.GPSFixMongoHandl
import com.sap.sailing.domain.persistence.racelog.tracking.impl.GPSFixMovingMongoHandlerImpl;
import com.sap.sailing.domain.polars.PolarDataService;
import com.sap.sailing.domain.racelog.tracking.SensorFixStoreSupplier;
import com.sap.sailing.domain.sharedsailingdata.SharedSailingData;
import com.sap.sailing.domain.tracking.TrackedRegattaListener;
import com.sap.sailing.domain.windestimation.WindEstimationFactoryService;
import com.sap.sailing.resultimport.ResultUrlRegistry;
@@ -56,6 +55,7 @@ import com.sap.sailing.server.notification.impl.SailingNotificationServiceImpl;
import com.sap.sailing.server.security.SailingViewerRole;
import com.sap.sailing.server.statistics.TrackedRaceStatisticsCache;
import com.sap.sailing.server.statistics.TrackedRaceStatisticsCacheImpl;
import com.sap.sailing.shared.server.SharedSailingData;
import com.sap.sse.MasterDataImportClassLoaderService;
import com.sap.sse.common.TypeBasedServiceFinder;
import com.sap.sse.common.Util;
@@ -63,7 +63,9 @@ import com.sap.sse.mail.MailService;
import com.sap.sse.mail.queue.MailQueue;
import com.sap.sse.mail.queue.impl.ExecutorMailQueue;
import com.sap.sse.osgi.CachedOsgiTypeBasedServiceFinderFactory;
import com.sap.sse.replication.FullyInitializedReplicableTracker;
import com.sap.sse.replication.Replicable;
import com.sap.sse.replication.ReplicationService;
import com.sap.sse.security.SecurityInitializationCustomizer;
import com.sap.sse.security.SecurityService;
import com.sap.sse.security.interfaces.PreferenceConverter;
@@ -111,9 +113,11 @@ public class Activator implements BundleActivator {
private ServiceTracker<MailService, MailService> mailServiceTracker;
private ServiceTracker<SecurityService, SecurityService> securityServiceTracker;
private FullyInitializedReplicableTracker<SecurityService> securityServiceTracker;
private ServiceTracker<SharedSailingData, SharedSailingData> sharedSailingDataTracker;
private FullyInitializedReplicableTracker<SharedSailingData> sharedSailingDataTracker;
private ServiceTracker<ReplicationService, ReplicationService> replicationServiceTracker;
public Activator() {
clearPersistentCompetitors = Boolean
@@ -130,13 +134,19 @@ public class Activator implements BundleActivator {
extenderBundleTracker = new ExtenderBundleTracker(context);
extenderBundleTracker.open();
mailServiceTracker = ServiceTrackerFactory.createAndOpen(context, MailService.class);
securityServiceTracker = ServiceTrackerFactory.createAndOpen(context, SecurityService.class);
replicationServiceTracker = ServiceTrackerFactory.createAndOpen(context, ReplicationService.class);
sharedSailingDataTracker = new FullyInitializedReplicableTracker<>(context, SharedSailingData.class,
/* customizer */ null, replicationServiceTracker);
sharedSailingDataTracker.open();
securityServiceTracker = new FullyInitializedReplicableTracker<>(context, SecurityService.class,
/* customizer */ null, replicationServiceTracker);
securityServiceTracker.open();
if (securityServiceTracker != null) {
new Thread("Racingevent wait for securityservice for migration thread") {
public void run() {
try {
// only continue once we have the service, as some of the services require it to start properly
securityServiceTracker.waitForService(0);
securityServiceTracker.getInitializedService(0);
internalStartBundle(context);
} catch (Exception e) {
logger.log(Level.SEVERE, "Could not start RacingEvent service properly", e);
@@ -200,13 +210,15 @@ public class Activator implements BundleActivator {
mailQueue.stop();
mailServiceTracker.close();
sharedSailingDataTracker.close();
replicationServiceTracker.close();
securityServiceTracker.close();
MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();
mbs.unregisterMBean(mBeanName);
}
private void internalStartBundle(BundleContext context) throws MalformedURLException, MalformedObjectNameException,
InstanceAlreadyExistsException, MBeanRegistrationException, NotCompliantMBeanException {
InstanceAlreadyExistsException, MBeanRegistrationException, NotCompliantMBeanException, InterruptedException {
assert securityServiceTracker.getInitializedService(0) != null; // callers must call securityServiceTracker.waitForService(0) before calling this method
mailQueue = new ExecutorMailQueue(mailServiceTracker);
notificationService = new SailingNotificationServiceImpl(context, mailQueue);
trackedRegattaListener = new OSGiBasedTrackedRegattaListener(context);
@@ -236,7 +248,6 @@ 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);
sharedSailingDataTracker = ServiceTrackerFactory.createAndOpen(context, SharedSailingData.class);
ServiceTracker<ScoreCorrectionProvider, ScoreCorrectionProvider> scoreCorrectionProviderServiceTracker =
ServiceTrackerFactory.createAndOpen(context, ScoreCorrectionProvider.class);
ServiceTracker<ResultUrlRegistry, ResultUrlRegistry> resultUrlRegistryServiceTracker = ServiceTrackerFactory
@@ -244,7 +255,7 @@ public class Activator implements BundleActivator {
racingEventService = new RacingEventServiceImpl(clearPersistentCompetitors,
serviceFinderFactory, trackedRegattaListener, notificationService,
trackedRaceStatisticsCache, restoreTrackedRaces, securityServiceTracker,
sharedSailingDataTracker, scoreCorrectionProviderServiceTracker, resultUrlRegistryServiceTracker);
sharedSailingDataTracker, replicationServiceTracker, scoreCorrectionProviderServiceTracker, resultUrlRegistryServiceTracker);
notificationService.setRacingEventService(racingEventService);
masterDataImportClassLoaderServiceTracker = new ServiceTracker<MasterDataImportClassLoaderService, MasterDataImportClassLoaderService>(
context, MasterDataImportClassLoaderService.class,
@@ -18,8 +18,6 @@ import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.stream.Collectors;
import org.osgi.util.tracker.ServiceTracker;
import com.sap.sailing.domain.abstractlog.AbstractLogEventAuthor;
import com.sap.sailing.domain.abstractlog.race.analyzing.impl.RaceLogResolver;
import com.sap.sailing.domain.abstractlog.race.state.ReadonlyRaceState;
@@ -88,22 +86,23 @@ import com.sap.sailing.domain.racelog.tracking.SensorFixStore;
import com.sap.sailing.domain.racelogtracking.DeviceMappingWithRegattaLogEvent;
import com.sap.sailing.domain.racelogtracking.PingDeviceIdentifier;
import com.sap.sailing.domain.racelogtracking.impl.PingDeviceIdentifierImpl;
import com.sap.sailing.domain.sharedsailingdata.SharedSailingData;
import com.sap.sailing.domain.tracking.TrackedRace;
import com.sap.sailing.server.gateway.deserialization.impl.CourseConfigurationBuilder;
import com.sap.sailing.server.interfaces.CourseAndMarkConfigurationFactory;
import com.sap.sailing.shared.server.SharedSailingData;
import com.sap.sse.common.NoCorrespondingServiceRegisteredException;
import com.sap.sse.common.TimePoint;
import com.sap.sse.common.Timed;
import com.sap.sse.common.Util;
import com.sap.sse.common.Util.Pair;
import com.sap.sse.replication.FullyInitializedReplicableTracker;
import com.sap.sse.security.shared.impl.UserGroup;
public class CourseAndMarkConfigurationFactoryImpl implements CourseAndMarkConfigurationFactory {
private static final Logger logger = Logger.getLogger(CourseAndMarkConfigurationFactoryImpl.class.getName());
private final ServiceTracker<SharedSailingData, SharedSailingData> sharedSailingDataTracker;
private final FullyInitializedReplicableTracker<SharedSailingData> sharedSailingDataTracker;
private final SensorFixStore sensorFixStore;
/**
@@ -117,7 +116,7 @@ public class CourseAndMarkConfigurationFactoryImpl implements CourseAndMarkConfi
private final DomainFactory domainFactory;
public CourseAndMarkConfigurationFactoryImpl(
ServiceTracker<SharedSailingData, SharedSailingData> sharedSailingDataTracker,
FullyInitializedReplicableTracker<SharedSailingData> sharedSailingDataTracker,
SensorFixStore sensorFixStore, RaceLogResolver raceLogResolver, DomainFactory domainFactory) {
this.sharedSailingDataTracker = sharedSailingDataTracker;
this.domainFactory = domainFactory;
@@ -139,7 +138,15 @@ public class CourseAndMarkConfigurationFactoryImpl implements CourseAndMarkConfi
}
private SharedSailingData getSharedSailingData() {
return sharedSailingDataTracker.getService();
SharedSailingData result;
try {
result = sharedSailingDataTracker.getInitializedService(0);
} catch (InterruptedException e) {
logger.log(Level.SEVERE, "Interrupted while waiting for a fully initialized SharedSailingData service; "
+ "continuing with null, probably causing a NullPointerException along the way", e);
result = null;
}
return result;
}
private CourseTemplate resolveCourseTemplateSafe(CourseBase course) {
@@ -189,7 +189,6 @@ import com.sap.sailing.domain.regattalike.IsRegattaLike;
import com.sap.sailing.domain.regattalike.LeaderboardThatHasRegattaLike;
import com.sap.sailing.domain.regattalog.RegattaLogStore;
import com.sap.sailing.domain.resultimport.ResultUrlProvider;
import com.sap.sailing.domain.sharedsailingdata.SharedSailingData;
import com.sap.sailing.domain.statistics.Statistics;
import com.sap.sailing.domain.tracking.AddResult;
import com.sap.sailing.domain.tracking.DynamicRaceDefinitionSet;
@@ -209,13 +208,13 @@ import com.sap.sailing.domain.tracking.TrackedRace;
import com.sap.sailing.domain.tracking.TrackedRaceStatus;
import com.sap.sailing.domain.tracking.TrackedRegatta;
import com.sap.sailing.domain.tracking.TrackedRegattaListener;
import com.sap.sailing.domain.tracking.TrackingConnectorInfo;
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.domain.tracking.impl.TrackedRaceImpl;
import com.sap.sailing.domain.tracking.TrackingConnectorInfo;
import com.sap.sailing.domain.windestimation.WindEstimationFactoryService;
import com.sap.sailing.expeditionconnector.ExpeditionTrackerFactory;
import com.sap.sailing.resultimport.ResultUrlRegistry;
@@ -286,6 +285,7 @@ import com.sap.sailing.server.statistics.StatisticsCalculator;
import com.sap.sailing.server.statistics.TrackedRaceStatisticsCache;
import com.sap.sailing.server.tagging.TaggingServiceFactory;
import com.sap.sailing.server.util.EventUtil;
import com.sap.sailing.shared.server.SharedSailingData;
import com.sap.sse.ServerInfo;
import com.sap.sse.common.Distance;
import com.sap.sse.common.Duration;
@@ -309,6 +309,7 @@ import com.sap.sse.pairinglist.PairingFrameProvider;
import com.sap.sse.pairinglist.PairingList;
import com.sap.sse.pairinglist.PairingListTemplate;
import com.sap.sse.pairinglist.PairingListTemplateFactory;
import com.sap.sse.replication.FullyInitializedReplicableTracker;
import com.sap.sse.replication.OperationExecutionListener;
import com.sap.sse.replication.OperationWithResult;
import com.sap.sse.replication.OperationWithResultWithIdWrapper;
@@ -519,7 +520,7 @@ public class RacingEventServiceImpl implements RacingEventService, ClearStateTes
private Set<OperationWithResultWithIdWrapper<?, ?>> operationsSentToMasterForReplication;
private boolean currentlyFillingFromInitialLoad = false;
private volatile boolean currentlyFillingFromInitialLoad;
private ThreadLocal<Boolean> currentlyApplyingOperationReceivedFromMaster = ThreadLocal.withInitial(() -> false);
@@ -534,7 +535,7 @@ public class RacingEventServiceImpl implements RacingEventService, ClearStateTes
private long numberOfTrackedRacesToRestore;
private final AtomicInteger numberOfTrackedRacesRestored;
private final ServiceTracker<ResultUrlRegistry, ResultUrlRegistry> resultUrlRegistryServiceTracker;
private final ServiceTracker<ScoreCorrectionProvider, ScoreCorrectionProvider> scoreCorrectionProviderServiceTracker;
@@ -565,8 +566,8 @@ public class RacingEventServiceImpl implements RacingEventService, ClearStateTes
*/
private OperationsToMasterSendingQueue unsentOperationsToMasterSender;
private ServiceTracker<SecurityService, SecurityService> securityServiceTracker;
private final FullyInitializedReplicableTracker<SecurityService> securityServiceTracker;
private final CourseAndMarkConfigurationFactory courseAndMarkConfigurationFactory;
/**
@@ -609,7 +610,7 @@ public class RacingEventServiceImpl implements RacingEventService, ClearStateTes
public RacingEventServiceImpl(boolean clearPersistentCompetitorAndBoatStore, final TypeBasedServiceFinderFactory serviceFinderFactory, boolean restoreTrackedRaces) {
this(clearPersistentCompetitorAndBoatStore, serviceFinderFactory, null, /* sailingNotificationService */ null,
/* trackedRaceStatisticsCache */ null, restoreTrackedRaces, null, /* sharedSailingDataTracker */ null,
/* trackedRaceStatisticsCache */ null, restoreTrackedRaces, null, /* sharedSailingDataTracker */ null, /* replicationServiceTracker */ null,
/* scoreCorrectionProviderServiceTracker */ null, /* resultUrlRegistryServiceTracker */ null);
}
@@ -636,8 +637,8 @@ public class RacingEventServiceImpl implements RacingEventService, ClearStateTes
final TypeBasedServiceFinderFactory serviceFinderFactory, TrackedRegattaListenerManager trackedRegattaListener,
SailingNotificationService sailingNotificationService,
TrackedRaceStatisticsCache trackedRaceStatisticsCache, boolean restoreTrackedRaces,
ServiceTracker<SecurityService, SecurityService> securityServiceTracker,
ServiceTracker<SharedSailingData, SharedSailingData> sharedSailingDataTracker,
FullyInitializedReplicableTracker<SecurityService> securityServiceTracker,
FullyInitializedReplicableTracker<SharedSailingData> sharedSailingDataTracker, ServiceTracker<ReplicationService, ReplicationService> replicationServiceTracker,
ServiceTracker<ScoreCorrectionProvider, ScoreCorrectionProvider> scoreCorrectionProviderServiceTracker,
ServiceTracker<ResultUrlRegistry, ResultUrlRegistry> resultUrlRegistryServiceTracker) {
this((final RaceLogAndTrackedRaceResolver raceLogResolver) -> {
@@ -669,8 +670,9 @@ public class RacingEventServiceImpl implements RacingEventService, ClearStateTes
}
};
}, MediaDBFactory.INSTANCE.getDefaultMediaDB(), null, null, serviceFinderFactory, trackedRegattaListener,
sailingNotificationService, trackedRaceStatisticsCache, restoreTrackedRaces, securityServiceTracker,
sharedSailingDataTracker, scoreCorrectionProviderServiceTracker, resultUrlRegistryServiceTracker);
sailingNotificationService, trackedRaceStatisticsCache, restoreTrackedRaces,
securityServiceTracker, sharedSailingDataTracker, /* replicationServiceTracker */ null,
scoreCorrectionProviderServiceTracker, resultUrlRegistryServiceTracker);
}
private RacingEventServiceImpl(final boolean clearPersistentCompetitorStore, WindStore windStore,
@@ -703,10 +705,11 @@ public class RacingEventServiceImpl implements RacingEventService, ClearStateTes
return competitorStore;
}
};
}, MediaDBFactory.INSTANCE.getDefaultMediaDB(), windStore, sensorFixStore, serviceFinderFactory, null,
sailingNotificationService, /* trackedRaceStatisticsCache */ null, restoreTrackedRaces, null,
/* sharedSailingDataTracker */ null, /* scoreCorrectionProviderServiceTracker */ null,
/* resultUrlRegistryServiceTracker */ null);
}, MediaDBFactory.INSTANCE.getDefaultMediaDB(), windStore, sensorFixStore, serviceFinderFactory,
/* tracked regatta listener */ null,
sailingNotificationService, /* trackedRaceStatisticsCache */ null, restoreTrackedRaces,
/* security service tracker */ null, /* sharedSailingDataTracker */ null, /* replicationServiceTracker */ null,
/* scoreCorrectionProviderServiceTracker */ null, /* resultUrlRegistryServiceTracker */ null);
}
public RacingEventServiceImpl(final DomainObjectFactory domainObjectFactory, MongoObjectFactory mongoObjectFactory,
@@ -733,8 +736,10 @@ public class RacingEventServiceImpl implements RacingEventService, ClearStateTes
return getBaseDomainFactory().getCompetitorAndBoatStore();
}
};
}, mediaDB, windStore, sensorFixStore, null, null, /* sailingNotificationService */ null,
/* trackedRaceStatisticsCache */ null, restoreTrackedRaces, null, /* sharedSailingDataTracker */ null,
}, mediaDB, windStore, sensorFixStore, /* service finder factory */ null,
/* tracked regatta listener */ null, /* sailingNotificationService */ null,
/* trackedRaceStatisticsCache */ null, restoreTrackedRaces, /* security service tracker */ null,
/* sharedSailingDataTracker */ null, /* replicationServiceTracker */ null,
/* scoreCorrectionProviderServiceTracker */ null, /* resultUrlRegistryServiceTracker */ null);
}
@@ -771,11 +776,13 @@ public class RacingEventServiceImpl implements RacingEventService, ClearStateTes
TypeBasedServiceFinderFactory serviceFinderFactory, TrackedRegattaListenerManager trackedRegattaListener,
SailingNotificationService sailingNotificationService,
TrackedRaceStatisticsCache trackedRaceStatisticsCache, boolean restoreTrackedRaces,
ServiceTracker<SecurityService, SecurityService> securityServiceTracker,
ServiceTracker<SharedSailingData, SharedSailingData> sharedSailingDataTracker,
FullyInitializedReplicableTracker<SecurityService> securityServiceTracker,
FullyInitializedReplicableTracker<SharedSailingData> sharedSailingDataTracker,
ServiceTracker<ReplicationService, ReplicationService> replicationServiceTracker,
ServiceTracker<ScoreCorrectionProvider, ScoreCorrectionProvider> scoreCorrectionProviderServiceTracker,
ServiceTracker<ResultUrlRegistry, ResultUrlRegistry> resultUrlRegistryServiceTracker) {
logger.info("Created " + this);
this.currentlyFillingFromInitialLoad = false;
this.securityServiceTracker = securityServiceTracker;
this.numberOfTrackedRacesRestored = new AtomicInteger();
this.resultUrlRegistryServiceTracker = resultUrlRegistryServiceTracker;
@@ -4776,13 +4783,18 @@ public class RacingEventServiceImpl implements RacingEventService, ClearStateTes
return competitorWithBoat;
}
@Override
/**
* This should only be used for replicable Operations that need access to the SecurityService, all other should
* obtain the SecurityService in another way.
*/
@Override
public SecurityService getSecurityService() {
return securityServiceTracker.getService();
try {
return securityServiceTracker.getInitializedService(0);
} catch (InterruptedException e) {
logger.severe("Interrupted while waiting for security service; returning null");
return null;
}
}
@Override
@@ -1,51 +0,0 @@
package com.sap.sailing.server.impl;
import java.net.URL;
import java.util.ArrayList;
import java.util.Map;
import java.util.UUID;
import com.sap.sailing.domain.common.DeviceIdentifier;
import com.sap.sailing.domain.common.Position;
import com.sap.sailing.domain.coursetemplate.CommonMarkProperties;
import com.sap.sailing.domain.coursetemplate.MarkRole;
import com.sap.sailing.domain.coursetemplate.MarkTemplate;
import com.sap.sailing.domain.coursetemplate.RepeatablePart;
import com.sap.sailing.domain.coursetemplate.WaypointTemplate;
import com.sap.sailing.domain.sharedsailingdata.SharedSailingData;
import com.sap.sse.replication.OperationWithResult;
import com.sap.sse.replication.ReplicableWithObjectInputStream;
public interface ReplicatingSharedSailingData extends SharedSailingData,
ReplicableWithObjectInputStream<ReplicatingSharedSailingData, OperationWithResult<ReplicatingSharedSailingData, ?>> {
Void internalCreateMarkRole(UUID idOfNewMarkRole, String name);
Void internalCreateMarkProperties(UUID idOfNewMarkProperties, CommonMarkProperties properties,
Iterable<String> tags);
Void internalUpdateMarkProperties(UUID idOfNewMarkProperties, CommonMarkProperties properties, Position position,
DeviceIdentifier deviceIdentifier, Iterable<String> tags);
Void internalCreateMarkTemplate(UUID idOfNewMarkTemplate, CommonMarkProperties properties);
Void internalCreateCourseTemplate(UUID idOfNewCourseTemplate, String courseTemplateName,
Iterable<MarkTemplate> marks, Iterable<WaypointTemplate> waypoints,
Map<MarkTemplate, MarkRole> associatedRoles, RepeatablePart optionalRepeatablePart, Iterable<String> tags,
URL optionalImageURL, Integer defaultNumberOfLaps);
Void internalSetTrackingDeviceIdentifierForMarkProperties(UUID markPropertiesUUID, DeviceIdentifier deviceIdentifier);
Void internalSetFixedPositionForMarkProperties(UUID markPropertiesUUID, Position position);
Void internalDeleteMarkProperties(UUID markPropertiesUUID);
Void internalDeleteCourseTemplate(UUID courseTemplateUUID);
Void internalRecordUsage(UUID markTemplateId, UUID markPropertiesId);
Void internalRecordUsage(UUID markPropertiesId, MarkRole roleName);
Void internalUpdateCourseTemplate(UUID uuid, String name, URL optionalImageURL, ArrayList<String> tags);
}
@@ -13,10 +13,10 @@ import com.sap.sailing.domain.base.Fleet;
import com.sap.sailing.domain.base.RaceColumn;
import com.sap.sailing.domain.base.RaceDefinition;
import com.sap.sailing.domain.base.Regatta;
import com.sap.sailing.domain.sharedsailingdata.SharedSailingData;
import com.sap.sailing.domain.tracking.DynamicTrackedRegatta;
import com.sap.sailing.domain.tracking.TrackedRace;
import com.sap.sailing.server.interfaces.RacingEventService;
import com.sap.sailing.shared.server.SharedSailingData;
import com.sap.sse.InvalidDateException;
import com.sap.sse.common.TimePoint;
import com.sap.sse.common.TypeBasedServiceFinderFactory;
@@ -7,8 +7,8 @@ import javax.ws.rs.core.Application;
import org.osgi.framework.BundleContext;
import org.osgi.util.tracker.ServiceTracker;
import com.sap.sailing.domain.sharedsailingdata.SharedSailingData;
import com.sap.sailing.server.interfaces.RacingEventService;
import com.sap.sailing.shared.server.SharedSailingData;
import com.sap.sse.replication.ReplicationService;
import com.sap.sse.security.SecurityService;
import com.sun.jersey.spi.container.servlet.ServletContainer;
@@ -7,38 +7,26 @@ Bundle-Version: 1.0.0.qualifier
Bundle-Activator: com.sap.sailing.shared.server.impl.Activator
Bundle-Vendor: SAP
Bundle-RequiredExecutionEnvironment: JavaSE-1.8
Import-Package: com.sap.sailing.server.gateway.deserialization,
javax.mail;version="1.4.0",
javax.mail.internet;version="1.4.0",
javax.mail.util;version="1.4.0",
org.json.simple,
org.json.simple.parser,
org.osgi.framework;version="1.3.0",
Import-Package: org.osgi.framework;version="1.3.0",
org.osgi.util.tracker;version="1.3.1"
Bundle-ActivationPolicy: lazy
Require-Bundle: com.sap.sailing.domain,
com.sap.sse.mongodb,
com.sap.sailing.domain.common,
Require-Bundle: com.sap.sailing.domain.common,
com.sap.sailing.domain.shared.android,
com.sap.sailing.server.gateway.serialization,
com.sap.sse.common,
com.sap.sse.operationaltransformation,
com.sap.sse.replication.interfaces,
com.sap.sse,
com.sap.sailing.server.gateway.serialization.shared.android,
com.sap.sse.shared.android,
com.sap.sse.security,
com.sap.sse.security.common,
org.apache.shiro.web;bundle-version="1.2.2",
org.apache.shiro.core;bundle-version="1.2.2",
javax.servlet;bundle-version="3.1.0",
com.sap.sse.mail,
com.sap.sailing.server.interface,
org.mongodb.mongo-java-driver;bundle-version="3.6.4",
com.sap.sse.security.common,
com.sap.sailing.shared.persistence
com.sap.sse.operationaltransformation,
com.sap.sse.security,
com.sap.sailing.shared.persistence,
javax.servlet;bundle-version="3.1.0"
Bundle-ClassPath: .
Export-Package: com.sap.sailing.shared.server.impl;
Export-Package: com.sap.sailing.shared.server,
com.sap.sailing.shared.server.impl;
x-friends:="com.sap.sailing.mongodb.test,
com.sap.sailing.server.test,
com.sap.sailing.server.gateway.test,
@@ -1,4 +1,4 @@
package com.sap.sailing.domain.sharedsailingdata;
package com.sap.sailing.shared.server;
import java.net.URL;
import java.util.ArrayList;
@@ -17,8 +17,11 @@ import com.sap.sailing.domain.coursetemplate.MarkTemplate;
import com.sap.sailing.domain.coursetemplate.Positioning;
import com.sap.sailing.domain.coursetemplate.RepeatablePart;
import com.sap.sailing.domain.coursetemplate.WaypointTemplate;
import com.sap.sailing.shared.server.impl.ReplicatingSharedSailingData;
import com.sap.sse.common.TimePoint;
import com.sap.sse.common.impl.MillisecondsTimePoint;
import com.sap.sse.replication.OperationWithResult;
import com.sap.sse.replication.ReplicableWithObjectInputStream;
import com.sap.sse.security.SecurityService;
import com.sap.sse.security.shared.HasPermissions.DefaultActions;
import com.sap.sse.security.shared.impl.UserGroup;
@@ -42,7 +45,7 @@ import com.sap.sse.security.shared.impl.UserGroup;
* @author Axel Uhl (D043530)
*
*/
public interface SharedSailingData {
public interface SharedSailingData extends ReplicableWithObjectInputStream<ReplicatingSharedSailingData, OperationWithResult<ReplicatingSharedSailingData, ?>> {
Iterable<MarkProperties> getAllMarkProperties(Iterable<String> tagsToFilterFor);
@@ -1,17 +1,20 @@
package com.sap.sailing.shared.server.impl;
import java.util.Dictionary;
import java.util.HashSet;
import java.util.Hashtable;
import java.util.Set;
import org.osgi.framework.BundleActivator;
import org.osgi.framework.BundleContext;
import org.osgi.framework.ServiceRegistration;
import org.osgi.util.tracker.ServiceTracker;
import com.sap.sailing.domain.sharedsailingdata.SharedSailingData;
import com.sap.sailing.shared.persistence.PersistenceFactory;
import com.sap.sailing.shared.server.SharedSailingData;
import com.sap.sse.osgi.CachedOsgiTypeBasedServiceFinderFactory;
import com.sap.sse.replication.FullyInitializedReplicableTracker;
import com.sap.sse.replication.Replicable;
import com.sap.sse.replication.ReplicationService;
import com.sap.sse.security.SecurityService;
import com.sap.sse.util.ClearStateTestSupport;
import com.sap.sse.util.ServiceTrackerFactory;
@@ -24,21 +27,27 @@ public class Activator implements BundleActivator {
private Set<ServiceRegistration<?>> registrations = new HashSet<>();
private ServiceTracker<SecurityService, SecurityService> securityServiceTracker;
private FullyInitializedReplicableTracker<SecurityService> securityServiceTracker;
private SharedSailingDataImpl sharedSailingData;
public void start(BundleContext context) throws Exception {
Activator.context = context;
securityServiceTracker = ServiceTrackerFactory.createAndOpen(context, SecurityService.class);
securityServiceTracker = new FullyInitializedReplicableTracker<>(context, SecurityService.class,
/* customizer */ null, ServiceTrackerFactory.createAndOpen(context, ReplicationService.class));
securityServiceTracker.open();
serviceFinderFactory = new CachedOsgiTypeBasedServiceFinderFactory(context);
sharedSailingData = new SharedSailingDataImpl(PersistenceFactory.INSTANCE.getDefaultDomainObjectFactory(serviceFinderFactory),
PersistenceFactory.INSTANCE.getDefaultMongoObjectFactory(serviceFinderFactory), serviceFinderFactory,
securityServiceTracker);
registrations.add(context.registerService(SharedSailingData.class, sharedSailingData, /* properties */ null));
registrations.add(context.registerService(ReplicatingSharedSailingData.class, sharedSailingData, /* properties */ null));
registrations
.add(context.registerService(ClearStateTestSupport.class, sharedSailingData, /* properties */ null));
registrations.add(context.registerService(Replicable.class, sharedSailingData, /* properties */ null));
final Dictionary<String, String> replicableServiceProperties = new Hashtable<>();
replicableServiceProperties.put(Replicable.OSGi_Service_Registry_ID_Property_Name,
sharedSailingData.getId().toString());
registrations.add(context.registerService(Replicable.class, sharedSailingData, /* properties */ replicableServiceProperties));
}
public static BundleContext getContext() {
@@ -11,12 +11,9 @@ import com.sap.sailing.domain.coursetemplate.MarkTemplate;
import com.sap.sailing.domain.coursetemplate.Positioning;
import com.sap.sailing.domain.coursetemplate.RepeatablePart;
import com.sap.sailing.domain.coursetemplate.WaypointTemplate;
import com.sap.sailing.domain.sharedsailingdata.SharedSailingData;
import com.sap.sse.replication.OperationWithResult;
import com.sap.sse.replication.ReplicableWithObjectInputStream;
import com.sap.sailing.shared.server.SharedSailingData;
public interface ReplicatingSharedSailingData extends SharedSailingData,
ReplicableWithObjectInputStream<ReplicatingSharedSailingData, OperationWithResult<ReplicatingSharedSailingData, ?>> {
public interface ReplicatingSharedSailingData extends SharedSailingData {
Void internalCreateMarkRole(UUID idOfNewMarkRole, String name, String shortName);
@@ -17,8 +17,6 @@ import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Collectors;
import org.osgi.util.tracker.ServiceTracker;
import com.sap.sailing.domain.common.DeviceIdentifier;
import com.sap.sailing.domain.common.Position;
import com.sap.sailing.domain.common.security.SecuredDomainType;
@@ -47,6 +45,7 @@ import com.sap.sse.common.TypeBasedServiceFinder;
import com.sap.sse.common.TypeBasedServiceFinderFactory;
import com.sap.sse.common.Util;
import com.sap.sse.common.impl.MillisecondsTimePoint;
import com.sap.sse.replication.FullyInitializedReplicableTracker;
import com.sap.sse.replication.OperationExecutionListener;
import com.sap.sse.replication.OperationWithResult;
import com.sap.sse.replication.OperationWithResultWithIdWrapper;
@@ -69,11 +68,11 @@ public class SharedSailingDataImpl implements ReplicatingSharedSailingData, Clea
private final Map<UUID, MarkRole> markRolesById = new ConcurrentHashMap<>();
private final TypeBasedServiceFinder<DeviceIdentifierMongoHandler> deviceIdentifierServiceFinder;
private final ServiceTracker<SecurityService, SecurityService> securityServiceTracker;
private final FullyInitializedReplicableTracker<SecurityService> securityServiceTracker;
// Replication related methods and fields
private final ConcurrentHashMap<OperationExecutionListener<ReplicatingSharedSailingData>, OperationExecutionListener<ReplicatingSharedSailingData>> operationExecutionListeners = new ConcurrentHashMap<>();
private ThreadLocal<Boolean> currentlyFillingFromInitialLoad = ThreadLocal.withInitial(() -> false);
private volatile boolean currentlyFillingFromInitialLoad;
private ThreadLocal<Boolean> currentlyApplyingOperationReceivedFromMaster = ThreadLocal.withInitial(() -> false);
private final Set<OperationWithResultWithIdWrapper<ReplicatingSharedSailingData, ?>> operationsSentToMasterForReplication = new HashSet<>();
private ReplicationMasterDescriptor master;
@@ -87,7 +86,8 @@ public class SharedSailingDataImpl implements ReplicatingSharedSailingData, Clea
public SharedSailingDataImpl(final DomainObjectFactory domainObjectFactory,
final MongoObjectFactory mongoObjectFactory, TypeBasedServiceFinderFactory serviceFinderFactory,
ServiceTracker<SecurityService, SecurityService> securityServiceTracker) {
FullyInitializedReplicableTracker<SecurityService> securityServiceTracker) {
this.currentlyFillingFromInitialLoad = false;
this.domainObjectFactory = domainObjectFactory;
this.mongoObjectFactory = mongoObjectFactory;
this.deviceIdentifierServiceFinder = serviceFinderFactory
@@ -123,7 +123,11 @@ public class SharedSailingDataImpl implements ReplicatingSharedSailingData, Clea
}
public SecurityService getSecurityService() {
return securityServiceTracker.getService();
try {
return securityServiceTracker.getInitializedService(0);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
@Override
@@ -579,12 +583,12 @@ public class SharedSailingDataImpl implements ReplicatingSharedSailingData, Clea
@Override
public boolean isCurrentlyFillingFromInitialLoad() {
return currentlyFillingFromInitialLoad.get();
return currentlyFillingFromInitialLoad;
}
@Override
public void setCurrentlyFillingFromInitialLoad(boolean currentlyFillingFromInitialLoad) {
this.currentlyFillingFromInitialLoad.set(currentlyFillingFromInitialLoad);
this.currentlyFillingFromInitialLoad = currentlyFillingFromInitialLoad;
}
@Override
@@ -45,7 +45,7 @@ public abstract class AbstractReplicableWithObjectInputStream<S, O extends Opera
private final Set<OperationWithResult<S, ?>> operationsSentToMasterForReplication;
private ThreadLocal<Boolean> currentlyFillingFromInitialLoad = ThreadLocal.withInitial(() -> false);
private volatile boolean currentlyFillingFromInitialLoad;
private ThreadLocal<Boolean> currentlyApplyingOperationReceivedFromMaster = ThreadLocal.withInitial(() -> false);
@@ -54,6 +54,7 @@ public abstract class AbstractReplicableWithObjectInputStream<S, O extends Opera
public AbstractReplicableWithObjectInputStream() {
this.operationsSentToMasterForReplication = new HashSet<>();
this.operationExecutionListeners = new ConcurrentHashMap<>();
this.currentlyFillingFromInitialLoad = false;
}
@Override
@@ -86,12 +87,12 @@ public abstract class AbstractReplicableWithObjectInputStream<S, O extends Opera
@Override
public boolean isCurrentlyFillingFromInitialLoad() {
return currentlyFillingFromInitialLoad.get();
return currentlyFillingFromInitialLoad;
}
@Override
public void setCurrentlyFillingFromInitialLoad(boolean currentlyFillingFromInitialLoad) {
this.currentlyFillingFromInitialLoad.set(currentlyFillingFromInitialLoad);
this.currentlyFillingFromInitialLoad = currentlyFillingFromInitialLoad;
}
@Override
@@ -17,10 +17,10 @@
</div>
</div>
<div class="yield_content">
<div class="contentWrapper">
<div class="mainContent">
<h2 class="releaseHeadline">Release Notes - Administration Console</h2>
<div class="innerContent">
<div class="contentWrapper">
<div class="mainContent">
<h2 class="releaseHeadline">Release Notes - Administration Console</h2>
<div class="innerContent">
<h2 class="articleSubheadline">March 2020</h2>
<ul class="bulletList">
<li>The visualization for ORC certificates has been much improved. It now shows all the
@@ -28,6 +28,11 @@
official PDF version of the respective certificate, based on its reference number.
</li>
<li>Improved ESC/Enter key handling in user role/permission editing dialog</li>
<li>The "Replication" panel in the "Advanced" category now has improved information about the
replicables shown. An advanced replica information string may reveal more than just the address,
and the address is now resolved through any <tt>X-Forwarded-For</tt> header fields present
during replica registration, hence also working through load balancers and reverse proxies.
</li>
</ul>
<h2 class="articleSubheadline">February 2020</h2>
<ul class="bulletList">
@@ -48,7 +48,7 @@ public class FileStorageManagementServiceImpl implements ReplicableFileStorageMa
private final Map<OperationExecutionListener<ReplicableFileStorageManagementService>, OperationExecutionListener<ReplicableFileStorageManagementService>> operationExecutionListeners = new ConcurrentHashMap<>();
private final Set<OperationWithResultWithIdWrapper<?, ?>> operationsSentToMasterForReplication = new HashSet<>();
private ReplicationMasterDescriptor replicationMasterDescriptor;
private ThreadLocal<Boolean> currentlyFillingFromInitialLoad = ThreadLocal.withInitial(() -> false);
private volatile boolean currentlyFillingFromInitialLoad;
private ThreadLocal<Boolean> currentlyApplyingOperationReceivedFromMaster = ThreadLocal.withInitial(() -> false);
@@ -68,6 +68,7 @@ public class FileStorageManagementServiceImpl implements ReplicableFileStorageMa
public FileStorageManagementServiceImpl(TypeBasedServiceFinder<FileStorageService> serviceFinder,
FileStorageServicePropertyStore propertyStore) {
this.currentlyFillingFromInitialLoad = false;
this.serviceFinder = serviceFinder;
this.propertyStore = propertyStore;
serviceResolver = new FileStorageServiceResolverAgainstOsgiRegistryImpl(serviceFinder);
@@ -229,12 +230,12 @@ public class FileStorageManagementServiceImpl implements ReplicableFileStorageMa
@Override
public boolean isCurrentlyFillingFromInitialLoad() {
return currentlyFillingFromInitialLoad.get();
return currentlyFillingFromInitialLoad;
}
@Override
public void setCurrentlyFillingFromInitialLoad(boolean currentlyFillingFromInitialLoad) {
this.currentlyFillingFromInitialLoad.set(currentlyFillingFromInitialLoad);
this.currentlyFillingFromInitialLoad = currentlyFillingFromInitialLoad;
}
@Override
@@ -48,7 +48,7 @@ public class MailServiceImpl implements ReplicableMailService {
private ReplicationMasterDescriptor replicatingFromMaster;
private final ConcurrentMap<OperationExecutionListener<ReplicableMailService>, OperationExecutionListener<ReplicableMailService>> operationExecutionListeners;
private final Set<OperationWithResultWithIdWrapper<?, ?>> operationsSentToMasterForReplication = new HashSet<>();
private ThreadLocal<Boolean> currentlyFillingFromInitialLoad = ThreadLocal.withInitial(() -> false);
private volatile boolean currentlyFillingFromInitialLoad;
private ThreadLocal<Boolean> currentlyApplyingOperationReceivedFromMaster = ThreadLocal.withInitial(() -> false);
@@ -63,6 +63,7 @@ public class MailServiceImpl implements ReplicableMailService {
private OperationsToMasterSendingQueue unsentOperationForMasterQueue;
public MailServiceImpl(Properties mailProperties, MailServiceResolver mailServiceResolver) {
this.currentlyFillingFromInitialLoad = false;
this.mailProperties = mailProperties;
this.operationExecutionListeners = new ConcurrentHashMap<>();
this.mailServiceResolver = mailServiceResolver;
@@ -238,12 +239,12 @@ public class MailServiceImpl implements ReplicableMailService {
@Override
public boolean isCurrentlyFillingFromInitialLoad() {
return currentlyFillingFromInitialLoad.get();
return currentlyFillingFromInitialLoad;
}
@Override
public void setCurrentlyFillingFromInitialLoad(boolean currentlyFillingFromInitialLoad) {
this.currentlyFillingFromInitialLoad.set(currentlyFillingFromInitialLoad);
this.currentlyFillingFromInitialLoad = currentlyFillingFromInitialLoad;
}
@Override
@@ -9,7 +9,9 @@ Bundle-RequiredExecutionEnvironment: JavaSE-1.8
Export-Package: com.sap.sse.replication,
com.sap.sse.replication.impl
Import-Package: com.rabbitmq.client;version="2.8.4",
org.json.simple
org.json.simple,
org.osgi.framework;version="1.8.0",
org.osgi.util.tracker;version="1.5.1"
Require-Bundle: com.sap.sse.operationaltransformation;bundle-version="1.0.0",
com.sap.sse.common;bundle-version="1.0.0",
com.sap.sse;bundle-version="1.0.0"
@@ -0,0 +1,129 @@
package com.sap.sse.replication;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import org.osgi.framework.BundleContext;
import org.osgi.framework.Filter;
import org.osgi.framework.ServiceReference;
import org.osgi.util.tracker.ServiceTracker;
import org.osgi.util.tracker.ServiceTrackerCustomizer;
import com.sap.sse.replication.ReplicationService.ReplicationStartingListener;
/**
* While a regular OSGi {@link ServiceTracker} would {@link ServiceTracker#waitForService(long) wait} for the service's
* appearance in the OSGi registry and then return it, this specialization is aware of the {@link ReplicationService}
* and understands the replication life cycle which can be in {@link ReplicationService#isReplicationStarting()
* starting} mode, and furthermore each replicable can be in the process of handling its initial load. This tracker has
* a specialized {@link #waitForService(long)} implementation that waits for the {@link ReplicationService} to not be in
* state {@link ReplicationService#isReplicationStarting()}, waits for the replicable requested using the regular
* (super-class) {@link ServiceTracker#waitForService(long)} method and asserts the {@link Replicable} to return is
* not in the state {@link Replicable#isCurrentlyFillingFromInitialLoad()}.<p>
*
* By analogy, the {@link #getService()} and related methods return only services for which the above rules apply.
* In particular, {@link #getService()} will return {@code null} if the {@link ReplicationService} is currently in mode
* {@link ReplicationService#isReplicationStarting()} or the replicable found by the regular OSGi tracker is currently
* {@link Replicable#isCurrentlyFillingFromInitialLoad() receiving its initial load}.<p>
*
* Note that {@link #waitForService(long)} must not be used during the activation of a {@link Replicable}'s bundle before
* that {@link Replicable} has been registered with the OSGi registry. Otherwise, a deadlock can result because the waiting
* {@link Replicable} will hold up the completion of the replication start-up and hence wait forever.
*
* @author Axel Uhl (D043530)
*
* @param <R>
* the type of {@link Replicable} to track
*/
public class FullyInitializedReplicableTracker<R extends Replicable<?, ?>> extends ServiceTracker<R, R> {
/**
* Used to find the {@link ReplicationService}. If {@code null}, no attempt will be made to look
* for the {@link ReplicationService}, and only the replicable's {@link Replicable#isCurrentlyFillingFromInitialLoad()}
* result will be considered.
*/
private final ServiceTracker<ReplicationService, ReplicationService> replicationServiceTracker;
public FullyInitializedReplicableTracker(BundleContext context, Class<R> clazz,
ServiceTrackerCustomizer<R, R> customizer,
ServiceTracker<ReplicationService, ReplicationService> replicationServiceTracker) {
super(context, clazz, customizer);
this.replicationServiceTracker = replicationServiceTracker;
}
public FullyInitializedReplicableTracker(BundleContext context, Filter filter,
ServiceTrackerCustomizer<R, R> customizer,
ServiceTracker<ReplicationService, ReplicationService> replicationServiceTracker) {
super(context, filter, customizer);
this.replicationServiceTracker = replicationServiceTracker;
}
public FullyInitializedReplicableTracker(BundleContext context, ServiceReference<R> reference,
ServiceTrackerCustomizer<R, R> customizer,
ServiceTracker<ReplicationService, ReplicationService> replicationServiceTracker) {
super(context, reference, customizer);
this.replicationServiceTracker = replicationServiceTracker;
}
public FullyInitializedReplicableTracker(BundleContext context, String clazz,
ServiceTrackerCustomizer<R, R> customizer,
ServiceTracker<ReplicationService, ReplicationService> replicationServiceTracker) {
super(context, clazz, customizer);
this.replicationServiceTracker = replicationServiceTracker;
}
/**
* @param timeoutInMillis
* 0 means indefinite waiting time
* @return {@code true} if the {@link #replicationServiceTracker} is {@code null} or the {@link ReplicationService}
* was obtained successfully and has been in or has reached the state of not
* {@link ReplicationService#isReplicationStarting()} within the timeout provided. {@code false} otherwise.
*/
private boolean waitForReplicationToBeInitialized(long timeoutInMillis) throws InterruptedException {
final boolean result;
if (replicationServiceTracker != null) {
final CountDownLatch latch = new CountDownLatch(1); // counted down either by the direct check or the listener
final ReplicationService replicationService = replicationServiceTracker.waitForService(timeoutInMillis);
final ReplicationStartingListener replicationStartingListener = newIsReplicationStarting->{
if (!newIsReplicationStarting) {
latch.countDown();
}
};
replicationService.addReplicationStartingListener(replicationStartingListener);
if (!replicationService.isReplicationStarting()) {
latch.countDown();
}
result = latch.await(timeoutInMillis, TimeUnit.MILLISECONDS);
replicationService.removeReplicationStartingListener(replicationStartingListener);
} else {
result = true;
}
return result;
}
/**
* Waits for one service object tracked to appear for {@code timeoutInMillis} milliseconds (see
* {@link #waitForService(long)}). If no such service object can be found before timing out, {@code null}
* is returned. Once a service object has been retrieved and a non-{@code null} {@link #replicationServiceTracker}
* has been provided at construction time, the {@link ReplicationService} is obtained from that tracker by
* waiting for it at least {@code timeoutInMillis} milliseconds and then
*
* @param timeoutInMillis
* 0 means indefinite wait time
* @return {@code null} if no service was obtained from the registry in the timeout specified or the replication did
* not reach a fully initialized state in the timeout specified.
*/
public R getInitializedService(long timeoutInMillis) throws InterruptedException {
final R service = waitForService(timeoutInMillis);
final R result;
if (service != null) {
if (waitForReplicationToBeInitialized(timeoutInMillis)) {
result = service;
} else {
result = null;
}
} else {
result = null;
}
return result;
}
}
@@ -45,6 +45,13 @@ public interface OperationWithResult<S, R> extends Operation<S>, Serializable {
default boolean isRequiresExplicitTransitiveReplication() {
return true;
}
/**
* @return the class to use for keeping statistics; this allows wrapper classes to report the actual inner class
*/
default Class<?> getClassForLogging() {
return getClass();
}
/**
* Ignores the actual result of {@link #internalApplyTo(Object)} and returns <code>toState</code> which
@@ -24,8 +24,7 @@ public class OperationWithResultWithIdWrapper<S, R> implements OperationWithResu
* Creates a new UUID for this wrapper operation
*/
public OperationWithResultWithIdWrapper(OperationWithResult<S, R> delegate) {
this.delegate = delegate;
this.id = UUID.randomUUID();
this(delegate, UUID.randomUUID());
}
/**
@@ -37,6 +36,14 @@ public class OperationWithResultWithIdWrapper<S, R> implements OperationWithResu
this.delegate = delegate;
}
/**
* @return the {@link #delegate}'s class for keeping statistics
*/
@Override
public Class<?> getClassForLogging() {
return delegate.getClass();
}
@Override
public int hashCode() {
final int prime = 31;
@@ -113,7 +113,20 @@ public interface ReplicationService {
*/
ReplicationReceiver getReplicator();
/**
* An update to this attribute can be observed by registering a {@link ReplicationStartingListener} using
* the {@link #addReplicationStartingListener} method.
*/
void setReplicationStarting(boolean b);
@FunctionalInterface
public static interface ReplicationStartingListener {
void onReplicationStartingChanged(boolean newReplicationStartingValue);
}
void addReplicationStartingListener(ReplicationStartingListener listener);
void removeReplicationStartingListener(ReplicationStartingListener listener);
/**
* @return {@code true} if replication is starting; during this phase it is clear that the replicables managed by
@@ -175,6 +175,7 @@ public class Activator implements BundleActivator {
" before firing up replication automatically...");
final List<Replicable<?, ?>> replicables = new ArrayList<>();
for (String replicableIdAsString : replicableIdsAsStrings) {
logger.info("Trying to obtain Replicable " + replicableIdAsString+", waiting if necessary");
Replicable<?, ?> replicable = replicablesProvider.getReplicable(replicableIdAsString, /* wait */true);
logger.info("Obtained Replicable " + replicableIdAsString);
replicables.add(replicable);
@@ -19,6 +19,7 @@ import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Random;
import java.util.Set;
import java.util.Timer;
import java.util.TimerTask;
import java.util.UUID;
@@ -232,7 +233,7 @@ public class ReplicationServiceImpl implements ReplicationService, OperationsToM
/**
* Will be set
*/
private boolean replicationStarting;
private volatile boolean replicationStarting;
/**
* An optional link to a persistence layer that allows this service to record replicas
@@ -240,6 +241,8 @@ public class ReplicationServiceImpl implements ReplicationService, OperationsToM
* links can be re-established.
*/
private final Optional<MongoObjectFactory> mongoObjectFactory;
private final Set<ReplicationStartingListener> replicationStartingListeners;
private static class InitialLoadRequest {
private final Channel channelForInitialLoad;
@@ -320,6 +323,7 @@ public class ReplicationServiceImpl implements ReplicationService, OperationsToM
Optional<MongoObjectFactory> optionalMongoObjectFactory, String exchangeName, String exchangeHost, int exchangePort,
ReplicationInstancesManager replicationInstancesManager, ReplicablesProvider replicablesProvider) throws IOException {
this.mongoObjectFactory = optionalMongoObjectFactory;
this.replicationStartingListeners = new HashSet<>();
timer = new Timer("ReplicationServiceImpl timer for delayed task sending", /* isDaemon */ true);
unsentOperationsSenderJob = new UnsentOperationsSenderJob();
executionListenersByReplicableIdAsString = new ConcurrentHashMap<>();
@@ -521,7 +525,7 @@ public class ReplicationServiceImpl implements ReplicationService, OperationsToM
outboundBufferClasses = new ArrayList<>();
}
outboundObjectBuffer.writeObject(serializedOperation);
outboundBufferClasses.add(operation.getClass());
outboundBufferClasses.add(operation.getClassForLogging());
if (outboundBuffer.size() > TRIGGER_MESSAGE_SIZE_IN_BYTES) {
logger.info("Triggering replication because buffer holds " + outboundBuffer.size()
+ " bytes which exceeds trigger size " + TRIGGER_MESSAGE_SIZE_IN_BYTES + " bytes");
@@ -647,7 +651,7 @@ public class ReplicationServiceImpl implements ReplicationService, OperationsToM
final Iterable<Replicable<?, ?>> replicables = master.getReplicables();
logger.info("Starting to replicate from " + master);
try {
registerReplicaWithMaster(master, replicables);
registerReplicaWithMaster(master);
} catch (Exception ex) {
logger.log(Level.SEVERE, "ERROR", ex);
throw ex;
@@ -680,7 +684,7 @@ public class ReplicationServiceImpl implements ReplicationService, OperationsToM
final URL initialLoadURL = master.getInitialLoadURL(replicables);
logger.info("Initial load URL is " + initialLoadURL);
// start receiving messages already now, but start in suspended mode
replicator = new ReplicationReceiverImpl(master, replicablesProvider, /* startSuspended */true, consumer);
replicator = new ReplicationReceiverImpl(master, replicablesProvider, /* startSuspended */ true, consumer);
// clear Replicable state here, before starting to receive and de-serialize operations which builds up
// new state, e.g., in competitor store
for (Replicable<?, ?> r : replicables) {
@@ -733,18 +737,13 @@ public class ReplicationServiceImpl implements ReplicationService, OperationsToM
}
/**
* @param replicables
* the replica is registered for these {@link Replicable}s. The master sends operations only for
* replicables that at least one replica has registered for. This may mean that operations are received
* for replicables for which no replicable was requested. Replicas shall drop such operations silently.
* TODO unused...
*
* @return the UUID that the master generated for this client which is also entered into {@link #replicaUUIDs}
*/
private String registerReplicaWithMaster(ReplicationMasterDescriptor master, Iterable<Replicable<?, ?>> replicables) throws IOException,
private String registerReplicaWithMaster(ReplicationMasterDescriptor master) throws IOException,
ClassNotFoundException {
URL replicationRegistrationRequestURL = master.getReplicationRegistrationRequestURL(getServerIdentifier(),
ServerInfo.getBuildVersion());
logger.info("Replication registration request URL: "+replicationRegistrationRequestURL);
final URLConnection registrationRequestConnection = HttpUrlConnectionHelper
.redirectConnectionWithBearerToken(replicationRegistrationRequestURL, master.getBearerToken());
final InputStream content = (InputStream) registrationRequestConnection.getContent();
@@ -761,6 +760,7 @@ public class ReplicationServiceImpl implements ReplicationService, OperationsToM
}
}
final String replicaUUID = uuid.toString();
logger.info("Obtained replica UUID "+replicaUUID+" from master");
registerReplicaUuidForMaster(replicaUUID, master);
return replicaUUID;
}
@@ -891,9 +891,31 @@ public class ReplicationServiceImpl implements ReplicationService, OperationsToM
servletPort, bearerToken, replicables);
}
@Override
public void setReplicationStarting(boolean b) {
this.replicationStarting = b;
public void addReplicationStartingListener(ReplicationStartingListener listener) {
synchronized (replicationStartingListeners) {
replicationStartingListeners.add(listener);
}
}
@Override
public void removeReplicationStartingListener(ReplicationStartingListener listener) {
synchronized (replicationStartingListeners) {
replicationStartingListeners.remove(listener);
}
}
@Override
public void setReplicationStarting(boolean newReplicationStarting) {
if (this.replicationStarting != newReplicationStarting) {
this.replicationStarting = newReplicationStarting;
synchronized (replicationStartingListeners) {
for (final ReplicationStartingListener listener : replicationStartingListeners) {
listener.onReplicationStartingChanged(newReplicationStarting);
}
}
}
}
@Override
@@ -504,7 +504,7 @@ public class UserManagementServiceImpl extends RemoteServiceServlet implements U
public User call() throws Exception {
if (userGroupExists(username + SecurityService.TENANT_SUFFIX)) {
throw new UserManagementException(
"User tenant already exists, please chose a different username!");
"User "+username+" already exists, please chose a different username!");
}
try {
User newUser = getSecurityService().createSimpleUser(username, email, password, fullName,
@@ -381,7 +381,6 @@ public class AccessControlStoreImpl implements AccessControlStore {
public Iterable<OwnershipAnnotation> getOwnerships() {
return LockUtil.executeWithReadLockAndResult(lockForManagementMappings,
new RunnableWithResult<Iterable<OwnershipAnnotation>>() {
@Override
public Iterable<OwnershipAnnotation> run() {
return new ArrayList<>(ownerships.values());
@@ -392,7 +391,6 @@ public class AccessControlStoreImpl implements AccessControlStore {
@Override
public void clear() {
LockUtil.executeWithWriteLock(lockForManagementMappings, new Runnable() {
@Override
public void run() {
accessControlLists.clear();
@@ -171,7 +171,7 @@ public class SecurityServiceImpl implements ReplicableSecurityService, ClearStat
private Set<OperationWithResultWithIdWrapper<?, ?>> operationsSentToMasterForReplication;
private ThreadLocal<Boolean> currentlyFillingFromInitialLoad = ThreadLocal.withInitial(() -> false);
private volatile boolean currentlyFillingFromInitialLoad;
private ThreadLocal<Boolean> currentlyApplyingOperationReceivedFromMaster = ThreadLocal.withInitial(() -> false);
@@ -240,6 +240,8 @@ public class SecurityServiceImpl implements ReplicableSecurityService, ClearStat
AccessControlStore accessControlStore, HasPermissionsProvider hasPermissionsProvider,
String sharedAcrossSubdomainsOf, String baseUrlForCrossDomainStorage) {
logger.info("Initializing Security Service with user store " + userStore);
this.currentlyFillingFromInitialLoad = false;
this.currentlyFillingFromInitialLoad = false;
operationsSentToMasterForReplication = new HashSet<>();
this.sharedAcrossSubdomainsOf = sharedAcrossSubdomainsOf;
this.baseUrlForCrossDomainStorage = baseUrlForCrossDomainStorage;
@@ -288,12 +290,12 @@ public class SecurityServiceImpl implements ReplicableSecurityService, ClearStat
@Override
public boolean isCurrentlyFillingFromInitialLoad() {
return currentlyFillingFromInitialLoad.get();
return currentlyFillingFromInitialLoad;
}
@Override
public void setCurrentlyFillingFromInitialLoad(boolean currentlyFillingFromInitialLoad) {
this.currentlyFillingFromInitialLoad.set(currentlyFillingFromInitialLoad);
this.currentlyFillingFromInitialLoad = currentlyFillingFromInitialLoad;
}
@Override