/*-
* ============LICENSE_START=======================================================
- * Copyright (C) 2021-2023 Nordix Foundation.
+ * Copyright (C) 2021-2024 Nordix Foundation.
* ================================================================================
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@NonNull
private ParticipantState participantState = ParticipantState.ON_LINE;
+ @NonNull
+ private String lastMsg;
+
@NonNull
private Map<UUID, ParticipantSupportedElementType> participantSupportedElementTypes = new HashMap<>();
public Participant(Participant otherParticipant) {
this.participantState = otherParticipant.participantState;
this.participantId = otherParticipant.participantId;
+ this.lastMsg = otherParticipant.lastMsg;
this.participantSupportedElementTypes = PfUtils.mapMap(otherParticipant.getParticipantSupportedElementTypes(),
ParticipantSupportedElementType::new);
}
/*-
* ============LICENSE_START=======================================================
- * Copyright (C) 2021-2023 Nordix Foundation.
+ * Copyright (C) 2021-2024 Nordix Foundation.
* ================================================================================
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
import jakarta.persistence.OneToMany;
import jakarta.persistence.Table;
import java.io.Serializable;
+import java.sql.Timestamp;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import org.apache.commons.lang3.ObjectUtils;
import org.onap.policy.clamp.models.acm.concepts.Participant;
import org.onap.policy.clamp.models.acm.concepts.ParticipantState;
+import org.onap.policy.clamp.models.acm.utils.TimestampHelper;
import org.onap.policy.common.parameters.annotations.NotNull;
import org.onap.policy.common.parameters.annotations.Valid;
import org.onap.policy.models.base.PfAuthorative;
@Column
private String description;
+ @Column
+ @NotNull
+ private Timestamp lastMsg;
+
@NotNull
@OneToMany(fetch = FetchType.EAGER, cascade = CascadeType.ALL)
@JoinColumn(name = "participantId", referencedColumnName = "participantId",
this.participantId = participantId;
this.participantState = participantState;
this.supportedElements = supportedElements;
+ this.lastMsg = TimestampHelper.nowTimestamp();
}
/**
this.description = copyConcept.description;
this.participantId = copyConcept.participantId;
this.supportedElements = copyConcept.supportedElements;
+ this.lastMsg = copyConcept.lastMsg;
}
/**
participant.setParticipantState(participantState);
participant.setParticipantId(UUID.fromString(participantId));
+ participant.setLastMsg(this.lastMsg.toString());
participant.setParticipantSupportedElementTypes(new LinkedHashMap<>(this.supportedElements.size()));
for (var element : this.supportedElements) {
participant.getParticipantSupportedElementTypes()
public void fromAuthorative(@NonNull final Participant participant) {
this.setParticipantState(participant.getParticipantState());
this.participantId = participant.getParticipantId().toString();
+ this.lastMsg = TimestampHelper.toTimestamp(participant.getLastMsg());
this.supportedElements = new ArrayList<>(participant.getParticipantSupportedElementTypes().size());
for (var elementEntry : participant.getParticipantSupportedElementTypes().entrySet()) {
return result;
}
+ result = lastMsg.compareTo(other.lastMsg);
+ if (result != 0) {
+ return result;
+ }
+
result = ObjectUtils.compare(participantState, other.participantState);
if (result != 0) {
return result;
--- /dev/null
+/*-
+ * ============LICENSE_START=======================================================
+ * Copyright (C) 2024 Nordix Foundation.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.policy.clamp.models.acm.utils;
+
+import java.sql.Timestamp;
+import java.time.Instant;
+import lombok.AccessLevel;
+import lombok.NoArgsConstructor;
+
+@NoArgsConstructor(access = AccessLevel.PRIVATE)
+public class TimestampHelper {
+
+ public static String now() {
+ return Timestamp.from(Instant.now()).toString();
+ }
+
+ public static Timestamp nowTimestamp() {
+ return Timestamp.from(Instant.now());
+ }
+
+ public static Timestamp toTimestamp(String time) {
+ return Timestamp.valueOf(time);
+ }
+
+ public static long nowEpochMilli() {
+ return Instant.now().toEpochMilli();
+ }
+
+ public static long toEpochMilli(String time) {
+ return Timestamp.valueOf(time).toInstant().toEpochMilli();
+ }
+}
/*-
* ============LICENSE_START=======================================================
- * Copyright (C) 2023 Nordix Foundation.
+ * Copyright (C) 2023-2024 Nordix Foundation.
* ================================================================================
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
import java.util.HashMap;
import java.util.UUID;
import org.junit.jupiter.api.Test;
+import org.onap.policy.clamp.models.acm.utils.TimestampHelper;
class ParticipantInformationTest {
var participant = new Participant();
participant.setParticipantId(UUID.randomUUID());
participant.setParticipantState(ParticipantState.ON_LINE);
+ participant.setLastMsg(TimestampHelper.now());
participant.setParticipantSupportedElementTypes(new HashMap<>());
var participantInfo1 = new ParticipantInformation();
participantInfo1.setParticipant(participant);
/*-
* ============LICENSE_START=======================================================
- * Copyright (C) 2021-2023 Nordix Foundation.
+ * Copyright (C) 2021-2024 Nordix Foundation.
* ================================================================================
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
import static org.junit.jupiter.api.Assertions.assertNotEquals;
import static org.junit.jupiter.api.Assertions.assertTrue;
+import java.sql.Timestamp;
+import java.time.Instant;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.UUID;
import org.junit.jupiter.api.Test;
import org.onap.policy.clamp.models.acm.concepts.Participant;
import org.onap.policy.clamp.models.acm.concepts.ParticipantState;
+import org.onap.policy.clamp.models.acm.utils.TimestampHelper;
/**
* Test the {@link JpaParticipant} class.
@Test
void testJpaParticipantConstructor() {
+ assertThatThrownBy(() -> new JpaParticipant((Participant) null))
+ .hasMessageMatching("authorativeConcept is marked .*ull but is null");
+
assertThatThrownBy(() -> new JpaParticipant((JpaParticipant) null))
.hasMessageMatching("copyConcept is marked .*ull but is null");
@Test
void testJpaParticipant() {
- var testJpaParticipant = createJpaParticipantInstance();
-
var participant = createParticipantInstance();
-
- participant.setParticipantId(testJpaParticipant.toAuthorative().getParticipantId());
+ var testJpaParticipant = new JpaParticipant(participant);
assertEquals(participant, testJpaParticipant.toAuthorative());
@Test
void testJpaParticipantValidation() {
- var testJpaParticipant = createJpaParticipantInstance();
+ var testJpaParticipant = new JpaParticipant(createParticipantInstance());
assertThatThrownBy(() -> testJpaParticipant.validate(null))
.hasMessageMatching("fieldName is marked .*ull but is null");
@Test
void testJpaParticipantCompareTo() {
- var testJpaParticipant = createJpaParticipantInstance();
+ var testJpaParticipant = new JpaParticipant(createParticipantInstance());
var otherJpaParticipant = new JpaParticipant(testJpaParticipant);
otherJpaParticipant.setParticipantId(testJpaParticipant.getParticipantId());
assertEquals(0, testJpaParticipant.compareTo(otherJpaParticipant));
assertEquals(testJpaParticipant, new JpaParticipant(testJpaParticipant));
+ testJpaParticipant.setLastMsg(Timestamp.from(Instant.EPOCH));
+ assertNotEquals(0, testJpaParticipant.compareTo(otherJpaParticipant));
+ testJpaParticipant.setLastMsg(otherJpaParticipant.getLastMsg());
+ assertEquals(0, testJpaParticipant.compareTo(otherJpaParticipant));
+ assertEquals(testJpaParticipant, new JpaParticipant(testJpaParticipant));
+
var newJpaParticipant = new JpaParticipant(testJpaParticipant);
newJpaParticipant.setParticipantId(testJpaParticipant.getParticipantId());
assertEquals(testJpaParticipant, newJpaParticipant);
var p2 = new JpaParticipant();
p2.setParticipantId(p0.getParticipantId());
+ p2.setLastMsg(p0.getLastMsg());
assertEquals(p2, p0);
}
- private JpaParticipant createJpaParticipantInstance() {
- var testParticipant = createParticipantInstance();
- var testJpaParticipant = new JpaParticipant();
- testParticipant.setParticipantId(UUID.fromString(testJpaParticipant.getParticipantId()));
- testJpaParticipant.fromAuthorative(testParticipant);
- testJpaParticipant.fromAuthorative(testParticipant);
-
- return testJpaParticipant;
- }
-
private Participant createParticipantInstance() {
var testParticipant = new Participant();
testParticipant.setParticipantId(UUID.randomUUID());
+ testParticipant.setLastMsg(TimestampHelper.now());
testParticipant.setParticipantSupportedElementTypes(new LinkedHashMap<>());
return testParticipant;
--- /dev/null
+/*-
+ * ============LICENSE_START=======================================================
+ * Copyright (C) 2024 Nordix Foundation.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.policy.clamp.models.acm.utils;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+import org.junit.jupiter.api.Test;
+
+class TimestampHelperTest {
+
+ @Test
+ void testNow() {
+ assertThat(TimestampHelper.nowTimestamp()).isNotNull();
+ assertThat(TimestampHelper.now()).isNotNull();
+ assertThat(TimestampHelper.nowEpochMilli()).isNotNull();
+ }
+
+ @Test
+ void testToEpochMilli() {
+ var timeStr = TimestampHelper.now();
+ var milli = TimestampHelper.toTimestamp(timeStr).toInstant().toEpochMilli();
+ var result = TimestampHelper.toEpochMilli(timeStr);
+ assertThat(milli).isEqualTo(result);
+ }
+}
"participantState": "ON_LINE",
"description": "A dummy PMSH participant1",
"participantId": "82fd8ef9-1d1e-4343-9b28-7f9564ee3de6",
+ "lastMsg": "2024-05-22 10:04:37.6020187",
"participantSupportedElementTypes": {
"68fe8c61-7629-4be7-99d8-18bc6a92d178": {
"id": "68fe8c61-7629-4be7-99d8-18bc6a92d178",
import lombok.RequiredArgsConstructor;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Aspect;
-import org.aspectj.lang.annotation.Before;
-import org.onap.policy.clamp.models.acm.messages.kafka.participant.ParticipantStatus;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.scheduling.annotation.Scheduled;
}
}
- @Before("@annotation(MessageIntercept) && args(participantStatusMsg,..)")
- public void handleParticipantStatus(ParticipantStatus participantStatusMsg) {
- executor.execute(() -> partecipantScanner.handleParticipantStatus(participantStatusMsg.getParticipantId()));
- }
-
@Override
public void close() throws IOException {
executor.shutdown();
/*-
* ============LICENSE_START=======================================================
- * Copyright (C) 2023 Nordix Foundation.
+ * Copyright (C) 2023-2024 Nordix Foundation.
* ================================================================================
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
package org.onap.policy.clamp.acm.runtime.supervision;
-import java.util.UUID;
import org.onap.policy.clamp.acm.runtime.main.parameters.AcRuntimeParameterGroup;
import org.onap.policy.clamp.models.acm.concepts.Participant;
import org.onap.policy.clamp.models.acm.concepts.ParticipantState;
import org.onap.policy.clamp.models.acm.persistence.provider.ParticipantProvider;
+import org.onap.policy.clamp.models.acm.utils.TimestampHelper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
public class SupervisionPartecipantScanner {
private static final Logger LOGGER = LoggerFactory.getLogger(SupervisionPartecipantScanner.class);
- private final TimeoutHandler<UUID> participantStatusTimeout = new TimeoutHandler<>();
+ private final long maxWaitMs;
private final ParticipantProvider participantProvider;
public SupervisionPartecipantScanner(final ParticipantProvider participantProvider,
final AcRuntimeParameterGroup acRuntimeParameterGroup) {
this.participantProvider = participantProvider;
-
- participantStatusTimeout.setMaxWaitMs(acRuntimeParameterGroup.getParticipantParameters().getMaxStatusWaitMs());
+ this.maxWaitMs = acRuntimeParameterGroup.getParticipantParameters().getMaxStatusWaitMs();
}
/**
private void scanParticipantStatus(Participant participant) {
var id = participant.getParticipantId();
- if (participantStatusTimeout.isTimeout(id)) {
- if (ParticipantState.ON_LINE.equals(participant.getParticipantState())) {
- // restart scenario
- LOGGER.debug("Participant is back ON_LINE {}", id);
- participantStatusTimeout.clear(id);
- } else {
- LOGGER.debug("report Participant is still OFF_LINE {}", id);
- return;
- }
+ if (ParticipantState.OFF_LINE.equals(participant.getParticipantState())) {
+ LOGGER.debug("report Participant is still OFF_LINE {}", id);
+ return;
}
- if (participantStatusTimeout.getDuration(id) > participantStatusTimeout.getMaxWaitMs()) {
+ var now = TimestampHelper.nowEpochMilli();
+ var lastMsg = TimestampHelper.toEpochMilli(participant.getLastMsg());
+ if ((now - lastMsg) > maxWaitMs) {
LOGGER.debug("report Participant OFF_LINE {}", id);
- participantStatusTimeout.setTimeout(id);
participant.setParticipantState(ParticipantState.OFF_LINE);
participantProvider.updateParticipant(participant);
}
}
-
- /**
- * handle participant Status message.
- */
- public void handleParticipantStatus(UUID id) {
- LOGGER.debug("Participant is ON_LINE {}", id);
- participantStatusTimeout.clear(id);
- }
}
import org.onap.policy.clamp.models.acm.persistence.provider.AcDefinitionProvider;
import org.onap.policy.clamp.models.acm.persistence.provider.AutomationCompositionProvider;
import org.onap.policy.clamp.models.acm.persistence.provider.ParticipantProvider;
+import org.onap.policy.clamp.models.acm.utils.TimestampHelper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
private void checkOnline(Participant participant) {
if (ParticipantState.OFF_LINE.equals(participant.getParticipantState())) {
participant.setParticipantState(ParticipantState.ON_LINE);
- participantProvider.saveParticipant(participant);
}
+ participant.setLastMsg(TimestampHelper.now());
+ participantProvider.saveParticipant(participant);
}
private void handleRestart(UUID participantId) {
participant.setParticipantId(participantId);
participant.setParticipantSupportedElementTypes(participantSupportedElementType);
participant.setParticipantState(ParticipantState.ON_LINE);
+ participant.setLastMsg(TimestampHelper.now());
return participant;
}
import static org.mockito.Mockito.verify;
import org.junit.jupiter.api.Test;
-import org.onap.policy.clamp.acm.runtime.util.CommonTestData;
-import org.onap.policy.clamp.models.acm.messages.kafka.participant.ParticipantStatus;
class SupervisionAspectTest {
verify(supervisionScanner, timeout(500).times(2)).run();
}
}
-
- @Test
- void testHandleParticipantStatus() throws Exception {
- var participantStatusMessage = new ParticipantStatus();
- participantStatusMessage.setParticipantId(CommonTestData.getParticipantId());
-
- var supervisionScanner = mock(SupervisionScanner.class);
- var partecipantScanner = mock(SupervisionPartecipantScanner.class);
- try (var supervisionAspect = new SupervisionAspect(supervisionScanner, partecipantScanner)) {
- supervisionAspect.handleParticipantStatus(participantStatusMessage);
- verify(partecipantScanner, timeout(500)).handleParticipantStatus(CommonTestData.getParticipantId());
- }
- }
}
/*-
* ============LICENSE_START=======================================================
- * Copyright (C) 2023 Nordix Foundation.
+ * Copyright (C) 2023-2024 Nordix Foundation.
* ================================================================================
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
import org.onap.policy.clamp.acm.runtime.util.CommonTestData;
import org.onap.policy.clamp.models.acm.concepts.ParticipantState;
import org.onap.policy.clamp.models.acm.persistence.provider.ParticipantProvider;
-import org.onap.policy.models.base.PfModelException;
class SupervisionParticipantScannerTest {
@Test
- void testScanParticipant() throws PfModelException {
+ void testScanParticipant() {
var acRuntimeParameterGroup = CommonTestData.geParameterGroup("dbScanParticipant");
acRuntimeParameterGroup.getParticipantParameters().setMaxStatusWaitMs(-1);
var participant = CommonTestData.createParticipant(CommonTestData.getParticipantId());
- participant.setParticipantState(ParticipantState.OFF_LINE);
var participantProvider = mock(ParticipantProvider.class);
when(participantProvider.getParticipants()).thenReturn(List.of(participant));
var supervisionScanner = new SupervisionPartecipantScanner(participantProvider, acRuntimeParameterGroup);
- supervisionScanner.handleParticipantStatus(participant.getParticipantId());
+ participant.setParticipantState(ParticipantState.OFF_LINE);
supervisionScanner.run();
- verify(participantProvider, times(0)).saveParticipant(any());
+ verify(participantProvider, times(0)).updateParticipant(any());
+ participant.setParticipantState(ParticipantState.ON_LINE);
supervisionScanner.run();
verify(participantProvider, times(1)).updateParticipant(any());
}
/*-
* ============LICENSE_START=======================================================
- * Copyright (C) 2021-2023 Nordix Foundation.
+ * Copyright (C) 2021-2024 Nordix Foundation.
* ================================================================================
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
package org.onap.policy.clamp.acm.runtime.util;
import jakarta.ws.rs.core.Response.Status;
-import java.util.List;
import java.util.UUID;
import org.onap.policy.clamp.acm.runtime.main.parameters.AcRuntimeParameterGroup;
import org.onap.policy.clamp.acm.runtime.main.parameters.AcmParameters;
import org.onap.policy.clamp.models.acm.concepts.ParticipantState;
import org.onap.policy.clamp.models.acm.concepts.ParticipantSupportedElementType;
import org.onap.policy.clamp.models.acm.utils.AcmUtils;
+import org.onap.policy.clamp.models.acm.utils.TimestampHelper;
import org.onap.policy.common.utils.coder.Coder;
import org.onap.policy.common.utils.coder.CoderException;
import org.onap.policy.common.utils.coder.StandardCoder;
.replace("${dbName}", "jdbc:h2:mem:" + dbName);
}
- /**
- * Create a List of Participants.
- *
- * @return a List of Participants
- */
- public static List<Participant> createParticipants() {
- var participant1 = createParticipant(UUID.fromString("101c62b3-8918-41b9-a747-d21eb79c6c02"));
- var participant2 = createParticipant(UUID.fromString("101c62b3-8918-41b9-a747-d21eb79c6c01"));
- var participant3 = createParticipant(UUID.fromString("101c62b3-8918-41b9-a747-d21eb79c6c03"));
- return List.of(participant1, participant2, participant3);
- }
-
/**
* Create a new Participant.
*
var participant = new Participant();
participant.setParticipantId(participantId);
participant.setParticipantState(ParticipantState.ON_LINE);
+ participant.setLastMsg(TimestampHelper.now());
return participant;
}
"participantState": "ON_LINE",
"description": "A dummy PMSH participant1",
"participantId": "82fd8ef9-1d1e-4343-9b28-7f9564ee3de6",
+ "lastMsg": "2024-05-22 10:04:37.6020187",
"participantType": {
"name": "org.onap.domain.pmsh.PolicyAutomationCompositionDefinition",
"version": "1.0.0"
"participantState": "ON_LINE",
"description": "A dummy PMSH participant2",
"participantId": "cac01d0a-7ba8-4dda-b9be-6983c46c0546",
+ "lastMsg": "2024-05-22 10:04:37.6020187",
"participantType": {
"name": "org.onap.domain.pmsh.PolicyAutomationCompositionDefinition2",
"version": "1.0.0"