mirror of
https://github.com/eclipse-sailing-analytics/sailing-analytics.git
synced 2026-09-22 21:55:39 +00:00
bug5374: introduced asynchronous background metadata update;
a few tests fail now, probably because the accelerated fix insertion leaves less time for actually committing the writes, and with write concern UNACKNOWLEDGED the client may not necessarily read its own writes. Should we introduce sleep times? Or is there a better way to have test cases wait for the completion also of unacknowledged writes?
This commit is contained in:
+151
@@ -0,0 +1,151 @@
|
||||
package com.sap.sailing.domain.persistence.racelog.tracking.impl;
|
||||
|
||||
import static com.sap.sailing.shared.persistence.impl.MongoObjectFactoryImpl.storeDeviceId;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import org.bson.Document;
|
||||
import org.bson.conversions.Bson;
|
||||
|
||||
import com.mongodb.WriteConcern;
|
||||
import com.mongodb.client.MongoCollection;
|
||||
import com.mongodb.client.model.Filters;
|
||||
import com.mongodb.client.model.UpdateOptions;
|
||||
import com.sap.sailing.domain.common.DeviceIdentifier;
|
||||
import com.sap.sailing.domain.common.racelog.tracking.TransformationException;
|
||||
import com.sap.sailing.domain.persistence.impl.DomainObjectFactoryImpl;
|
||||
import com.sap.sailing.domain.persistence.impl.FieldNames;
|
||||
import com.sap.sailing.domain.persistence.impl.MongoObjectFactoryImpl;
|
||||
import com.sap.sailing.domain.persistence.racelog.tracking.FixMongoHandler;
|
||||
import com.sap.sailing.shared.persistence.device.DeviceIdentifierMongoHandler;
|
||||
import com.sap.sse.common.NoCorrespondingServiceRegisteredException;
|
||||
import com.sap.sse.common.TimeRange;
|
||||
import com.sap.sse.common.Timed;
|
||||
import com.sap.sse.common.TypeBasedServiceFinder;
|
||||
|
||||
public class MetadataCollection extends MongoFixHandler {
|
||||
private static final Logger logger = Logger.getLogger(MetadataCollection.class.getName());
|
||||
private final MongoCollection<Document> metadataCollection;
|
||||
private final ConcurrentHashMap<DeviceIdentifier, MetadataUpdater> metadataUpdaters;
|
||||
|
||||
public MetadataCollection(MongoObjectFactoryImpl mongoOF,
|
||||
TypeBasedServiceFinder<FixMongoHandler<?>> fixServiceFinder,
|
||||
TypeBasedServiceFinder<DeviceIdentifierMongoHandler> deviceServiceFinder) {
|
||||
super(fixServiceFinder, deviceServiceFinder);
|
||||
this.metadataCollection = mongoOF.getGPSFixMetadataCollection();
|
||||
this.metadataUpdaters = new ConcurrentHashMap<>();
|
||||
}
|
||||
|
||||
/**
|
||||
* First {@link #waitForPendingMetadataUpdates(DeviceIdentifier) waits for any pending metadata updates},
|
||||
* then loads and returns them.
|
||||
*/
|
||||
private Document findMetadataObject(DeviceIdentifier device)
|
||||
throws TransformationException, NoCorrespondingServiceRegisteredException {
|
||||
waitForPendingMetadataUpdates(device);
|
||||
return findMetadataObjectInternal(device);
|
||||
}
|
||||
|
||||
/**
|
||||
* Doesn't {@link #waitForPendingMetadataUpdates(DeviceIdentifier) wait for pending updates} but obtains the
|
||||
* metadata object directly from the DB
|
||||
*/
|
||||
private Document findMetadataObjectInternal(DeviceIdentifier device) throws TransformationException {
|
||||
Bson query = getDeviceQuery(device);
|
||||
Document result = metadataCollection.find(query).first();
|
||||
return result;
|
||||
}
|
||||
|
||||
private Bson getDeviceQuery(DeviceIdentifier device)
|
||||
throws TransformationException, NoCorrespondingServiceRegisteredException {
|
||||
Document dbDeviceId = storeDeviceId(deviceServiceFinder, device);
|
||||
Bson query = Filters.eq(FieldNames.DEVICE_ID.name(), dbDeviceId);
|
||||
return query;
|
||||
}
|
||||
|
||||
TimeRange getTimeRangeCoveredByFixes(DeviceIdentifier device)
|
||||
throws TransformationException, NoCorrespondingServiceRegisteredException {
|
||||
final Document resultDocument = findMetadataObject(device);
|
||||
return getTimeRangeCoveredByFixesInternal(resultDocument);
|
||||
}
|
||||
|
||||
private TimeRange getTimeRangeCoveredByFixesInternal(DeviceIdentifier device) throws TransformationException {
|
||||
return getTimeRangeCoveredByFixesInternal(findMetadataObjectInternal(device));
|
||||
}
|
||||
|
||||
/**
|
||||
* Doesn't {@link #waitForPendingMetadataUpdates(DeviceIdentifier) wait for pending updates} but tells the current
|
||||
* status as loaded from the DB
|
||||
*/
|
||||
private TimeRange getTimeRangeCoveredByFixesInternal(final Document resultDocument) {
|
||||
final TimeRange result;
|
||||
if (resultDocument == null) {
|
||||
result = null;
|
||||
} else {
|
||||
result = DomainObjectFactoryImpl.loadTimeRange(resultDocument, FieldNames.TIMERANGE);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
long getNumberOfFixes(DeviceIdentifier device)
|
||||
throws TransformationException, NoCorrespondingServiceRegisteredException {
|
||||
final Document resultDocument = findMetadataObject(device);
|
||||
final long result;
|
||||
if (resultDocument == null) {
|
||||
result = 0;
|
||||
} else {
|
||||
result = ((Number) resultDocument.get(FieldNames.NUM_FIXES.name())).longValue();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
<FixT extends Timed> Map<DeviceIdentifier, FixT> getFixLastReceived(Iterable<DeviceIdentifier> forDevices)
|
||||
throws TransformationException, NoCorrespondingServiceRegisteredException {
|
||||
Map<DeviceIdentifier, FixT> result = new HashMap<>();
|
||||
for (final DeviceIdentifier deviceIdentifier : forDevices) {
|
||||
final Document metadataDoc = findMetadataObject(deviceIdentifier);
|
||||
if (metadataDoc != null) {
|
||||
final Document lastFixForDeviceDbObject = (Document) metadataDoc.get(FieldNames.LAST_FIX_RECEIVED.name());
|
||||
if (lastFixForDeviceDbObject != null) {
|
||||
final Timed lastFixForDevice = loadFix(lastFixForDeviceDbObject);
|
||||
@SuppressWarnings("unchecked")
|
||||
final FixT lastFixForDeviceTyped = (FixT) lastFixForDevice;
|
||||
result.put(deviceIdentifier, lastFixForDeviceTyped);
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
<FixT extends Timed> void enqueueMetadataUpdate(DeviceIdentifier device, final Object dbDeviceId,
|
||||
final int nrOfTotalFixes, TimeRange fixesTimeRange, FixT latestFix) throws TransformationException {
|
||||
final MetadataUpdater metadataUpdaterForDevice = metadataUpdaters.computeIfAbsent(device, d->new MetadataUpdater(this, device));
|
||||
metadataUpdaterForDevice.enqueueMetadataUpdate(device, dbDeviceId, nrOfTotalFixes, fixesTimeRange, latestFix);
|
||||
}
|
||||
|
||||
private void waitForPendingMetadataUpdates(DeviceIdentifier device) {
|
||||
final MetadataUpdater metadataUpdaterForDevice = metadataUpdaters.get(device);
|
||||
if (metadataUpdaterForDevice != null) {
|
||||
metadataUpdaterForDevice.waitForPendingUpdates();
|
||||
}
|
||||
}
|
||||
|
||||
<FixT extends Timed> void update(MetadataUpdate<FixT> update) throws TransformationException, NoCorrespondingServiceRegisteredException {
|
||||
logger.fine(()->"Updating sensor fix store metadata with "+update);
|
||||
final TimeRange oldTimeRange = getTimeRangeCoveredByFixesInternal(update.getDevice());
|
||||
final TimeRange newTimeRange = oldTimeRange == null ? update.getFixesTimeRange() : update.getFixesTimeRange() == null ? oldTimeRange : oldTimeRange.extend(update.getFixesTimeRange());
|
||||
final Document updateOperation = new Document();
|
||||
final Document newMetadata = new Document();
|
||||
newMetadata.put(FieldNames.DEVICE_ID.name(), update.getDbDeviceId());
|
||||
if (update.getLatestFix() != null) {
|
||||
newMetadata.put(FieldNames.LAST_FIX_RECEIVED.name(), storeFixToDocument(new Document(), update.getLatestFix()));
|
||||
}
|
||||
MongoObjectFactoryImpl.storeTimeRange(newTimeRange, newMetadata, FieldNames.TIMERANGE);
|
||||
updateOperation.append("$set", newMetadata);
|
||||
updateOperation.append("$inc", new Document(FieldNames.NUM_FIXES.name(), update.getNrOfTotalFixes()));
|
||||
metadataCollection.withWriteConcern(WriteConcern.UNACKNOWLEDGED).updateOne(getDeviceQuery(update.getDevice()), updateOperation, new UpdateOptions().upsert(true));
|
||||
}
|
||||
}
|
||||
+65
@@ -0,0 +1,65 @@
|
||||
package com.sap.sailing.domain.persistence.racelog.tracking.impl;
|
||||
|
||||
import com.sap.sailing.domain.common.DeviceIdentifier;
|
||||
import com.sap.sse.common.TimeRange;
|
||||
import com.sap.sse.common.Timed;
|
||||
|
||||
public class MetadataUpdate<FixT extends Timed> {
|
||||
private final DeviceIdentifier device;
|
||||
private final Object dbDeviceId;
|
||||
private final int nrOfTotalFixes;
|
||||
private final TimeRange fixesTimeRange;
|
||||
private final FixT latestFix;
|
||||
|
||||
public MetadataUpdate(DeviceIdentifier device, Object dbDeviceId, int nrOfTotalFixes, TimeRange fixesTimeRange,
|
||||
FixT latestFix) {
|
||||
super();
|
||||
this.device = device;
|
||||
this.dbDeviceId = dbDeviceId;
|
||||
this.nrOfTotalFixes = nrOfTotalFixes;
|
||||
this.fixesTimeRange = fixesTimeRange;
|
||||
this.latestFix = latestFix;
|
||||
}
|
||||
|
||||
public DeviceIdentifier getDevice() {
|
||||
return device;
|
||||
}
|
||||
|
||||
public Object getDbDeviceId() {
|
||||
return dbDeviceId;
|
||||
}
|
||||
|
||||
public int getNrOfTotalFixes() {
|
||||
return nrOfTotalFixes;
|
||||
}
|
||||
|
||||
public TimeRange getFixesTimeRange() {
|
||||
return fixesTimeRange;
|
||||
}
|
||||
|
||||
public FixT getLatestFix() {
|
||||
return latestFix;
|
||||
}
|
||||
|
||||
public MetadataUpdate<FixT> merge(MetadataUpdate<FixT> other) {
|
||||
final MetadataUpdate<FixT> result;
|
||||
if (other == null) {
|
||||
result = this;
|
||||
} else {
|
||||
if (!other.getDevice().equals(getDevice())) {
|
||||
throw new IllegalArgumentException("Can only merge metadata updates for the same device: "+getDevice()+" vs. "+other.getDevice());
|
||||
}
|
||||
result = new MetadataUpdate<FixT>(getDevice(), getDbDeviceId(),
|
||||
getNrOfTotalFixes() + other.getNrOfTotalFixes(),
|
||||
getFixesTimeRange().extend(other.getFixesTimeRange()),
|
||||
other.getLatestFix());
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "MetadataUpdate [device=" + device + ", dbDeviceId=" + dbDeviceId + ", nrOfTotalFixes=" + nrOfTotalFixes
|
||||
+ ", fixesTimeRange=" + fixesTimeRange + ", latestFix=" + latestFix + "]";
|
||||
}
|
||||
}
|
||||
+110
@@ -0,0 +1,110 @@
|
||||
package com.sap.sailing.domain.persistence.racelog.tracking.impl;
|
||||
|
||||
import java.util.concurrent.Callable;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.Future;
|
||||
import java.util.concurrent.ScheduledExecutorService;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import com.sap.sailing.domain.common.DeviceIdentifier;
|
||||
import com.sap.sailing.domain.common.racelog.tracking.TransformationException;
|
||||
import com.sap.sse.common.TimeRange;
|
||||
import com.sap.sse.common.Timed;
|
||||
import com.sap.sse.util.ThreadPoolUtil;
|
||||
|
||||
public class MetadataUpdater {
|
||||
private static final Logger logger = Logger.getLogger(MetadataUpdater.class.getName());
|
||||
private final ScheduledExecutorService executor;
|
||||
private final DeviceIdentifier forDevice;
|
||||
private final MetadataCollection metadataCollection;
|
||||
private Future<?> runningUpdate;
|
||||
private MetadataUpdate<?> nextUpdate;
|
||||
|
||||
MetadataUpdater(ScheduledExecutorService executor, MetadataCollection metadataCollection, DeviceIdentifier forDevice) {
|
||||
super();
|
||||
this.executor = executor;
|
||||
this.metadataCollection = metadataCollection;
|
||||
this.forDevice = forDevice;
|
||||
}
|
||||
|
||||
/**
|
||||
* Uses the {@link ThreadPoolUtil#getDefaultBackgroundTaskThreadPoolExecutor() default background thread pool
|
||||
* executor} for updating the metadata.
|
||||
*
|
||||
* @param forDevice
|
||||
* used to validate the constraint that all updates delivered to this updater must be for that device
|
||||
*/
|
||||
MetadataUpdater(MetadataCollection metadataCollection, DeviceIdentifier forDevice) {
|
||||
this(ThreadPoolUtil.INSTANCE.getDefaultBackgroundTaskThreadPoolExecutor(), metadataCollection, forDevice);
|
||||
}
|
||||
|
||||
synchronized <FixT extends Timed> void enqueueMetadataUpdate(DeviceIdentifier device, final Object dbDeviceId,
|
||||
final int nrOfTotalFixes, TimeRange fixesTimeRange, FixT latestFix) throws TransformationException {
|
||||
final MetadataUpdate<FixT> update = new MetadataUpdate<>(device, dbDeviceId, nrOfTotalFixes, fixesTimeRange, latestFix);
|
||||
if (runningUpdate == null) {
|
||||
setNextUpdate(update);
|
||||
scheduleUpdate();
|
||||
} else {
|
||||
if (getNextUpdate() == null) {
|
||||
setNextUpdate(update);
|
||||
} else {
|
||||
final MetadataUpdate<FixT> theNextUpdate = getNextUpdate();
|
||||
setNextUpdate(theNextUpdate.merge(update));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Schedules a task that under this object's monitor ({@code synchronized}) obtains the {@link #getNextUpdate() next update}
|
||||
* and if one is found, {@link MetadataCollection#update(MetadataUpdate) updates} the MongoDB metadata collection accordingly.
|
||||
* Before terminating, this object's monitor is acquired again, and if then another {@link #getNextUpdate() next update} is
|
||||
* found, it is applied again; otherwise, the task ends.
|
||||
*/
|
||||
private synchronized <FixT extends Timed> void scheduleUpdate() {
|
||||
assert runningUpdate == null;
|
||||
runningUpdate = executor.submit((Callable<Void>) ()->{
|
||||
MetadataUpdate<FixT> theNextUpdate;
|
||||
logger.fine(()->"Starting metadata updater task for device "+forDevice);
|
||||
do {
|
||||
synchronized (MetadataUpdater.this) {
|
||||
theNextUpdate = getNextUpdate();
|
||||
if (theNextUpdate == null) {
|
||||
runningUpdate = null;
|
||||
} else {
|
||||
setNextUpdate(null);
|
||||
}
|
||||
}
|
||||
if (theNextUpdate != null) {
|
||||
metadataCollection.update(theNextUpdate);
|
||||
}
|
||||
} while (theNextUpdate != null);
|
||||
logger.fine(()->"Terminating metadata updater task for device "+forDevice);
|
||||
return null;
|
||||
});
|
||||
}
|
||||
|
||||
private <FixT extends Timed> void setNextUpdate(MetadataUpdate<FixT> update) {
|
||||
assert update == null || update.getDevice().equals(forDevice);
|
||||
nextUpdate = update;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private synchronized <FixT extends Timed> MetadataUpdate<FixT> getNextUpdate() {
|
||||
return (MetadataUpdate<FixT>) nextUpdate;
|
||||
}
|
||||
|
||||
void waitForPendingUpdates() {
|
||||
final Future<?> theRunningUpdate;
|
||||
synchronized (this) {
|
||||
theRunningUpdate = runningUpdate;
|
||||
}
|
||||
if (theRunningUpdate != null) {
|
||||
try {
|
||||
theRunningUpdate.get();
|
||||
} catch (InterruptedException | ExecutionException e) {
|
||||
logger.log(Level.INFO, "Exception waiting for pending metadata updates", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+63
@@ -0,0 +1,63 @@
|
||||
package com.sap.sailing.domain.persistence.racelog.tracking.impl;
|
||||
|
||||
import org.bson.Document;
|
||||
|
||||
import com.sap.sailing.domain.common.racelog.tracking.TransformationException;
|
||||
import com.sap.sailing.domain.persistence.impl.FieldNames;
|
||||
import com.sap.sailing.domain.persistence.racelog.tracking.FixMongoHandler;
|
||||
import com.sap.sailing.shared.persistence.device.DeviceIdentifierMongoHandler;
|
||||
import com.sap.sse.common.NoCorrespondingServiceRegisteredException;
|
||||
import com.sap.sse.common.Timed;
|
||||
import com.sap.sse.common.TypeBasedServiceFinder;
|
||||
|
||||
abstract class MongoFixHandler {
|
||||
protected final TypeBasedServiceFinder<FixMongoHandler<?>> fixServiceFinder;
|
||||
protected final TypeBasedServiceFinder<DeviceIdentifierMongoHandler> deviceServiceFinder;
|
||||
|
||||
public MongoFixHandler(TypeBasedServiceFinder<FixMongoHandler<?>> fixServiceFinder,
|
||||
TypeBasedServiceFinder<DeviceIdentifierMongoHandler> deviceServiceFinder) {
|
||||
super();
|
||||
this.fixServiceFinder = fixServiceFinder;
|
||||
this.deviceServiceFinder = deviceServiceFinder;
|
||||
}
|
||||
|
||||
/**
|
||||
* Try to find a service implementing specified type of objects interface using the {@link #fixServiceFinder}.
|
||||
* <p>
|
||||
* To support an additional fix type, an implementation of {@link FixMongoHandler} is required, which specifies how
|
||||
* to transform a fix forth to and back from database. This implementation needs to be registered during OSGi bundle
|
||||
* activator startup, providing respective type mapping properties.
|
||||
* </p>
|
||||
*
|
||||
* @param type
|
||||
* type object to find service for
|
||||
* @return the registered {@link FixMongoHandler} implementation
|
||||
*
|
||||
* @see TypeBasedServiceFinder#findService(String)
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
protected <FixT extends Timed> FixMongoHandler<FixT> findService(String type) {
|
||||
return (FixMongoHandler<FixT>) fixServiceFinder.findService(type);
|
||||
}
|
||||
|
||||
protected <T extends Timed> T loadFix(Document object)
|
||||
throws TransformationException, NoCorrespondingServiceRegisteredException {
|
||||
String type = (String) object.get(FieldNames.GPSFIX_TYPE.name());
|
||||
Document fixObject = (Document) object.get(FieldNames.GPSFIX.name());
|
||||
return this.<T> findService(type).transformBack(fixObject);
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes the {@code fix} to the {@code entry} document such that {@link #loadFix(Document)} can re-establish
|
||||
* the fix from that document.
|
||||
*
|
||||
* @return for convenience and call chaining, the updated {@code entry} is returned
|
||||
*/
|
||||
protected <FixT extends Timed> Document storeFixToDocument(Document entry, FixT fix) throws TransformationException {
|
||||
String type = fix.getClass().getName();
|
||||
FixMongoHandler<FixT> mongoHandler = findService(type);
|
||||
Object fixObject = mongoHandler.transformForth(fix);
|
||||
entry.append(FieldNames.GPSFIX_TYPE.name(), type).append(FieldNames.GPSFIX.name(), fixObject);
|
||||
return entry;
|
||||
}
|
||||
}
|
||||
+17
-114
@@ -21,13 +21,11 @@ import com.mongodb.WriteConcern;
|
||||
import com.mongodb.client.FindIterable;
|
||||
import com.mongodb.client.MongoCollection;
|
||||
import com.mongodb.client.model.Filters;
|
||||
import com.mongodb.client.model.UpdateOptions;
|
||||
import com.sap.sailing.domain.common.DeviceIdentifier;
|
||||
import com.sap.sailing.domain.common.RegattaAndRaceIdentifier;
|
||||
import com.sap.sailing.domain.common.racelog.tracking.TransformationException;
|
||||
import com.sap.sailing.domain.persistence.DomainObjectFactory;
|
||||
import com.sap.sailing.domain.persistence.MongoObjectFactory;
|
||||
import com.sap.sailing.domain.persistence.impl.DomainObjectFactoryImpl;
|
||||
import com.sap.sailing.domain.persistence.impl.FieldNames;
|
||||
import com.sap.sailing.domain.persistence.impl.MongoObjectFactoryImpl;
|
||||
import com.sap.sailing.domain.persistence.racelog.tracking.FixMongoHandler;
|
||||
@@ -54,13 +52,12 @@ import com.sap.sse.concurrent.NamedReentrantReadWriteLock;
|
||||
* @author Fredrik Teschke
|
||||
*
|
||||
*/
|
||||
public class MongoSensorFixStoreImpl implements MongoSensorFixStore {
|
||||
public class MongoSensorFixStoreImpl extends MongoFixHandler implements MongoSensorFixStore {
|
||||
private static final Logger logger = Logger.getLogger(MongoSensorFixStoreImpl.class.getName());
|
||||
private final TypeBasedServiceFinder<FixMongoHandler<?>> fixServiceFinder;
|
||||
private final TypeBasedServiceFinder<DeviceIdentifierMongoHandler> deviceServiceFinder;
|
||||
private final MongoCollection<Document> fixesCollection;
|
||||
private final MongoCollection<Document> metadataCollection;
|
||||
private final MetadataCollection metadataCollection;
|
||||
private final MongoObjectFactoryImpl mongoOF;
|
||||
|
||||
/**
|
||||
* Lock object to be used when accessing {@link #listeners}.
|
||||
*/
|
||||
@@ -69,32 +66,19 @@ public class MongoSensorFixStoreImpl implements MongoSensorFixStore {
|
||||
|
||||
public MongoSensorFixStoreImpl(MongoObjectFactory mongoObjectFactory, DomainObjectFactory domainObjectFactory,
|
||||
TypeBasedServiceFinderFactory serviceFinderFactory) {
|
||||
super(serviceFinderFactory != null ? createFixServiceFinder(serviceFinderFactory) : null,
|
||||
serviceFinderFactory != null ? serviceFinderFactory.createServiceFinder(DeviceIdentifierMongoHandler.class) : null);
|
||||
mongoOF = (MongoObjectFactoryImpl) mongoObjectFactory;
|
||||
if (serviceFinderFactory != null) {
|
||||
fixServiceFinder = createFixServiceFinder(serviceFinderFactory);
|
||||
deviceServiceFinder = serviceFinderFactory.createServiceFinder(DeviceIdentifierMongoHandler.class);
|
||||
} else {
|
||||
fixServiceFinder = null;
|
||||
deviceServiceFinder = null;
|
||||
}
|
||||
fixesCollection = mongoOF.getGPSFixCollection();
|
||||
metadataCollection = mongoOF.getGPSFixMetadataCollection();
|
||||
|
||||
metadataCollection = new MetadataCollection(mongoOF, fixServiceFinder, deviceServiceFinder);
|
||||
}
|
||||
|
||||
@SuppressWarnings({ "rawtypes", "unchecked" })
|
||||
private TypeBasedServiceFinder<FixMongoHandler<?>> createFixServiceFinder(
|
||||
private static TypeBasedServiceFinder<FixMongoHandler<?>> createFixServiceFinder(
|
||||
TypeBasedServiceFinderFactory serviceFinderFactory) {
|
||||
return (TypeBasedServiceFinder) serviceFinderFactory.createServiceFinder(FixMongoHandler.class);
|
||||
}
|
||||
|
||||
private <T extends Timed> T loadFix(Document object)
|
||||
throws TransformationException, NoCorrespondingServiceRegisteredException {
|
||||
String type = (String) object.get(FieldNames.GPSFIX_TYPE.name());
|
||||
Document fixObject = (Document) object.get(FieldNames.GPSFIX.name());
|
||||
return this.<T> findService(type).transformBack(fixObject);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <FixT extends Timed> boolean loadOldestFix(Consumer<FixT> consumer, DeviceIdentifier device, TimeRange timeRangeToLoad) throws NoCorrespondingServiceRegisteredException, TransformationException {
|
||||
return loadFixes(consumer, device, timeRangeToLoad.from(), timeRangeToLoad.to(), false, () -> false, (d) -> {
|
||||
@@ -199,8 +183,7 @@ public class MongoSensorFixStoreImpl implements MongoSensorFixStore {
|
||||
final Object dbDeviceId = storeDeviceId(deviceServiceFinder, device);
|
||||
final int nrOfTotalFixes = Util.size(fixes);
|
||||
final ArrayList<Document> dbFixes = new ArrayList<>(nrOfTotalFixes);
|
||||
final TimeRange oldTimeRange = getTimeRangeCoveredByFixes(device);
|
||||
TimeRange newTimeRange = oldTimeRange;
|
||||
TimeRange newTimeRange = null;
|
||||
FixT latestFix = null;
|
||||
for (FixT fix : fixes) {
|
||||
if (latestFix == null || latestFix.getTimePoint().before(fix.getTimePoint())) {
|
||||
@@ -215,39 +198,15 @@ public class MongoSensorFixStoreImpl implements MongoSensorFixStore {
|
||||
newTimeRange = newTimeRange == null ? fixTimeRange : newTimeRange.extend(fixTimeRange);
|
||||
}
|
||||
fixesCollection.withWriteConcern(WriteConcern.UNACKNOWLEDGED).insertMany(dbFixes);
|
||||
final Document updateOperation = new Document();
|
||||
final Document newMetadata = new Document();
|
||||
newMetadata.put(FieldNames.DEVICE_ID.name(), dbDeviceId);
|
||||
if (latestFix != null) {
|
||||
newMetadata.put(FieldNames.LAST_FIX_RECEIVED.name(), storeFixToDocument(new Document(), latestFix));
|
||||
}
|
||||
MongoObjectFactoryImpl.storeTimeRange(newTimeRange, newMetadata, FieldNames.TIMERANGE);
|
||||
updateOperation.append("$set", newMetadata);
|
||||
updateOperation.append("$inc", new Document(FieldNames.NUM_FIXES.name(), nrOfTotalFixes));
|
||||
metadataCollection.withWriteConcern(WriteConcern.UNACKNOWLEDGED).updateOne(getDeviceQuery(device), updateOperation, new UpdateOptions().upsert(true));
|
||||
metadataCollection.enqueueMetadataUpdate(device, dbDeviceId, nrOfTotalFixes, newTimeRange, latestFix);
|
||||
} catch (TransformationException e) {
|
||||
logger.log(Level.WARNING, "Could not store fix in MongoDB");
|
||||
e.printStackTrace();
|
||||
logger.log(Level.WARNING, "Could not store fix in MongoDB", e);
|
||||
}
|
||||
Util.addAll(notifyListeners(device, fixes, returnManeuverChanges, returnLiveDelay), racesWithManeuverChangesOrLiveDelay);
|
||||
}
|
||||
return racesWithManeuverChangesOrLiveDelay;
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes the {@code fix} to the {@code entry} document such that {@link #loadFix(Document)} can re-establish
|
||||
* the fix from that document.
|
||||
*
|
||||
* @return for convenience and call chaining, the updated {@code entry} is returned
|
||||
*/
|
||||
private <FixT extends Timed> Document storeFixToDocument(Document entry, FixT fix) throws TransformationException {
|
||||
String type = fix.getClass().getName();
|
||||
FixMongoHandler<FixT> mongoHandler = findService(type);
|
||||
Object fixObject = mongoHandler.transformForth(fix);
|
||||
entry.append(FieldNames.GPSFIX_TYPE.name(), type).append(FieldNames.GPSFIX.name(), fixObject);
|
||||
return entry;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <FixT extends Timed> void storeFix(DeviceIdentifier device, FixT fix) {
|
||||
storeFixes(device, Collections.singletonList(fix), /* returnManeuverUpdate */ false, /* returnLiveDelay */ false);
|
||||
@@ -286,81 +245,25 @@ public class MongoSensorFixStoreImpl implements MongoSensorFixStore {
|
||||
LockUtil.executeWithWriteLock(listenersLock, () -> Util.removeFromValueSet(listeners, device, listener));
|
||||
}
|
||||
|
||||
private Bson getDeviceQuery(DeviceIdentifier device)
|
||||
throws TransformationException, NoCorrespondingServiceRegisteredException {
|
||||
Document dbDeviceId = storeDeviceId(deviceServiceFinder, device);
|
||||
Bson query = Filters.eq(FieldNames.DEVICE_ID.name(), dbDeviceId);
|
||||
return query;
|
||||
}
|
||||
|
||||
private Document findMetadataObject(DeviceIdentifier device)
|
||||
throws TransformationException, NoCorrespondingServiceRegisteredException {
|
||||
Bson query = getDeviceQuery(device);
|
||||
Document result = metadataCollection.find(query).first();
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TimeRange getTimeRangeCoveredByFixes(DeviceIdentifier device)
|
||||
throws TransformationException, NoCorrespondingServiceRegisteredException {
|
||||
final Document resultDocument = findMetadataObject(device);
|
||||
final TimeRange result;
|
||||
if (resultDocument == null) {
|
||||
result = null;
|
||||
} else {
|
||||
result = DomainObjectFactoryImpl.loadTimeRange(resultDocument, FieldNames.TIMERANGE);
|
||||
}
|
||||
return result;
|
||||
return getMetadataCollection().getTimeRangeCoveredByFixes(device);
|
||||
}
|
||||
|
||||
private MetadataCollection getMetadataCollection() {
|
||||
return metadataCollection;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getNumberOfFixes(DeviceIdentifier device)
|
||||
throws TransformationException, NoCorrespondingServiceRegisteredException {
|
||||
final Document resultDocument = findMetadataObject(device);
|
||||
final long result;
|
||||
if (resultDocument == null) {
|
||||
result = 0;
|
||||
} else {
|
||||
result = ((Number) resultDocument.get(FieldNames.NUM_FIXES.name())).longValue();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Try to find a service implementing specified type of objects interface using the {@link #fixServiceFinder}.
|
||||
* <p>
|
||||
* To support an additional fix type, an implementation of {@link FixMongoHandler} is required, which specifies how
|
||||
* to transform a fix forth to and back from database. This implementation needs to be registered during OSGi bundle
|
||||
* activator startup, providing respective type mapping properties.
|
||||
* </p>
|
||||
*
|
||||
* @param type
|
||||
* type object to find service for
|
||||
* @return the registered {@link FixMongoHandler} implementation
|
||||
*
|
||||
* @see TypeBasedServiceFinder#findService(String)
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
private <FixT extends Timed> FixMongoHandler<FixT> findService(String type) {
|
||||
return (FixMongoHandler<FixT>) fixServiceFinder.findService(type);
|
||||
return metadataCollection.getNumberOfFixes(device);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <FixT extends Timed> Map<DeviceIdentifier, FixT> getFixLastReceived(Iterable<DeviceIdentifier> forDevices)
|
||||
throws TransformationException, NoCorrespondingServiceRegisteredException {
|
||||
Map<DeviceIdentifier, FixT> result = new HashMap<>();
|
||||
for (final DeviceIdentifier deviceIdentifier : forDevices) {
|
||||
final Document metadataDoc = findMetadataObject(deviceIdentifier);
|
||||
if (metadataDoc != null) {
|
||||
final Document lastFixForDeviceDbObject = (Document) metadataDoc.get(FieldNames.LAST_FIX_RECEIVED.name());
|
||||
if (lastFixForDeviceDbObject != null) {
|
||||
final Timed lastFixForDevice = loadFix(lastFixForDeviceDbObject);
|
||||
@SuppressWarnings("unchecked")
|
||||
final FixT lastFixForDeviceTyped = (FixT) lastFixForDevice;
|
||||
result.put(deviceIdentifier, lastFixForDeviceTyped);
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
return metadataCollection.getFixLastReceived(forDevices);
|
||||
}
|
||||
}
|
||||
|
||||
-3
@@ -150,12 +150,9 @@ public class SensorFixStoreAndLoadTest {
|
||||
raceLog = new RaceLogImpl("racelog");
|
||||
raceLog.add(new RaceLogStartOfTrackingEventImpl(new MillisecondsTimePoint(START_OF_TRACKING), author, 0));
|
||||
raceLog.add(new RaceLogEndOfTrackingEventImpl(new MillisecondsTimePoint(END_OF_TRACKING), author, 0));
|
||||
|
||||
regattaLog = new RegattaLogImpl("regattalog");
|
||||
|
||||
store = new MongoSensorFixStoreImpl(PersistenceFactory.INSTANCE.getDefaultMongoObjectFactory(),
|
||||
PersistenceFactory.INSTANCE.getDefaultDomainObjectFactory(), serviceFinderFactory);
|
||||
|
||||
regattaLog.add(new RegattaLogDefineMarkEventImpl(new MillisecondsTimePoint(1), author,
|
||||
new MillisecondsTimePoint(1), 0, mark));
|
||||
regattaLog.add(new RegattaLogDefineMarkEventImpl(new MillisecondsTimePoint(2), author,
|
||||
|
||||
-1
@@ -348,7 +348,6 @@ public class SensorFixStoreTest {
|
||||
private List<Timed> loadFixes(long start, long end, DeviceIdentifier device, boolean endIsInclusive)
|
||||
throws TransformationException {
|
||||
List<Timed> loadedFixes = new ArrayList<>();
|
||||
|
||||
store.loadFixes(loadedFixes::add, device, new MillisecondsTimePoint(start), new MillisecondsTimePoint(end), endIsInclusive);
|
||||
return loadedFixes;
|
||||
}
|
||||
|
||||
@@ -33,38 +33,67 @@
|
||||
<stringAttribute key="profilingTraceType-PERFORMANCE_HOTSPOT_TRACE" value="KEY_IGNORE_SLEEPING_THREADS%CTX_KEY%false%CTX_ENTRY%KEY_APPLICATION_FILTER%CTX_KEY%*%CTX_ENTRY%KEY_SESSION_FILTER%CTX_KEY%*%CTX_ENTRY%KEY_ENABLEMENT%CTX_KEY%true%CTX_ENTRY%KEY_USER_FILTER%CTX_KEY%*%CTX_ENTRY%KEY_REQUEST_FILTER%CTX_KEY%*%CTX_ENTRY%KEY_TENANT_FILTER%CTX_KEY%*%CTX_ENTRY%"/>
|
||||
<stringAttribute key="profilingTraceType-SYNCHRONIZATION_TRACE" value="KEY_APPLICATION_FILTER%CTX_KEY%*%CTX_ENTRY%KEY_SESSION_FILTER%CTX_KEY%*%CTX_ENTRY%KEY_ENABLEMENT%CTX_KEY%false%CTX_ENTRY%KEY_USER_FILTER%CTX_KEY%*%CTX_ENTRY%KEY_REQUEST_FILTER%CTX_KEY%*%CTX_ENTRY%KEY_TENANT_FILTER%CTX_KEY%*%CTX_ENTRY%"/>
|
||||
<setAttribute key="selected_target_bundles">
|
||||
<setEntry value="routeconverter@default:default"/>
|
||||
<setEntry value="org.apache.commons.codec@default:default"/>
|
||||
<setEntry value="org.apache.poi@default:default"/>
|
||||
<setEntry value="org.apache.poi.ooxml@default:default"/>
|
||||
<setEntry value="org.apache.poi.ooxml.schemas@default:default"/>
|
||||
<setEntry value="org.dom4j@default:default"/>
|
||||
<setEntry value="org.apache.xmlbeans@default:default"/>
|
||||
<setEntry value="org.apache.commons.math@default:default"/>
|
||||
<setEntry value="org.apache.httpcomponents.httpclient@default:default"/>
|
||||
<setEntry value="org.apache.httpcomponents.httpcore@default:default"/>
|
||||
<setEntry value="org.objectweb.asm@default:default"/>
|
||||
<setEntry value="org.hyperic.sigar@default:default"/>
|
||||
<setEntry value="com.amazon.aws.aws-java-api@default:default"/>
|
||||
<setEntry value="com.fasterxml.jackson.core.jackson-annotations@default:default"/>
|
||||
<setEntry value="com.fasterxml.jackson.core.jackson-core@default:default"/>
|
||||
<setEntry value="com.fasterxml.jackson.core.jackson-databind@default:default"/>
|
||||
<setEntry value="com.jcraft.jsch@default:default"/>
|
||||
<setEntry value="com.rabbitmq.client@default:default"/>
|
||||
<setEntry value="com.sun.activation.javax.activation@default:default"/>
|
||||
<setEntry value="com.sun.istack.commons-runtime@default:default"/>
|
||||
<setEntry value="com.sun.jersey.contribs.jersey-multipart@default:default"/>
|
||||
<setEntry value="javax.validation@default:default"/>
|
||||
<setEntry value="org.apache.commons.fileupload@default:default"/>
|
||||
<setEntry value="org.jdom@default:default"/>
|
||||
<setEntry value="org.jvnet.mimepull@default:default"/>
|
||||
<setEntry value="org.apache.commons.math3@default:default"/>
|
||||
<setEntry value="org.mongodb.mongo-java-driver@default:default"/>
|
||||
<setEntry value="org.eclipse.jetty.osgi.boot@3:true"/>
|
||||
<setEntry value="slf4j.jdk14@default:default"/>
|
||||
<setEntry value="org.apache.felix.shell@0:true"/>
|
||||
<setEntry value="org.apache.felix.shell.remote@0:true"/>
|
||||
<setEntry value="lz4-java@default:default"/>
|
||||
<setEntry value="com.sun.jersey@default:default"/>
|
||||
<setEntry value="com.sun.mail.javax.mail@default:default"/>
|
||||
<setEntry value="com.sun.xml.bind.jaxb-impl@default:default"/>
|
||||
<setEntry value="jackson-core-asl@default:default"/>
|
||||
<setEntry value="jackson-jaxrs@default:default"/>
|
||||
<setEntry value="jackson-mapper-asl@default:default"/>
|
||||
<setEntry value="javax.servlet@default:default"/>
|
||||
<setEntry value="javax.validation@default:default"/>
|
||||
<setEntry value="javax.ws.rs@default:default"/>
|
||||
<setEntry value="javax.xml.stream@default:default"/>
|
||||
<setEntry value="javax.xml.ws@default:default"/>
|
||||
<setEntry value="javax.xml@default:default"/>
|
||||
<setEntry value="jaxb-api@default:default"/>
|
||||
<setEntry value="jcl.over.slf4j@default:default"/>
|
||||
<setEntry value="lz4-java@default:default"/>
|
||||
<setEntry value="org.apache.commons.beanutils@default:default"/>
|
||||
<setEntry value="org.apache.commons.codec@default:default"/>
|
||||
<setEntry value="org.apache.commons.collections@default:default"/>
|
||||
<setEntry value="org.apache.commons.fileupload@default:default"/>
|
||||
<setEntry value="org.apache.commons.io@default:default"/>
|
||||
<setEntry value="org.apache.commons.lang@default:default"/>
|
||||
<setEntry value="org.apache.commons.math3@default:default"/>
|
||||
<setEntry value="org.apache.commons.math@default:default"/>
|
||||
<setEntry value="org.apache.felix.gogo.command@default:default"/>
|
||||
<setEntry value="org.apache.felix.gogo.runtime@default:default"/>
|
||||
<setEntry value="org.apache.felix.gogo.shell@default:default"/>
|
||||
<setEntry value="org.apache.felix.shell.remote@0:true"/>
|
||||
<setEntry value="org.apache.felix.shell@0:true"/>
|
||||
<setEntry value="org.apache.httpcomponents.httpclient@default:default"/>
|
||||
<setEntry value="org.apache.httpcomponents.httpcore@default:default"/>
|
||||
<setEntry value="org.apache.poi.ooxml.schemas@default:default"/>
|
||||
<setEntry value="org.apache.poi.ooxml@default:default"/>
|
||||
<setEntry value="org.apache.poi@default:default"/>
|
||||
<setEntry value="org.apache.servicemix.bundles.ehcache@default:default"/>
|
||||
<setEntry value="org.apache.servicemix.bundles.scribe@default:default"/>
|
||||
<setEntry value="org.apache.servicemix.bundles.zxing@default:default"/>
|
||||
<setEntry value="org.apache.shiro.core@default:default"/>
|
||||
<setEntry value="org.apache.shiro.ehcache@default:default"/>
|
||||
<setEntry value="org.apache.shiro.web@default:default"/>
|
||||
<setEntry value="org.apache.xmlbeans@default:default"/>
|
||||
<setEntry value="org.dom4j@default:default"/>
|
||||
<setEntry value="org.eclipse.equinox.cm@default:default"/>
|
||||
<setEntry value="org.eclipse.equinox.common@2:true"/>
|
||||
<setEntry value="org.eclipse.equinox.console@default:default"/>
|
||||
<setEntry value="org.eclipse.equinox.launcher@default:default"/>
|
||||
<setEntry value="org.eclipse.equinox.simpleconfigurator@2:true"/>
|
||||
<setEntry value="org.eclipse.jetty.client@default:default"/>
|
||||
<setEntry value="org.eclipse.jetty.deploy@4:true"/>
|
||||
<setEntry value="org.eclipse.jetty.http@4:true"/>
|
||||
<setEntry value="org.eclipse.jetty.io@4:true"/>
|
||||
<setEntry value="org.eclipse.jetty.jmx@4:true"/>
|
||||
<setEntry value="org.eclipse.jetty.osgi.boot@3:true"/>
|
||||
<setEntry value="org.eclipse.jetty.security@4:true"/>
|
||||
<setEntry value="org.eclipse.jetty.server@4:true"/>
|
||||
<setEntry value="org.eclipse.jetty.servlet@4:true"/>
|
||||
@@ -74,149 +103,118 @@
|
||||
<setEntry value="org.eclipse.jetty.websocket.client@default:default"/>
|
||||
<setEntry value="org.eclipse.jetty.websocket.common@default:default"/>
|
||||
<setEntry value="org.eclipse.jetty.xml@4:true"/>
|
||||
<setEntry value="slf4j.api@default:default"/>
|
||||
<setEntry value="org.apache.servicemix.bundles.zxing@default:default"/>
|
||||
<setEntry value="com.fasterxml.jackson.core.jackson-annotations@default:default"/>
|
||||
<setEntry value="com.fasterxml.jackson.core.jackson-core@default:default"/>
|
||||
<setEntry value="com.fasterxml.jackson.core.jackson-databind@default:default"/>
|
||||
<setEntry value="org.apache.commons.io@default:default"/>
|
||||
<setEntry value="jcl.over.slf4j@default:default"/>
|
||||
<setEntry value="com.sun.mail.javax.mail@default:default"/>
|
||||
<setEntry value="com.rabbitmq.client@default:default"/>
|
||||
<setEntry value="org.apache.commons.lang@default:default"/>
|
||||
<setEntry value="jackson-jaxrs@default:default"/>
|
||||
<setEntry value="com.sun.jersey@default:default"/>
|
||||
<setEntry value="javax.ws.rs@default:default"/>
|
||||
<setEntry value="org.apache.commons.beanutils@default:default"/>
|
||||
<setEntry value="org.apache.servicemix.bundles.ehcache@default:default"/>
|
||||
<setEntry value="org.apache.servicemix.bundles.scribe@default:default"/>
|
||||
<setEntry value="org.apache.shiro.core@default:default"/>
|
||||
<setEntry value="org.apache.shiro.ehcache@default:default"/>
|
||||
<setEntry value="org.apache.shiro.web@default:default"/>
|
||||
<setEntry value="jackson-core-asl@default:default"/>
|
||||
<setEntry value="jackson-mapper-asl@default:default"/>
|
||||
<setEntry value="org.apache.commons.collections@default:default"/>
|
||||
<setEntry value="org.eclipse.jetty.client@default:default"/>
|
||||
<setEntry value="javax.xml@default:default"/>
|
||||
<setEntry value="com.sun.activation.javax.activation@default:default"/>
|
||||
<setEntry value="org.eclipse.equinox.common@2:true"/>
|
||||
<setEntry value="org.eclipse.equinox.console@default:default"/>
|
||||
<setEntry value="org.eclipse.equinox.launcher@default:default"/>
|
||||
<setEntry value="org.eclipse.equinox.simpleconfigurator@2:true"/>
|
||||
<setEntry value="org.eclipse.osgi@-1:true"/>
|
||||
<setEntry value="org.eclipse.osgi.services@default:default"/>
|
||||
<setEntry value="org.eclipse.equinox.cm@default:default"/>
|
||||
<setEntry value="com.sun.istack.commons-runtime@default:default"/>
|
||||
<setEntry value="jaxb-api@default:default"/>
|
||||
<setEntry value="com.sun.xml.bind.jaxb-impl@default:default"/>
|
||||
<setEntry value="javax.xml.stream@default:default"/>
|
||||
<setEntry value="javax.xml.ws@default:default"/>
|
||||
<setEntry value="org.eclipse.osgi.util@default:default"/>
|
||||
<setEntry value="com.jcraft.jsch@default:default"/>
|
||||
<setEntry value="com.amazon.aws.aws-java-api@default:default"/>
|
||||
<setEntry value="org.eclipse.osgi@-1:true"/>
|
||||
<setEntry value="org.hyperic.sigar@default:default"/>
|
||||
<setEntry value="org.jdom@default:default"/>
|
||||
<setEntry value="org.jvnet.mimepull@default:default"/>
|
||||
<setEntry value="org.mongodb.mongo-java-driver@default:default"/>
|
||||
<setEntry value="org.objectweb.asm@default:default"/>
|
||||
<setEntry value="routeconverter@default:default"/>
|
||||
<setEntry value="slf4j.api@default:default"/>
|
||||
<setEntry value="slf4j.jdk14@default:false"/>
|
||||
</setAttribute>
|
||||
<setAttribute key="selected_workspace_bundles">
|
||||
<setEntry value="com.sap.sailing.geocoding@default:default"/>
|
||||
<setEntry value="com.sap.sailing.domain.common@default:default"/>
|
||||
<setEntry value="com.sap.sailing.domain@default:default"/>
|
||||
<setEntry value="com.sap.sailing.news@4:true"/>
|
||||
<setEntry value="com.sap.sailing.domain.tractracadapter@5:true"/>
|
||||
<setEntry value="com.sap.sailing.expeditionconnector@default:default"/>
|
||||
<setEntry value="com.sap.sailing.domain.windfinderadapter@4:true"/>
|
||||
<setEntry value="com.sap.sailing.server@5:true"/>
|
||||
<setEntry value="com.sap.sailing.server.gateway@5:true"/>
|
||||
<setEntry value="com.tractrac.clientmodule@default:default"/>
|
||||
<setEntry value="com.google.gwt.servlet@default:default"/>
|
||||
<setEntry value="com.googlecode.java-diff-utils@default:default"/>
|
||||
<setEntry value="com.sap.sailing.barbados.resultimport@4:true"/>
|
||||
<setEntry value="com.sap.sailing.competitorimport@default:default"/>
|
||||
<setEntry value="com.sap.sailing.dashboards.gwt@6:true"/>
|
||||
<setEntry value="com.sap.sailing.datamining.provider@default:default"/>
|
||||
<setEntry value="com.sap.sailing.datamining.shared@default:default"/>
|
||||
<setEntry value="com.sap.sailing.datamining@5:true"/>
|
||||
<setEntry value="com.sap.sailing.declination@default:default"/>
|
||||
<setEntry value="com.sap.sailing.domain.bravoadapter@5:true"/>
|
||||
<setEntry value="com.sap.sailing.domain.common@default:default"/>
|
||||
<setEntry value="com.sap.sailing.domain.deckmanadapter@5:true"/>
|
||||
<setEntry value="com.sap.sailing.domain.expeditionadapter@5:true"/>
|
||||
<setEntry value="com.sap.sailing.domain.igtimiadapter.gateway@5:true"/>
|
||||
<setEntry value="com.sap.sailing.domain.igtimiadapter.persistence@default:default"/>
|
||||
<setEntry value="com.sap.sailing.domain.igtimiadapter@4:true"/>
|
||||
<setEntry value="com.sap.sailing.domain.persistence@default:default"/>
|
||||
<setEntry value="com.sap.sailing.domain.swisstimingadapter@5:true"/>
|
||||
<setEntry value="com.sap.sailing.domain.racelogtrackingadapter@4:true"/>
|
||||
<setEntry value="com.sap.sailing.domain.shared.android@default:default"/>
|
||||
<setEntry value="com.sap.sailing.domain.swisstimingadapter.persistence@4:true"/>
|
||||
<setEntry value="com.sap.sailing.domain.swisstimingadapter@5:true"/>
|
||||
<setEntry value="com.sap.sailing.domain.swisstimingreplayadapter@4:true"/>
|
||||
<setEntry value="com.sap.sailing.domain.tractracadapter.persistence@4:true"/>
|
||||
<setEntry value="com.sap.sailing.gwt.ui@6:true"/>
|
||||
<setEntry value="com.sap.sailing.udpconnector@default:default"/>
|
||||
<setEntry value="com.sap.sailing.xmlexport@5:true"/>
|
||||
<setEntry value="com.sap.sailing.simulator@default:default"/>
|
||||
<setEntry value="com.sap.sailing.www@5:true"/>
|
||||
<setEntry value="com.sap.sailing.resultimport@4:true"/>
|
||||
<setEntry value="com.sap.sailing.kiworesultimport@4:true"/>
|
||||
<setEntry value="com.sap.sailing.domain.tractracadapter@5:true"/>
|
||||
<setEntry value="com.sap.sailing.domain.windfinderadapter@4:true"/>
|
||||
<setEntry value="com.sap.sailing.domain@default:default"/>
|
||||
<setEntry value="com.sap.sailing.ess40.resultimport@4:true"/>
|
||||
<setEntry value="com.sap.sailing.expeditionconnector.common@default:default"/>
|
||||
<setEntry value="com.sap.sailing.expeditionconnector.persistence@4:true"/>
|
||||
<setEntry value="com.sap.sailing.expeditionconnector@default:default"/>
|
||||
<setEntry value="com.sap.sailing.freg.resultimport@4:true"/>
|
||||
<setEntry value="com.sap.sailing.barbados.resultimport@4:true"/>
|
||||
<setEntry value="com.sap.sailing.sailwave.resultimport@4:true"/>
|
||||
<setEntry value="com.sap.sailing.geocoding@default:default"/>
|
||||
<setEntry value="com.sap.sailing.grib@default:default"/>
|
||||
<setEntry value="com.sap.sailing.gwt.ui@6:true"/>
|
||||
<setEntry value="com.sap.sailing.kiworesultimport@4:true"/>
|
||||
<setEntry value="com.sap.sailing.manage2sail.resultimport@4:true"/>
|
||||
<setEntry value="com.sap.sailing.yachtscoring.resultimport@4:true"/>
|
||||
<setEntry value="com.sap.sailing.velum.resultimport@4:true"/>
|
||||
<setEntry value="com.sap.sailing.manage2sail@default:default"/>
|
||||
<setEntry value="com.sap.sailing.monitoring@7:true"/>
|
||||
<setEntry value="com.sap.sailing.xrr.resultimport@4:true"/>
|
||||
<setEntry value="com.sap.sailing.domain.igtimiadapter@4:true"/>
|
||||
<setEntry value="com.sap.sailing.domain.igtimiadapter.persistence@default:default"/>
|
||||
<setEntry value="com.sap.sailing.domain.racelogtrackingadapter@4:true"/>
|
||||
<setEntry value="com.sap.sailing.domain.deckmanadapter@5:true"/>
|
||||
<setEntry value="com.sap.sailing.xrr.structureimport@default:default"/>
|
||||
<setEntry value="com.sap.sailing.news@4:true"/>
|
||||
<setEntry value="com.sap.sailing.nmeaconnector@default:default"/>
|
||||
<setEntry value="com.sap.sailing.polars.datamining.shared@default:default"/>
|
||||
<setEntry value="com.sap.sailing.polars.datamining@5:true"/>
|
||||
<setEntry value="com.sap.sailing.polars@5:true"/>
|
||||
<setEntry value="com.sap.sailing.resultimport@4:true"/>
|
||||
<setEntry value="com.sap.sailing.routeconverterjava11extension@default:false"/>
|
||||
<setEntry value="com.sap.sailing.sailwave.resultimport@4:true"/>
|
||||
<setEntry value="com.sap.sailing.server.gateway.serialization.shared.android@default:default"/>
|
||||
<setEntry value="com.sap.sailing.server.gateway.serialization@default:default"/>
|
||||
<setEntry value="com.sap.sailing.dashboards.gwt@6:true"/>
|
||||
<setEntry value="com.sap.sailing.dashboards.gwt@6:true"/>
|
||||
<setEntry value="com.sap.sailing.datamining@5:true"/>
|
||||
<setEntry value="com.sap.sailing.datamining.shared@default:default"/>
|
||||
<setEntry value="com.sap.sailing.polars@5:true"/>
|
||||
<setEntry value="com.sap.sailing.windestimation@5:true"/>
|
||||
<setEntry value="com.sap.sailing.polars.datamining@5:true"/>
|
||||
<setEntry value="com.sap.sailing.domain.shared.android@default:default"/>
|
||||
<setEntry value="com.sap.sailing.manage2sail@default:default"/>
|
||||
<setEntry value="com.sap.sailing.polars.datamining.shared@default:default"/>
|
||||
<setEntry value="com.sap.sailing.xrr.schema@default:default"/>
|
||||
<setEntry value="com.sap.sailing.server.trackfiles@default:default"/>
|
||||
<setEntry value="com.sap.sailing.competitorimport@default:default"/>
|
||||
<setEntry value="com.sap.sailing.datamining.provider@default:default"/>
|
||||
<setEntry value="com.sap.sailing.grib@default:default"/>
|
||||
<setEntry value="com.sap.sailing.nmeaconnector@default:default"/>
|
||||
<setEntry value="com.sap.sailing.domain.expeditionadapter@5:true"/>
|
||||
<setEntry value="com.sap.sailing.expeditionconnector.persistence@4:true"/>
|
||||
<setEntry value="com.sap.sailing.expeditionconnector.common@default:default"/>
|
||||
<setEntry value="com.sap.sailing.domain.bravoadapter@5:true"/>
|
||||
<setEntry value="net.sf.marineapi@default:default"/>
|
||||
<setEntry value="com.sap.sailing.routeconverterjava11extension@default:default"/>
|
||||
<setEntry value="com.sap.sailing.server.gateway@5:true"/>
|
||||
<setEntry value="com.sap.sailing.server.interface@default:default"/>
|
||||
<setEntry value="com.sap.sse.datamining.ui@default:default"/>
|
||||
<setEntry value="com.sap.sailing.domain.igtimiadapter.gateway@5:true"/>
|
||||
<setEntry value="com.sap.sailing.shared.server@5:true"/>
|
||||
<setEntry value="com.sap.sailing.shared.server.gateway@5:true"/>
|
||||
<setEntry value="com.sap.sailing.server.trackfiles@default:default"/>
|
||||
<setEntry value="com.sap.sailing.server@5:true"/>
|
||||
<setEntry value="com.sap.sailing.shared.persistence@default:default"/>
|
||||
<setEntry value="com.sap.sse.debranding@default:default"/>
|
||||
<setEntry value="com.tractrac.clientmodule@default:default"/>
|
||||
<setEntry value="com.sap.sse.gwt@default:default"/>
|
||||
<setEntry value="com.google.gwt.servlet@default:default"/>
|
||||
<setEntry value="com.sap.sse.security@default:default"/>
|
||||
<setEntry value="com.sap.sse.security.ui@6:true"/>
|
||||
<setEntry value="com.sap.sse.security.userstore.mongodb@4:true"/>
|
||||
<setEntry value="com.sap.sse@default:default"/>
|
||||
<setEntry value="com.sap.sailing.shared.server.gateway@5:true"/>
|
||||
<setEntry value="com.sap.sailing.shared.server@5:true"/>
|
||||
<setEntry value="com.sap.sailing.simulator@default:default"/>
|
||||
<setEntry value="com.sap.sailing.udpconnector@default:default"/>
|
||||
<setEntry value="com.sap.sailing.velum.resultimport@4:true"/>
|
||||
<setEntry value="com.sap.sailing.windestimation@5:true"/>
|
||||
<setEntry value="com.sap.sailing.www@5:true"/>
|
||||
<setEntry value="com.sap.sailing.xmlexport@5:true"/>
|
||||
<setEntry value="com.sap.sailing.xrr.resultimport@4:true"/>
|
||||
<setEntry value="com.sap.sailing.xrr.schema@default:default"/>
|
||||
<setEntry value="com.sap.sailing.xrr.structureimport@default:default"/>
|
||||
<setEntry value="com.sap.sailing.yachtscoring.resultimport@4:true"/>
|
||||
<setEntry value="com.sap.sse.common@default:default"/>
|
||||
<setEntry value="com.sap.sse.datamining@default:default"/>
|
||||
<setEntry value="com.sap.sse.datamining.annotations@default:default"/>
|
||||
<setEntry value="com.sap.sse.datamining.shared@default:default"/>
|
||||
<setEntry value="com.sap.sse.datamining.ui@default:default"/>
|
||||
<setEntry value="com.sap.sse.datamining@default:default"/>
|
||||
<setEntry value="com.sap.sse.debranding@default:default"/>
|
||||
<setEntry value="com.sap.sse.filestorage@4:true"/>
|
||||
<setEntry value="com.sap.sse.gwt.adminconsole@default:default"/>
|
||||
<setEntry value="com.sap.sse.gwt@default:default"/>
|
||||
<setEntry value="com.sap.sse.jersey.jaxbdependencyfragment@default:false"/>
|
||||
<setEntry value="com.sap.sse.jettyextensions@default:false"/>
|
||||
<setEntry value="com.sap.sse.landscape.aws.persistence@default:default"/>
|
||||
<setEntry value="com.sap.sse.landscape.aws@default:default"/>
|
||||
<setEntry value="com.sap.sse.landscape@default:default"/>
|
||||
<setEntry value="com.sap.sse.mail@5:true"/>
|
||||
<setEntry value="com.sap.sse.mongodb@default:default"/>
|
||||
<setEntry value="com.sap.sse.operationaltransformation@default:default"/>
|
||||
<setEntry value="com.sap.sse.replication@6:true"/>
|
||||
<setEntry value="com.sap.sse.filestorage@4:true"/>
|
||||
<setEntry value="com.sap.sse.shared.android@default:default"/>
|
||||
<setEntry value="com.sap.sse.mail@5:true"/>
|
||||
<setEntry value="com.sap.sse.threadmanager@default:default"/>
|
||||
<setEntry value="com.sap.sse.security.common@default:default"/>
|
||||
<setEntry value="org.json.simple@default:default"/>
|
||||
<setEntry value="com.sap.sse.jersey.jaxbdependencyfragment@default:default"/>
|
||||
<setEntry value="org.moxieapps.gwt.highcharts@default:default"/>
|
||||
<setEntry value="com.googlecode.java-diff-utils@default:default"/>
|
||||
<setEntry value="org.mp4parser.isoparser@default:default"/>
|
||||
<setEntry value="com.sap.sse.replication.interfaces@default:default"/>
|
||||
<setEntry value="com.sap.sse.security.persistence@default:default"/>
|
||||
<setEntry value="com.sap.sse.security.interface@default:default"/>
|
||||
<setEntry value="com.sap.sse.jettyextensions@default:default"/>
|
||||
<setEntry value="com.sap.sse.replication.persistence@default:default"/>
|
||||
<setEntry value="com.sap.sse.landscape@default:default"/>
|
||||
<setEntry value="com.sap.sse.landscape.aws@default:default"/>
|
||||
<setEntry value="com.sap.sse.landscape.aws.persistence@default:default"/>
|
||||
<setEntry value="com.sap.sse.replication@6:true"/>
|
||||
<setEntry value="com.sap.sse.security.common@default:default"/>
|
||||
<setEntry value="com.sap.sse.security.interface@default:default"/>
|
||||
<setEntry value="com.sap.sse.security.persistence@default:default"/>
|
||||
<setEntry value="com.sap.sse.security.ui@6:true"/>
|
||||
<setEntry value="com.sap.sse.security.userstore.mongodb@4:true"/>
|
||||
<setEntry value="com.sap.sse.security@default:default"/>
|
||||
<setEntry value="com.sap.sse.shared.android@default:default"/>
|
||||
<setEntry value="com.sap.sse.threadmanager@default:default"/>
|
||||
<setEntry value="com.sap.sse@default:default"/>
|
||||
<setEntry value="com.tractrac.clientmodule@default:default"/>
|
||||
<setEntry value="net.sf.marineapi@default:default"/>
|
||||
<setEntry value="org.json.simple@default:default"/>
|
||||
<setEntry value="org.moxieapps.gwt.highcharts@default:default"/>
|
||||
<setEntry value="org.mp4parser.isoparser@default:default"/>
|
||||
</setAttribute>
|
||||
<booleanAttribute key="show_selected_only" value="false"/>
|
||||
<booleanAttribute key="tracing" value="false"/>
|
||||
|
||||
+2
-5
@@ -23,7 +23,6 @@ import com.sap.sse.common.impl.MillisecondsTimePoint;
|
||||
*
|
||||
*/
|
||||
public class WindFieldTrackedRaceImpl extends WindFieldGeneratorImpl implements WindFieldGenerator {
|
||||
|
||||
private static final long serialVersionUID = -7005970781594631010L;
|
||||
private static final double EPSILON_DISTANCE_METER = 20;
|
||||
private static final long EPSILON_TIME_MILLIS = 5000;
|
||||
@@ -31,7 +30,6 @@ public class WindFieldTrackedRaceImpl extends WindFieldGeneratorImpl implements
|
||||
private final ConcurrentMap<TimedPosition, Wind> cache;
|
||||
private TimePoint startSimulationTime = null;
|
||||
|
||||
|
||||
public WindFieldTrackedRaceImpl(TrackedRace race) {
|
||||
super(null, null);
|
||||
this.race = race;
|
||||
@@ -60,10 +58,9 @@ public class WindFieldTrackedRaceImpl extends WindFieldGeneratorImpl implements
|
||||
TimedPosition qTimedPosition = new TimedPositionImpl(qTime, qPosition);
|
||||
Wind wind = cache.get(qTimedPosition);
|
||||
if (wind == null) {
|
||||
wind = this.race.getWind(qPosition, qTime);
|
||||
cache.put(qTimedPosition, wind);
|
||||
wind = this.race.getWind(qPosition, qTime);
|
||||
cache.put(qTimedPosition, wind);
|
||||
}
|
||||
return wind;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user