Skip to content

Commit

Permalink
Initialize invocation counter in same session as original request
Browse files Browse the repository at this point in the history
Signed-off-by: Gerben Kroes <[email protected]>
  • Loading branch information
kroesctrl committed Oct 18, 2023
1 parent f01d80c commit 0623b2d
Show file tree
Hide file tree
Showing 5 changed files with 77 additions and 146 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -113,16 +113,30 @@ private void createAndHandleConnectionForDevice(
final ConnectionProperties connectionProperties,
final MessageMetadata messageMetadata,
final Permit permit,
final Consumer<DlmsConnectionManager> taskForConnectionManager)
final Consumer<DlmsConnectionManager> originalTaskForConnectionManager)
throws OsgpException {

if (connectionProperties.isPingDevice()) {
this.devicePingConfig.pinger().ping(device.getIpAddress());
}

final Consumer<DlmsConnectionManager> taskForConnectionManager;
if (connectionProperties.isInitializeInvocationCounter()) {
this.delay(connectionProperties.getWaitBeforeInitializingInvocationCounter());
this.invocationCounterManager.initializeInvocationCounter(messageMetadata, device);

/*
* When the invocation counter is out of sync, the device closes the session.
* By setting the ip-address to null, the application will be forced to get a new ip-address.
* This is done by the DlmsConnectionFactory in the method:
* this.domainHelperService.setIpAddressFromMessageMetadataOrSessionProvider
*/
device.setIpAddress(null);

taskForConnectionManager =
this.invocationCounterManager.addInitializeInvocationCounterTask(
device, originalTaskForConnectionManager);
} else {
taskForConnectionManager = originalTaskForConnectionManager;
}

try {
Expand Down Expand Up @@ -152,7 +166,7 @@ private void createAndHandleConnectionForDevice(
newConnectionProperties,
messageMetadata,
permit,
taskForConnectionManager);
originalTaskForConnectionManager);
return;
}
/*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,22 +5,16 @@
package org.opensmartgridplatform.adapter.protocol.dlms.domain.factories;

import java.util.Objects;
import java.util.function.Consumer;
import org.openmuc.jdlms.AttributeAddress;
import org.openmuc.jdlms.ObisCode;
import org.opensmartgridplatform.adapter.protocol.dlms.domain.commands.utils.DlmsHelper;
import org.opensmartgridplatform.adapter.protocol.dlms.domain.entities.DlmsDevice;
import org.opensmartgridplatform.adapter.protocol.dlms.domain.repositories.DlmsDeviceRepository;
import org.opensmartgridplatform.adapter.protocol.dlms.exceptions.ThrowingConsumer;
import org.opensmartgridplatform.adapter.protocol.dlms.infra.messaging.DlmsLogItemRequestMessageSender;
import org.opensmartgridplatform.adapter.protocol.dlms.infra.messaging.DlmsMessageListener;
import org.opensmartgridplatform.adapter.protocol.dlms.infra.messaging.InvocationCountingDlmsMessageListener;
import org.opensmartgridplatform.adapter.protocol.dlms.infra.messaging.LoggingDlmsMessageListener;
import org.opensmartgridplatform.shared.exceptionhandling.ComponentType;
import org.opensmartgridplatform.shared.exceptionhandling.FunctionalException;
import org.opensmartgridplatform.shared.exceptionhandling.FunctionalExceptionType;
import org.opensmartgridplatform.shared.exceptionhandling.OsgpException;
import org.opensmartgridplatform.shared.infra.jms.MessageMetadata;
import org.opensmartgridplatform.throttling.api.Permit;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
Expand All @@ -36,59 +30,35 @@ public class InvocationCounterManager {
private static final AttributeAddress ATTRIBUTE_ADDRESS_INVOCATION_COUNTER_VALUE =
new AttributeAddress(1, new ObisCode(new byte[] {0, 0, 43, 1, 0, -1}), 2);

private final DlmsConnectionFactory connectionFactory;
private final DlmsHelper dlmsHelper;
private final DlmsDeviceRepository deviceRepository;
private final DlmsLogItemRequestMessageSender dlmsLogItemRequestMessageSender;

@Autowired
public InvocationCounterManager(
final DlmsConnectionFactory connectionFactory,
final DlmsHelper dlmsHelper,
final DlmsDeviceRepository deviceRepository,
final DlmsLogItemRequestMessageSender dlmsLogItemRequestMessageSender) {
this.connectionFactory = connectionFactory;
final DlmsHelper dlmsHelper, final DlmsDeviceRepository deviceRepository) {
this.dlmsHelper = dlmsHelper;
this.deviceRepository = deviceRepository;
this.dlmsLogItemRequestMessageSender = dlmsLogItemRequestMessageSender;
}

/**
* Updates the device instance with the invocation counter value on the actual device. Should only
* be called for a device that actually has an invocation counter stored on the device itself.
*/
public void initializeInvocationCounter(
final MessageMetadata messageMetadata, final DlmsDevice device) throws OsgpException {

/*
* When the invocation counter is out of sync, the device closes the session.
* By setting the ip-address to null, the application will be forced to get a new ip-address.
* This is done by the DlmsConnectionFactory in the method:
* this.domainHelperService.setIpAddressFromMessageMetadataOrSessionProvider
*/
device.setIpAddress(null);

this.initializeWithInvocationCounterStoredOnDevice(messageMetadata, device, null);
public Consumer<DlmsConnectionManager> addInitializeInvocationCounterTask(
final DlmsDevice device,
final Consumer<DlmsConnectionManager> originalTaskForConnectionManager) {
final Consumer<DlmsConnectionManager> initializeTask =
(ThrowingConsumer<DlmsConnectionManager>)
connectionManager ->
this.initializeWithInvocationCounterStoredOnDeviceTask(device, connectionManager);
return initializeTask.andThen(originalTaskForConnectionManager);
}

/**
* Updates the device instance with the invocation counter value on the actual device. Should only
* be called for a device that actually has an invocation counter stored on the device itself. If
* a permit for network access is passed, it is to be released upon closing the connection.
*/
private void initializeWithInvocationCounterStoredOnDevice(
final MessageMetadata messageMetadata, final DlmsDevice device, final Permit permit)
throws OsgpException {

final ThrowingConsumer<DlmsConnectionManager> taskForConnectionManager =
public Consumer<DlmsConnectionManager> createInitializeInvocationCounterTask(
final DlmsDevice device) {
return (ThrowingConsumer<DlmsConnectionManager>)
connectionManager ->
this.initializeWithInvocationCounterStoredOnDeviceTask(device, connectionManager);

final DlmsMessageListener dlmsMessageListener =
this.createMessageListenerForDeviceConnection(device, messageMetadata);

this.connectionFactory.createAndHandlePublicClientConnection(
messageMetadata, device, dlmsMessageListener, permit, taskForConnectionManager);
}

void initializeWithInvocationCounterStoredOnDeviceTask(
Expand Down Expand Up @@ -136,19 +106,4 @@ private long getInvocationCounter(final DlmsConnectionManager connectionManager)
.getValue();
return invocationCounter.longValue();
}

protected DlmsMessageListener createMessageListenerForDeviceConnection(
final DlmsDevice device, final MessageMetadata messageMetadata) {
final InvocationCountingDlmsMessageListener dlmsMessageListener;
if (device.isInDebugMode()) {
dlmsMessageListener =
new LoggingDlmsMessageListener(
device.getDeviceIdentification(), this.dlmsLogItemRequestMessageSender);
dlmsMessageListener.setMessageMetadata(messageMetadata);
dlmsMessageListener.setDescription("Create connection");
} else {
dlmsMessageListener = null;
}
return dlmsMessageListener;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
import org.opensmartgridplatform.adapter.protocol.dlms.domain.entities.DlmsDevice;
import org.opensmartgridplatform.adapter.protocol.dlms.domain.entities.DlmsDeviceBuilder;
import org.opensmartgridplatform.adapter.protocol.dlms.exceptions.ConnectionException;
import org.opensmartgridplatform.adapter.protocol.dlms.exceptions.ThrowingConsumer;
import org.opensmartgridplatform.adapter.protocol.dlms.infra.messaging.DlmsMessageListener;
import org.opensmartgridplatform.adapter.protocol.dlms.infra.messaging.InvocationCountingDlmsMessageListener;
import org.opensmartgridplatform.shared.infra.jms.MessageMetadata;
Expand Down Expand Up @@ -135,14 +136,16 @@ void noInteractionsWithInvocationCounterManagerForDeviceThatDoesNotNeedInvocatio
.build();
final DlmsMessageListener listener = new InvocationCountingDlmsMessageListener();

final Consumer<DlmsConnectionManager> initTask = this.createInitTask();
when(this.invocationCounterManager.addInitializeInvocationCounterTask(device, this.task))
.thenReturn(initTask);

doNothing()
.when(this.connectionFactory)
.createAndHandleConnection(this.messageMetadata, device, listener, null, this.task);
.createAndHandleConnection(this.messageMetadata, device, listener, null, initTask);

this.helper.createAndHandleConnectionForDevice(
this.messageMetadata, device, listener, this.task);

verify(this.invocationCounterManager).initializeInvocationCounter(this.messageMetadata, device);
}

@Test
Expand Down Expand Up @@ -173,6 +176,10 @@ void initializesInvocationCounterWhenInvocationCounterIsOutOfSyncForIskraDevice(
.build();
final DlmsMessageListener listener = new InvocationCountingDlmsMessageListener();

final Consumer<DlmsConnectionManager> initTask = this.createInitTask();
when(this.invocationCounterManager.addInitializeInvocationCounterTask(device, this.task))
.thenReturn(initTask);

final ConnectionException exception =
new ConnectionException(
"Error creating connection for device E0033006878667817 with Ip address:62.133.86.119 Port:4059 "
Expand All @@ -181,16 +188,20 @@ void initializesInvocationCounterWhenInvocationCounterIsOutOfSyncForIskraDevice(
doThrow(exception)
.when(this.connectionFactory)
.createAndHandleConnection(this.messageMetadata, device, listener, null, this.task);
doThrow(exception)
.when(this.connectionFactory)
.createAndHandleConnection(this.messageMetadata, device, listener, null, initTask);

assertThrows(
ConnectionException.class,
() ->
this.helper.createAndHandleConnectionForDevice(
this.messageMetadata, device, listener, null, this.task));

verify(this.invocationCounterManager).initializeInvocationCounter(this.messageMetadata, device);
verify(this.connectionFactory, times(2))
verify(this.connectionFactory, times(1))
.createAndHandleConnection(this.messageMetadata, device, listener, null, this.task);
verify(this.connectionFactory, times(1))
.createAndHandleConnection(this.messageMetadata, device, listener, null, initTask);
}

@Test
Expand All @@ -204,23 +215,31 @@ void initializesInvocationCounterWhenInvocationCounterIsOutOfSyncForLAndGDevice(
.build();
final DlmsMessageListener listener = new InvocationCountingDlmsMessageListener();

final Consumer<DlmsConnectionManager> initTask = this.createInitTask();
when(this.invocationCounterManager.addInitializeInvocationCounterTask(device, this.task))
.thenReturn(initTask);

final ConnectionException exception =
new ConnectionException(
"Error creating connection for device E0051004228715518 with Ip address:62.133.88.34 Port:null "
+ "UseHdlc:false UseSn:false Message:Socket was closed by remote host.");
doThrow(exception)
.when(this.connectionFactory)
.createAndHandleConnection(this.messageMetadata, device, listener, null, this.task);
doThrow(exception)
.when(this.connectionFactory)
.createAndHandleConnection(this.messageMetadata, device, listener, null, initTask);

assertThrows(
ConnectionException.class,
() ->
this.helper.createAndHandleConnectionForDevice(
this.messageMetadata, device, listener, null, this.task));

verify(this.invocationCounterManager).initializeInvocationCounter(this.messageMetadata, device);
verify(this.connectionFactory, times(2))
verify(this.connectionFactory, times(1))
.createAndHandleConnection(this.messageMetadata, device, listener, null, this.task);
verify(this.connectionFactory, times(1))
.createAndHandleConnection(this.messageMetadata, device, listener, null, initTask);
}

@Test
Expand All @@ -233,23 +252,30 @@ void invocationCounterUpdateSuccesfull() throws Exception {
.build();
final DlmsMessageListener listener = new InvocationCountingDlmsMessageListener();

final Consumer<DlmsConnectionManager> initTask = this.createInitTask();
when(this.invocationCounterManager.addInitializeInvocationCounterTask(device, this.task))
.thenReturn(initTask);

final ConnectionException exception =
new ConnectionException(
"Error creating connection for device E0051004228715518 with Ip address:62.133.88.34 Port:null "
+ "UseHdlc:false UseSn:false Message:Socket was closed by remote host.");

// First try throw exception, second time no exception
doThrow(exception)
.doNothing()
.when(this.connectionFactory)
.createAndHandleConnection(this.messageMetadata, device, listener, null, this.task);
doNothing()
.when(this.connectionFactory)
.createAndHandleConnection(this.messageMetadata, device, listener, null, initTask);

this.helper.createAndHandleConnectionForDevice(
this.messageMetadata, device, listener, null, this.task);

verify(this.invocationCounterManager).initializeInvocationCounter(this.messageMetadata, device);
verify(this.connectionFactory, times(2))
verify(this.connectionFactory, times(1))
.createAndHandleConnection(this.messageMetadata, device, listener, null, this.task);
verify(this.connectionFactory, times(1))
.createAndHandleConnection(this.messageMetadata, device, listener, null, initTask);
}

@Test
Expand Down Expand Up @@ -280,4 +306,8 @@ void invocationCounterUpdateSuccesfull() throws Exception {

verifyNoMoreInteractions(this.invocationCounterManager);
}

private Consumer<DlmsConnectionManager> createInitTask() {
return (ThrowingConsumer<DlmsConnectionManager>) connectionManager -> {};
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,9 @@

import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.catchThrowableOfType;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.ArgumentMatchers.isNotNull;
import static org.mockito.ArgumentMatchers.isNull;
import static org.mockito.ArgumentMatchers.refEq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;

Expand All @@ -21,6 +17,7 @@
import ch.qos.logback.classic.spi.ILoggingEvent;
import ch.qos.logback.core.read.ListAppender;
import java.util.List;
import java.util.function.Consumer;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
Expand All @@ -33,11 +30,9 @@
import org.opensmartgridplatform.adapter.protocol.dlms.domain.entities.DlmsDevice;
import org.opensmartgridplatform.adapter.protocol.dlms.domain.entities.DlmsDeviceBuilder;
import org.opensmartgridplatform.adapter.protocol.dlms.domain.repositories.DlmsDeviceRepository;
import org.opensmartgridplatform.adapter.protocol.dlms.infra.messaging.DlmsLogItemRequestMessageSender;
import org.opensmartgridplatform.shared.exceptionhandling.FunctionalException;
import org.opensmartgridplatform.shared.exceptionhandling.FunctionalExceptionType;
import org.opensmartgridplatform.shared.exceptionhandling.OsgpException;
import org.opensmartgridplatform.shared.infra.jms.MessageMetadata;
import org.slf4j.LoggerFactory;

@ExtendWith(MockitoExtension.class)
Expand All @@ -47,26 +42,16 @@ class InvocationCounterManagerTest {
private static final String IP_ADDRESS = "1.2.3.4";

private InvocationCounterManager manager;
private MessageMetadata messageMetadata;
private DlmsDevice device;
private final long invocationCounterValueInDatabaseEntity = 7;
private final long initialDeviceVersion = 2;

@Mock private DlmsConnectionFactory connectionFactory;

@Mock private DlmsHelper dlmsHelper;
@Mock private DlmsDeviceRepository deviceRepository;
private DlmsLogItemRequestMessageSender dlmsLogItemRequestMessageSender;

@BeforeEach
void setUp() {
this.manager =
new InvocationCounterManager(
this.connectionFactory,
this.dlmsHelper,
this.deviceRepository,
this.dlmsLogItemRequestMessageSender);
this.messageMetadata = MessageMetadata.newBuilder().withCorrelationUid("123456").build();
this.manager = new InvocationCounterManager(this.dlmsHelper, this.deviceRepository);
this.device =
new DlmsDeviceBuilder()
.withInvocationCounter(this.invocationCounterValueInDatabaseEntity)
Expand All @@ -78,25 +63,10 @@ void setUp() {
void initializeInvocationCounterForDeviceTaskExecuted() throws OsgpException {
this.device.setIpAddress(IP_ADDRESS);

this.manager.initializeInvocationCounter(this.messageMetadata, this.device);

assertThat(this.device.getIpAddress()).isNull();
verify(this.connectionFactory, times(1))
.createAndHandlePublicClientConnection(
any(MessageMetadata.class), eq(this.device), isNull(), isNull(), any());
}

@Test
void initializeInvocationCounterForDeviceTaskExecutedDebugEnabled() throws OsgpException {
this.device.setInDebugMode(true);
this.device.setIpAddress(IP_ADDRESS);

this.manager.initializeInvocationCounter(this.messageMetadata, this.device);
final Consumer<DlmsConnectionManager> task =
this.manager.createInitializeInvocationCounterTask(this.device);

assertThat(this.device.getIpAddress()).isNull();
verify(this.connectionFactory, times(1))
.createAndHandlePublicClientConnection(
any(MessageMetadata.class), eq(this.device), isNotNull(), isNull(), any());
assertThat(task).isNotNull();
}

@Test
Expand Down
Loading

0 comments on commit 0623b2d

Please sign in to comment.