From ebccd0416b8689ee9c03a83b6c1ed2c3cc27981b Mon Sep 17 00:00:00 2001 From: Axel Uhl Date: Wed, 22 Jan 2025 17:01:42 +0100 Subject: [PATCH] bug6085: replicate last heartbeat/remote address as Device property --- .../persistence/IgtimiPersistenceTest.java | 18 + .../impl/DomainObjectFactoryImpl.java | 8 +- .../persistence/impl/FieldNames.java | 2 +- .../impl/MongoObjectFactoryImpl.java | 2 + .../replication/ReplicableRiotServer.java | 4 +- .../igtimiadapter/server/riot/RiotServer.java | 2 + .../server/riot/impl/RiotConnectionImpl.java | 34 +- .../server/riot/impl/RiotServerImpl.java | 15 + .../sailing/domain/igtimiadapter/Device.java | 13 + .../domain/igtimiadapter/impl/DeviceImpl.java | 15 + .../ui/adminconsole/IgtimiDevicesPanel.java | 6 +- .../gwt/ui/server/SailingServiceImpl.java | 23 +- .../shared/IgtimiDeviceWithSecurityDTO.java | 15 +- ...oxy, Jetty on 8889, auto-replicate).launch | 654 +++++++++--------- 14 files changed, 443 insertions(+), 368 deletions(-) diff --git a/java/com.sap.sailing.domain.igtimiadapter.persistence.test/src/com/sap/sailing/domain/igtimiadapter/persistence/IgtimiPersistenceTest.java b/java/com.sap.sailing.domain.igtimiadapter.persistence.test/src/com/sap/sailing/domain/igtimiadapter/persistence/IgtimiPersistenceTest.java index e9d9b55380d..0513b6ede6c 100755 --- a/java/com.sap.sailing.domain.igtimiadapter.persistence.test/src/com/sap/sailing/domain/igtimiadapter/persistence/IgtimiPersistenceTest.java +++ b/java/com.sap.sailing.domain.igtimiadapter.persistence.test/src/com/sap/sailing/domain/igtimiadapter/persistence/IgtimiPersistenceTest.java @@ -2,8 +2,10 @@ package com.sap.sailing.domain.igtimiadapter.persistence; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; +import java.net.InetSocketAddress; import java.util.Arrays; import java.util.HashSet; import java.util.Iterator; @@ -60,11 +62,27 @@ public class IgtimiPersistenceTest { @Test public void testStoringAndLoadingSimpleDevice() { final Device device = Device.create(123, "DE-AC-AAHJ", "The tricky one"); + final String remoteAddress = new InetSocketAddress("127.0.0.1", 1234).toString(); + final TimePoint heartbeat = TimePoint.now(); + device.setLastHeartbeat(heartbeat, remoteAddress); mongoObjectFactory.storeDevice(device, clientSession); final Device loadedDevice = domainObjectFactory.getDevices(clientSession).iterator().next(); assertEquals(device.getId(), loadedDevice.getId()); assertEquals(device.getName(), loadedDevice.getName()); assertEquals(device.getSerialNumber(), loadedDevice.getSerialNumber()); + assertEquals(new Util.Pair<>(heartbeat, remoteAddress), loadedDevice.getLastHeartbeat()); + } + + @Test + public void testStoringAndLoadingSimpleDeviceWithEmptyHeartbeat() { + final Device device = Device.create(123, "DE-AC-AAHJ", "The empty heartbeat"); + assertNull(device.getLastHeartbeat()); + mongoObjectFactory.storeDevice(device, clientSession); + final Device loadedDevice = domainObjectFactory.getDevices(clientSession).iterator().next(); + assertEquals(device.getId(), loadedDevice.getId()); + assertEquals(device.getName(), loadedDevice.getName()); + assertEquals(device.getSerialNumber(), loadedDevice.getSerialNumber()); + assertNull(loadedDevice.getLastHeartbeat()); } @Test diff --git a/java/com.sap.sailing.domain.igtimiadapter.persistence/src/com/sap/sailing/domain/igtimiadapter/persistence/impl/DomainObjectFactoryImpl.java b/java/com.sap.sailing.domain.igtimiadapter.persistence/src/com/sap/sailing/domain/igtimiadapter/persistence/impl/DomainObjectFactoryImpl.java index d795919bf63..e5c93e10c7f 100644 --- a/java/com.sap.sailing.domain.igtimiadapter.persistence/src/com/sap/sailing/domain/igtimiadapter/persistence/impl/DomainObjectFactoryImpl.java +++ b/java/com.sap.sailing.domain.igtimiadapter.persistence/src/com/sap/sailing/domain/igtimiadapter/persistence/impl/DomainObjectFactoryImpl.java @@ -76,7 +76,13 @@ public class DomainObjectFactoryImpl implements DomainObjectFactory { final Number id = ((Number) ((Document) o).get(FieldNames.IGTIMI_DEVICES_ID.name())); final String serialNumber = (String) ((Document) o).get(FieldNames.IGTIMI_DEVICES_SERIAL_NUMBER.name()); final String name = (String) ((Document) o).get(FieldNames.IGTIMI_DEVICES_NAME.name()); - result.add(Device.create(id.longValue(), serialNumber, name)); + final Device device = Device.create(id.longValue(), serialNumber, name); + final Long lastHeartbeatMillis = ((Document) o).getLong(FieldNames.IGTIMI_DEVICES_LAST_HEARTBEAT_MILLIS.name()); + if (lastHeartbeatMillis != null) { + final String remoteAddress = ((Document) o).getString(FieldNames.IGTIMI_DEVICES_REMOTE_ADDRESS.name()); + device.setLastHeartbeat(lastHeartbeatMillis == null ? null : TimePoint.of(lastHeartbeatMillis), remoteAddress); + } + result.add(device); } return result; } diff --git a/java/com.sap.sailing.domain.igtimiadapter.persistence/src/com/sap/sailing/domain/igtimiadapter/persistence/impl/FieldNames.java b/java/com.sap.sailing.domain.igtimiadapter.persistence/src/com/sap/sailing/domain/igtimiadapter/persistence/impl/FieldNames.java index d5c07b88867..c6a89fb664f 100755 --- a/java/com.sap.sailing.domain.igtimiadapter.persistence/src/com/sap/sailing/domain/igtimiadapter/persistence/impl/FieldNames.java +++ b/java/com.sap.sailing.domain.igtimiadapter.persistence/src/com/sap/sailing/domain/igtimiadapter/persistence/impl/FieldNames.java @@ -1,7 +1,7 @@ package com.sap.sailing.domain.igtimiadapter.persistence.impl; public enum FieldNames { - IGTIMI_DEVICES_ID, IGTIMI_DEVICES_SERIAL_NUMBER, IGTIMI_DEVICES_NAME, + IGTIMI_DEVICES_ID, IGTIMI_DEVICES_SERIAL_NUMBER, IGTIMI_DEVICES_NAME, IGTIMI_DEVICES_LAST_HEARTBEAT_MILLIS, IGTIMI_DEVICES_REMOTE_ADDRESS, IGTIMI_DATA_ACCESS_WINDOWS_ID, IGTIMI_DATA_ACCESS_WINDOWS_START_TIME_MILLIS, IGTIMI_DATA_ACCESS_WINDOWS_END_TIME_MILLIS, IGTIMI_DATA_ACCESS_WINDOWS_DEVICE_SERIAL_NUMBER, IGTIMI_MESSAGES_TIMESTAMP, IGTIMI_MESSAGES_DEVICE_SERIAL_NUMBER, IGTIMI_MESSAGES_PROTOBUF_MESSAGE; } diff --git a/java/com.sap.sailing.domain.igtimiadapter.persistence/src/com/sap/sailing/domain/igtimiadapter/persistence/impl/MongoObjectFactoryImpl.java b/java/com.sap.sailing.domain.igtimiadapter.persistence/src/com/sap/sailing/domain/igtimiadapter/persistence/impl/MongoObjectFactoryImpl.java index 8e048d8a635..c83f182c6d6 100755 --- a/java/com.sap.sailing.domain.igtimiadapter.persistence/src/com/sap/sailing/domain/igtimiadapter/persistence/impl/MongoObjectFactoryImpl.java +++ b/java/com.sap.sailing.domain.igtimiadapter.persistence/src/com/sap/sailing/domain/igtimiadapter/persistence/impl/MongoObjectFactoryImpl.java @@ -64,6 +64,8 @@ public class MongoObjectFactoryImpl implements MongoObjectFactory { update.put(FieldNames.IGTIMI_DEVICES_ID.name(), device.getId()); update.put(FieldNames.IGTIMI_DEVICES_NAME.name(), device.getName()); update.put(FieldNames.IGTIMI_DEVICES_SERIAL_NUMBER.name(), device.getSerialNumber()); + update.put(FieldNames.IGTIMI_DEVICES_LAST_HEARTBEAT_MILLIS.name(), device.getLastHeartbeat() == null ? null : device.getLastHeartbeat().getA() == null ? null : device.getLastHeartbeat().getA().asMillis()); + update.put(FieldNames.IGTIMI_DEVICES_REMOTE_ADDRESS.name(), device.getLastHeartbeat() == null ? null : device.getLastHeartbeat().getB()); final MongoCollection deviceCollection = db.getCollection(CollectionNames.IGTIMI_DEVICES.name()).withWriteConcern(WriteConcern.ACKNOWLEDGED); if (clientSessionOrNull == null) { deviceCollection.replaceOne(filter, update, new ReplaceOptions().upsert(true)); diff --git a/java/com.sap.sailing.domain.igtimiadapter.server/src/com/sap/sailing/domain/igtimiadapter/server/replication/ReplicableRiotServer.java b/java/com.sap.sailing.domain.igtimiadapter.server/src/com/sap/sailing/domain/igtimiadapter/server/replication/ReplicableRiotServer.java index 285e24db8d8..21cd515eb77 100644 --- a/java/com.sap.sailing.domain.igtimiadapter.server/src/com/sap/sailing/domain/igtimiadapter/server/replication/ReplicableRiotServer.java +++ b/java/com.sap.sailing.domain.igtimiadapter.server/src/com/sap/sailing/domain/igtimiadapter/server/replication/ReplicableRiotServer.java @@ -10,11 +10,12 @@ import com.sap.sailing.domain.igtimiadapter.server.riot.RiotStandardCommand; import com.sap.sse.common.TimePoint; public interface ReplicableRiotServer extends RiotServer { - Void internalRemoveDevice(long deviceId); Void internalUpdateDeviceName(long deviceId, String name); + Void internalUpdateDeviceLastHeartbeat(long deviceId, TimePoint timePointOfLastHeartbeat, String remoteAddress); + DataAccessWindow internalCreateDataAccessWindow(String deviceSerialNumber, TimePoint startTime, TimePoint endTime); Void internalRemoveDataAccessWindow(long dawId); @@ -24,5 +25,4 @@ public interface ReplicableRiotServer extends RiotServer { Device internalCreateDevice(String deviceSerialNumber); boolean internalSendStandardCommand(String deviceSerialNumber, RiotStandardCommand command) throws IOException; - } diff --git a/java/com.sap.sailing.domain.igtimiadapter.server/src/com/sap/sailing/domain/igtimiadapter/server/riot/RiotServer.java b/java/com.sap.sailing.domain.igtimiadapter.server/src/com/sap/sailing/domain/igtimiadapter/server/riot/RiotServer.java index 614517c025d..a17550a0d9a 100644 --- a/java/com.sap.sailing.domain.igtimiadapter.server/src/com/sap/sailing/domain/igtimiadapter/server/riot/RiotServer.java +++ b/java/com.sap.sailing.domain.igtimiadapter.server/src/com/sap/sailing/domain/igtimiadapter/server/riot/RiotServer.java @@ -105,6 +105,8 @@ public interface RiotServer extends Replicable getDataAccessWindows(); DataAccessWindow getDataAccessWindowById(long id); diff --git a/java/com.sap.sailing.domain.igtimiadapter.server/src/com/sap/sailing/domain/igtimiadapter/server/riot/impl/RiotConnectionImpl.java b/java/com.sap.sailing.domain.igtimiadapter.server/src/com/sap/sailing/domain/igtimiadapter/server/riot/impl/RiotConnectionImpl.java index bdf392434eb..d9bdb7a8388 100644 --- a/java/com.sap.sailing.domain.igtimiadapter.server/src/com/sap/sailing/domain/igtimiadapter/server/riot/impl/RiotConnectionImpl.java +++ b/java/com.sap.sailing.domain.igtimiadapter.server/src/com/sap/sailing/domain/igtimiadapter/server/riot/impl/RiotConnectionImpl.java @@ -27,6 +27,7 @@ import com.igtimi.IgtimiStream.ChannelManagement; import com.igtimi.IgtimiStream.Msg; import com.igtimi.IgtimiStream.ServerDisconnecting; import com.sap.sailing.domain.igtimiadapter.ChannelManagementVisitor; +import com.sap.sailing.domain.igtimiadapter.Device; import com.sap.sailing.domain.igtimiadapter.MsgVisitor; import com.sap.sailing.domain.igtimiadapter.server.riot.RiotConnection; import com.sap.sse.common.TimePoint; @@ -253,16 +254,13 @@ public class RiotConnectionImpl implements RiotConnection { MsgVisitor.accept(message, new MsgVisitor() { @Override public void handleDeviceManagement(DeviceManagement deviceManagement) { - serialNumber = deviceManagement.getSerialNumber(); + updateSerialNumber(deviceManagement.getSerialNumber()); } @Override public void handleData(Data data) { for (final DataMsg dataMsg : data.getDataList()) { - final String messageSerialNumber = dataMsg.getSerialNumber(); - if (Util.hasLength(messageSerialNumber)) { - serialNumber = dataMsg.getSerialNumber(); - } + updateSerialNumber(dataMsg.getSerialNumber()); } } @@ -288,6 +286,7 @@ public class RiotConnectionImpl implements RiotConnection { @Override public void handleHeartbeat(long heartbeat) { lastHeartbeatReceivedAt = TimePoint.now(); + updateDeviceHeartbeatIfSerialNumberKnown(); } }); } @@ -296,9 +295,34 @@ public class RiotConnectionImpl implements RiotConnection { public void handleAckResponse(AckResponse ackResponse) { logger.info("Received AckResponse from device "+getSerialNumber()+": "+ackResponse); } + + private void updateSerialNumber(String serialNumber) { + if (Util.hasLength(serialNumber)) { + final boolean serialNumberWasUnknown = RiotConnectionImpl.this.serialNumber == null; + RiotConnectionImpl.this.serialNumber = serialNumber; + if (serialNumberWasUnknown && lastHeartbeatReceivedAt != null) { + // we see the serial number for the first time although we already have received a heartbeat; update + updateDeviceHeartbeatIfSerialNumberKnown(); + } + } + } }); } + + private void updateDeviceHeartbeatIfSerialNumberKnown() { + if (serialNumber != null) { + final Device device = riotServer.getDeviceBySerialNumber(serialNumber); + if (device != null) { + try { + riotServer.updateDeviceLastHeartbeat(device.getId(), lastHeartbeatReceivedAt, getSocketChannel().getRemoteAddress().toString()); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + } + } + private void sendHeartbeat() { try { send(Msg.newBuilder().setChannelManagement(ChannelManagement.newBuilder().setHeartbeat(1)).build()); diff --git a/java/com.sap.sailing.domain.igtimiadapter.server/src/com/sap/sailing/domain/igtimiadapter/server/riot/impl/RiotServerImpl.java b/java/com.sap.sailing.domain.igtimiadapter.server/src/com/sap/sailing/domain/igtimiadapter/server/riot/impl/RiotServerImpl.java index f27b1c85d3c..9cb54e56f16 100644 --- a/java/com.sap.sailing.domain.igtimiadapter.server/src/com/sap/sailing/domain/igtimiadapter/server/riot/impl/RiotServerImpl.java +++ b/java/com.sap.sailing.domain.igtimiadapter.server/src/com/sap/sailing/domain/igtimiadapter/server/riot/impl/RiotServerImpl.java @@ -402,6 +402,21 @@ public class RiotServerImpl extends AbstractReplicableWithObjectInputStreams.internalUpdateDeviceLastHeartbeat(deviceId, timePointOfLastHeartbeat, remoteAddress)); + } + + @Override + public Void internalUpdateDeviceLastHeartbeat(long deviceId, TimePoint timePointOfLastHeartbeat, String remoteAddress) { + final Device existingDevice = devices.get(deviceId); + if (existingDevice != null) { + existingDevice.setLastHeartbeat(timePointOfLastHeartbeat, remoteAddress); + mongoObjectFactory.storeDevice(existingDevice, /* clientSessionOrNull */ null); + } + return null; + } @Override public Iterable getDataAccessWindows() { diff --git a/java/com.sap.sailing.domain.igtimiadapter/src/com/sap/sailing/domain/igtimiadapter/Device.java b/java/com.sap.sailing.domain.igtimiadapter/src/com/sap/sailing/domain/igtimiadapter/Device.java index 8447d315d00..6e1a0545a0a 100755 --- a/java/com.sap.sailing.domain.igtimiadapter/src/com/sap/sailing/domain/igtimiadapter/Device.java +++ b/java/com.sap.sailing.domain.igtimiadapter/src/com/sap/sailing/domain/igtimiadapter/Device.java @@ -2,6 +2,8 @@ package com.sap.sailing.domain.igtimiadapter; import com.sap.sailing.domain.igtimiadapter.impl.DeviceImpl; import com.sap.sse.common.Renamable; +import com.sap.sse.common.TimePoint; +import com.sap.sse.common.Util.Pair; import com.sap.sse.security.shared.WithQualifiedObjectIdentifier; public interface Device extends HasId, WithQualifiedObjectIdentifier, Renamable { @@ -9,6 +11,17 @@ public interface Device extends HasId, WithQualifiedObjectIdentifier, Renamable * @return a string identifying the device, such as "AA-AA-AAAA" */ String getSerialNumber(); + + /** + * Returns the time point and the remote address of the last heart beat received from this device, + * or {@code null} if no heartbeat has been received from this device yet. + */ + Pair getLastHeartbeat(); + + /** + * @param remoteAddress the remote address from which the heart beat was received + */ + void setLastHeartbeat(TimePoint timePointOfLastHeartbeat, String remoteAddress); static Device create(long id, String serialNumber, String name) { return new DeviceImpl(id, serialNumber, name); diff --git a/java/com.sap.sailing.domain.igtimiadapter/src/com/sap/sailing/domain/igtimiadapter/impl/DeviceImpl.java b/java/com.sap.sailing.domain.igtimiadapter/src/com/sap/sailing/domain/igtimiadapter/impl/DeviceImpl.java index 90d049e0ee6..3654f29999c 100755 --- a/java/com.sap.sailing.domain.igtimiadapter/src/com/sap/sailing/domain/igtimiadapter/impl/DeviceImpl.java +++ b/java/com.sap.sailing.domain.igtimiadapter/src/com/sap/sailing/domain/igtimiadapter/impl/DeviceImpl.java @@ -2,6 +2,8 @@ package com.sap.sailing.domain.igtimiadapter.impl; import com.sap.sailing.domain.common.security.SecuredDomainType; import com.sap.sailing.domain.igtimiadapter.Device; +import com.sap.sse.common.TimePoint; +import com.sap.sse.common.Util.Pair; import com.sap.sse.security.shared.HasPermissions; import com.sap.sse.security.shared.QualifiedObjectIdentifier; import com.sap.sse.security.shared.TypeRelativeObjectIdentifier; @@ -10,6 +12,8 @@ public class DeviceImpl extends HasIdImpl implements Device { private static final long serialVersionUID = 7224992550721569935L; private final String serialNumber; private String name; + private TimePoint lastHeartbeat; + private String remoteAddress; public DeviceImpl(long id, String serialNumber) { this(id, serialNumber, /* name */ null); @@ -36,6 +40,17 @@ public class DeviceImpl extends HasIdImpl implements Device { this.name = name; } + @Override + public Pair getLastHeartbeat() { + return lastHeartbeat == null ? null : new Pair<>(lastHeartbeat, remoteAddress); + } + + @Override + public void setLastHeartbeat(TimePoint timePointOfLastHeartbeat, String remoteAddress) { + this.lastHeartbeat = timePointOfLastHeartbeat; + this.remoteAddress = remoteAddress; + } + @Override public QualifiedObjectIdentifier getIdentifier() { return getPermissionType().getQualifiedObjectIdentifier(new TypeRelativeObjectIdentifier(getSerialNumber())); diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/IgtimiDevicesPanel.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/IgtimiDevicesPanel.java index 6424377c895..ed684850997 100755 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/IgtimiDevicesPanel.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/IgtimiDevicesPanel.java @@ -313,9 +313,9 @@ public class IgtimiDevicesPanel extends FlowPanel implements FilterablePanelProv device -> device.getSerialNumber(), columnSortHandler); final TextColumn lastHeartBeatColumn = new AbstractSortableTextColumn<>( device -> device.getLastHeartBeat()==null?"":device.getLastHeartBeat().toString(), columnSortHandler, - (a,b)->Util.compareToWithNull(a.getLastHeartBeat(), b.getLastHeartBeat(), /* null is less */ true)); + (a,b)->Util.compareToWithNull(a.getLastHeartBeat()==null?null:a.getLastHeartBeat().getA(), b.getLastHeartBeat()==null?null:b.getLastHeartBeat().getA(), /* null is less */ true)); final TextColumn remoteAddressColumn = new AbstractSortableTextColumn<>( - device -> device.getRemoteAddress(), columnSortHandler); + device -> device.getLastHeartBeat() == null ? null : device.getLastHeartBeat().getB(), columnSortHandler); final SafeHtmlCell lastKnownPositionCell = new SafeHtmlCell(); final Column lastKnownPositionColumn = new Column(lastKnownPositionCell) { @Override @@ -427,7 +427,7 @@ public class IgtimiDevicesPanel extends FlowPanel implements FilterablePanelProv final IgtimiDeviceWithSecurityDTO result = new IgtimiDeviceWithSecurityDTO( device.getId(), device.getSerialNumber(), nameField.getText(), device.getLastHeartBeat(), - device.getRemoteAddress(), device.getLastKnownPosition(), device.getLastKnownBatteryPercent()); + device.getLastKnownPosition(), device.getLastKnownBatteryPercent()); result.setAccessControlList(device.getAccessControlList()); result.setOwnership(device.getOwnership()); return result; diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/server/SailingServiceImpl.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/server/SailingServiceImpl.java index a06e7e508cd..100c9af2094 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/server/SailingServiceImpl.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/server/SailingServiceImpl.java @@ -258,7 +258,6 @@ import com.sap.sailing.domain.igtimiadapter.IgtimiConnection; import com.sap.sailing.domain.igtimiadapter.IgtimiConnectionFactory; import com.sap.sailing.domain.igtimiadapter.datatypes.BatteryLevel; import com.sap.sailing.domain.igtimiadapter.datatypes.GpsLatLong; -import com.sap.sailing.domain.igtimiadapter.server.riot.RiotConnection; import com.sap.sailing.domain.igtimiadapter.server.riot.RiotServer; import com.sap.sailing.domain.leaderboard.FlexibleLeaderboard; import com.sap.sailing.domain.leaderboard.Leaderboard; @@ -4251,29 +4250,18 @@ public class SailingServiceImpl extends ResultCachingProxiedRemoteServiceServlet @Override public ArrayList getAllIgtimiDevicesWithSecurity() throws IllegalStateException, ClientProtocolException, IOException, org.json.simple.parser.ParseException { - final Map lastHeartBeatsByDeviceSerialNumber = new HashMap<>(); final Map remoteAddressByDeviceSerialNumber = new HashMap<>(); final RiotServer riotServer = getRiotServer(); - for (final RiotConnection connection : riotServer.getLiveConnections()) { // FIXME this ignores replication; we would also want to get this data from all replicas - final String serialNumber = connection.getSerialNumber(); - if (serialNumber != null) { - if (Util.compareToWithNull(connection.getLastHeartbeatReceivedAt(), lastHeartBeatsByDeviceSerialNumber.get(serialNumber), /* null is less */ true) > 0) { - lastHeartBeatsByDeviceSerialNumber.put(serialNumber, connection.getLastHeartbeatReceivedAt()); - } - remoteAddressByDeviceSerialNumber.put(serialNumber, connection.getSocketChannel().getRemoteAddress()); - } - } final MultiTimeRange infiniteTimeRange = MultiTimeRange.of(TimeRange.create(null, null)); return new ArrayList<>(Util.asList(getSecurityService().mapAndFilterByReadPermissionForCurrentUser( riotServer.getDevices(), device->{ + final SocketAddress remoteAddress = remoteAddressByDeviceSerialNumber.get(device.getSerialNumber()); try { return toSecuredIgtimiDeviceDTO( device, - lastHeartBeatsByDeviceSerialNumber.get(device.getSerialNumber()), - remoteAddressByDeviceSerialNumber.get(device.getSerialNumber()), - getPositionFromMessage(riotServer.getLastFix(device.getSerialNumber(), GpsLatLong.class, - infiniteTimeRange)), + remoteAddress == null ? null : remoteAddress.toString(), + getPositionFromMessage(riotServer.getLastFix(device.getSerialNumber(), GpsLatLong.class, infiniteTimeRange)), getBatteryPercentFromMessage(riotServer.getLastFix(device.getSerialNumber(), BatteryLevel.class, infiniteTimeRange))); } catch (org.json.simple.parser.ParseException | IOException e) { throw new RuntimeException(e); @@ -4297,12 +4285,13 @@ public class SailingServiceImpl extends ResultCachingProxiedRemoteServiceServlet } private IgtimiDeviceWithSecurityDTO toSecuredIgtimiDeviceDTO(final Device igtimiDevice, - final TimePoint lastHeartBeat, final SocketAddress remoteAddress, Position lastKnownPosition, double lastKnownBatteryPercent) { + final String remoteAddress, Position lastKnownPosition, double lastKnownBatteryPercent) { final long id = igtimiDevice.getId(); final String serialNumber = igtimiDevice.getSerialNumber(); final String name = igtimiDevice.getName(); + final Pair lastHeartBeat = igtimiDevice.getLastHeartbeat(); final IgtimiDeviceWithSecurityDTO securedDevice = new IgtimiDeviceWithSecurityDTO(id, serialNumber, name, - lastHeartBeat, remoteAddress == null ? null : remoteAddress.toString(), lastKnownPosition, + lastHeartBeat, lastKnownPosition, lastKnownBatteryPercent); SecurityDTOUtil.addSecurityInformation(getSecurityService(), securedDevice); return securedDevice; diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/IgtimiDeviceWithSecurityDTO.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/IgtimiDeviceWithSecurityDTO.java index 7a7a9f48962..b0efc12a31e 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/IgtimiDeviceWithSecurityDTO.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/IgtimiDeviceWithSecurityDTO.java @@ -3,6 +3,7 @@ package com.sap.sailing.gwt.ui.shared; import com.sap.sailing.domain.common.Position; import com.sap.sailing.domain.common.security.SecuredDomainType; import com.sap.sse.common.TimePoint; +import com.sap.sse.common.Util.Pair; import com.sap.sse.security.shared.HasPermissions; import com.sap.sse.security.shared.QualifiedObjectIdentifier; import com.sap.sse.security.shared.TypeRelativeObjectIdentifier; @@ -18,21 +19,19 @@ public class IgtimiDeviceWithSecurityDTO implements SecuredDTO { private long id; private String name; private String serialNumber; - private TimePoint lastHeartBeat; - private String remoteAddress; + private Pair lastHeartBeat; private Position lastKnownPosition; private double lastKnownBatteryPercent; @Deprecated // GWT serialization only IgtimiDeviceWithSecurityDTO() {} - public IgtimiDeviceWithSecurityDTO(long id, String serialNumber, String name, TimePoint lastHeartBeat, - String remoteAddress, Position lastKnownPosition, double lastKnownBatteryPercent) { + public IgtimiDeviceWithSecurityDTO(long id, String serialNumber, String name, Pair lastHeartBeat, + Position lastKnownPosition, double lastKnownBatteryPercent) { this.id = id; this.serialNumber = serialNumber; this.name = name; this.lastHeartBeat = lastHeartBeat; - this.remoteAddress = remoteAddress; this.lastKnownPosition = lastKnownPosition; this.lastKnownBatteryPercent = lastKnownBatteryPercent; } @@ -49,14 +48,10 @@ public class IgtimiDeviceWithSecurityDTO implements SecuredDTO { return serialNumber; } - public TimePoint getLastHeartBeat() { + public Pair getLastHeartBeat() { return lastHeartBeat; } - public String getRemoteAddress() { - return remoteAddress; - } - public Position getLastKnownPosition() { return lastKnownPosition; } diff --git a/java/com.sap.sailing.server/SailingServer (No Proxy, Jetty on 8889, auto-replicate).launch b/java/com.sap.sailing.server/SailingServer (No Proxy, Jetty on 8889, auto-replicate).launch index 3c284643051..4ffa947c582 100755 --- a/java/com.sap.sailing.server/SailingServer (No Proxy, Jetty on 8889, auto-replicate).launch +++ b/java/com.sap.sailing.server/SailingServer (No Proxy, Jetty on 8889, auto-replicate).launch @@ -23,339 +23,335 @@ - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +