diff options
23 files changed, 1287 insertions, 85 deletions
diff --git a/tosca-controlloop/participant/participant-impl/participant-impl-simulator/src/main/java/org/onap/policy/clamp/controlloop/participant/simulator/main/rest/RestController.java b/tosca-controlloop/participant/participant-impl/participant-impl-simulator/src/main/java/org/onap/policy/clamp/controlloop/participant/simulator/main/rest/RestController.java index 120c52c26..444f37889 100644 --- a/tosca-controlloop/participant/participant-impl/participant-impl-simulator/src/main/java/org/onap/policy/clamp/controlloop/participant/simulator/main/rest/RestController.java +++ b/tosca-controlloop/participant/participant-impl/participant-impl-simulator/src/main/java/org/onap/policy/clamp/controlloop/participant/simulator/main/rest/RestController.java @@ -34,9 +34,7 @@ import javax.ws.rs.core.MediaType; import javax.ws.rs.core.Response.ResponseBuilder; import lombok.AccessLevel; import lombok.Getter; -import lombok.NoArgsConstructor; -import org.onap.policy.clamp.controlloop.common.exception.ControlLoopRuntimeException; -import org.onap.policy.clamp.controlloop.participant.intermediary.parameters.ParticipantIntermediaryParameters; +import org.onap.policy.clamp.controlloop.participant.simulator.simulation.SimulationHandler; import org.onap.policy.clamp.controlloop.participant.simulator.simulation.SimulationProvider; /** @@ -56,7 +54,6 @@ import org.onap.policy.clamp.controlloop.participant.simulator.simulation.Simula tags = {@Tag(name = "participantsim", description = "Participant Simulator")}, securityDefinition = @SecurityDefinition(basicAuthDefinitions = {@BasicAuthDefinition(key = "basicAuth")})) // @formatter:on -@NoArgsConstructor public class RestController { public static final String APPLICATION_YAML = "application/yaml"; @@ -95,17 +92,14 @@ public class RestController { public static final String SERVER_ERROR_MESSAGE = "Internal Server Error"; @Getter(AccessLevel.PROTECTED) // The provider for simulation requests - private static SimulationProvider simulationProvider; + private SimulationProvider simulationProvider; + /** - * Create a participant simulation provider. - * @return - * - * @throws ControlLoopRuntimeException on errors creating the provider + * create a Rest Controller. */ - public static void init(ParticipantIntermediaryParameters participantParameters) - throws ControlLoopRuntimeException { - simulationProvider = new SimulationProvider(participantParameters); + public RestController() { + simulationProvider = SimulationHandler.getInstance().getSimulationProvider(); } /** diff --git a/tosca-controlloop/participant/participant-impl/participant-impl-simulator/src/main/java/org/onap/policy/clamp/controlloop/participant/simulator/main/startstop/ParticipantSimulatorActivator.java b/tosca-controlloop/participant/participant-impl/participant-impl-simulator/src/main/java/org/onap/policy/clamp/controlloop/participant/simulator/main/startstop/ParticipantSimulatorActivator.java index 8658750f8..4daa0393f 100644 --- a/tosca-controlloop/participant/participant-impl/participant-impl-simulator/src/main/java/org/onap/policy/clamp/controlloop/participant/simulator/main/startstop/ParticipantSimulatorActivator.java +++ b/tosca-controlloop/participant/participant-impl/participant-impl-simulator/src/main/java/org/onap/policy/clamp/controlloop/participant/simulator/main/startstop/ParticipantSimulatorActivator.java @@ -53,6 +53,10 @@ public class ParticipantSimulatorActivator extends ServiceManagerContainer { () -> simulationHandler.set(new SimulationHandler(parameters)), () -> simulationHandler.get().close()); + addAction("Simulation Providers", + () -> simulationHandler.get().startProviders(), + () -> simulationHandler.get().stopProviders()); + parameters.getRestServerParameters().setName(parameters.getName()); addAction("REST server", diff --git a/tosca-controlloop/participant/participant-impl/participant-impl-simulator/src/main/java/org/onap/policy/clamp/controlloop/participant/simulator/simulation/SimulationHandler.java b/tosca-controlloop/participant/participant-impl/participant-impl-simulator/src/main/java/org/onap/policy/clamp/controlloop/participant/simulator/simulation/SimulationHandler.java index e409460c0..e6e2609da 100644 --- a/tosca-controlloop/participant/participant-impl/participant-impl-simulator/src/main/java/org/onap/policy/clamp/controlloop/participant/simulator/simulation/SimulationHandler.java +++ b/tosca-controlloop/participant/participant-impl/participant-impl-simulator/src/main/java/org/onap/policy/clamp/controlloop/participant/simulator/simulation/SimulationHandler.java @@ -20,14 +20,20 @@ package org.onap.policy.clamp.controlloop.participant.simulator.simulation; +import java.io.IOException; import java.util.List; import java.util.Set; +import javax.ws.rs.core.Response; +import lombok.Getter; import org.onap.policy.clamp.controlloop.common.handler.ControlLoopHandler; +import org.onap.policy.clamp.controlloop.participant.intermediary.parameters.ParticipantIntermediaryParameters; import org.onap.policy.clamp.controlloop.participant.simulator.main.parameters.ParticipantSimulatorParameters; import org.onap.policy.clamp.controlloop.participant.simulator.simulation.rest.SimulationElementController; import org.onap.policy.clamp.controlloop.participant.simulator.simulation.rest.SimulationParticipantController; import org.onap.policy.common.endpoints.event.comm.TopicSink; import org.onap.policy.common.endpoints.listeners.MessageTypeDispatcher; +import org.onap.policy.common.utils.services.Registry; +import org.onap.policy.models.base.PfModelRuntimeException; /** * This class handles simulation of participants and control loop elements. @@ -35,6 +41,11 @@ import org.onap.policy.common.endpoints.listeners.MessageTypeDispatcher; * <p/>It is effectively a singleton that is started at system start. */ public class SimulationHandler extends ControlLoopHandler { + private final ParticipantIntermediaryParameters participantParameters; + + @Getter + private SimulationProvider simulationProvider; + /** * Create a handler. * @@ -42,6 +53,11 @@ public class SimulationHandler extends ControlLoopHandler { */ public SimulationHandler(ParticipantSimulatorParameters parameters) { super(parameters.getDatabaseProviderParameters()); + participantParameters = parameters.getIntermediaryParameters(); + } + + public static SimulationHandler getInstance() { + return Registry.get(SimulationHandler.class.getName()); } @Override @@ -71,11 +87,15 @@ public class SimulationHandler extends ControlLoopHandler { @Override public void startProviders() { - // No providers on this handler + simulationProvider = new SimulationProvider(participantParameters); } @Override public void stopProviders() { - // No providers on this handler + try { + simulationProvider.close(); + } catch (IOException e) { + throw new PfModelRuntimeException(Response.Status.INTERNAL_SERVER_ERROR, "Stop providers failed ", e); + } } } diff --git a/tosca-controlloop/participant/participant-impl/participant-impl-simulator/src/test/java/org/onap/policy/clamp/controlloop/participant/simulator/main/intermediary/TestControlLoopUpdateListener.java b/tosca-controlloop/participant/participant-impl/participant-impl-simulator/src/test/java/org/onap/policy/clamp/controlloop/participant/simulator/main/intermediary/TestControlLoopUpdateListener.java new file mode 100644 index 000000000..a307d3457 --- /dev/null +++ b/tosca-controlloop/participant/participant-impl/participant-impl-simulator/src/test/java/org/onap/policy/clamp/controlloop/participant/simulator/main/intermediary/TestControlLoopUpdateListener.java @@ -0,0 +1,91 @@ +/*- + * ============LICENSE_START======================================================= + * Copyright (C) 2021 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.controlloop.participant.simulator.main.intermediary; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotEquals; + +import java.io.FileNotFoundException; +import java.io.IOException; +import org.junit.BeforeClass; +import org.junit.Test; +import org.onap.policy.clamp.controlloop.common.exception.ControlLoopException; +import org.onap.policy.clamp.controlloop.models.controlloop.concepts.ControlLoopOrderedState; +import org.onap.policy.clamp.controlloop.models.messages.dmaap.participant.ParticipantControlLoopUpdate; +import org.onap.policy.clamp.controlloop.participant.intermediary.comm.ControlLoopUpdateListener; +import org.onap.policy.clamp.controlloop.participant.simulator.main.parameters.CommonTestData; +import org.onap.policy.clamp.controlloop.participant.simulator.main.rest.TestListenerUtils; +import org.onap.policy.common.endpoints.event.comm.Topic.CommInfrastructure; +import org.onap.policy.common.utils.coder.CoderException; + +/** + * Class to perform unit test of {@link ControlLoopUpdateListener}. + */ +public class TestControlLoopUpdateListener { + private static ControlLoopUpdateListener clUpdateListener; + private static final CommInfrastructure INFRA = CommInfrastructure.NOOP; + private static final String TOPIC = "my-topic"; + static CommonTestData commonTestData = new CommonTestData(); + + /** + * Method for setup. + * + * @throws ParticipantException if some error occurs while starting up the participant + * @throws FileNotFoundException if the file is missing + * @throws IOException if IO exception occurs + */ + @BeforeClass + public static void setUp() throws ControlLoopException, FileNotFoundException, IOException { + TestListenerUtils.initParticipantHandler(); + clUpdateListener = new ControlLoopUpdateListener(TestListenerUtils.getParticipantHandler()); + } + + @Test + public void testControlLoopUpdateListener_ParticipantIdNoMatch() throws CoderException { + ParticipantControlLoopUpdate participantControlLoopUpdateMsg = prepareMsg("DummyName"); + clUpdateListener.onTopicEvent(INFRA, TOPIC, null, participantControlLoopUpdateMsg); + + // Verify the content in participantHandler + assertNotEquals(participantControlLoopUpdateMsg.getParticipantId().getName(), + TestListenerUtils.getParticipantHandler().getParticipantId().getName()); + } + + @Test + public void testControlLoopUpdateListener() throws CoderException { + ParticipantControlLoopUpdate participantControlLoopUpdateMsg = prepareMsg("org.onap.PM_CDS_Blueprint"); + clUpdateListener.onTopicEvent(INFRA, TOPIC, null, participantControlLoopUpdateMsg); + + // Verify the content in participantHandler + assertEquals(TestListenerUtils.getParticipantHandler().getParticipantId(), + participantControlLoopUpdateMsg.getParticipantId()); + assertThat(TestListenerUtils.getParticipantHandler().getControlLoopHandler().getControlLoops() + .getControlLoopList()).hasSize(1); + } + + private ParticipantControlLoopUpdate prepareMsg(final String participantName) { + ParticipantControlLoopUpdate participantControlLoopUpdateMsg; + participantControlLoopUpdateMsg = TestListenerUtils.createControlLoopUpdateMsg(); + participantControlLoopUpdateMsg.getParticipantId().setName(participantName); + participantControlLoopUpdateMsg.getControlLoop().setOrderedState(ControlLoopOrderedState.PASSIVE); + return participantControlLoopUpdateMsg; + } +} diff --git a/tosca-controlloop/participant/participant-impl/participant-impl-simulator/src/test/java/org/onap/policy/clamp/controlloop/participant/simulator/main/parameters/CommonTestData.java b/tosca-controlloop/participant/participant-impl/participant-impl-simulator/src/test/java/org/onap/policy/clamp/controlloop/participant/simulator/main/parameters/CommonTestData.java index e0e001743..0a8754256 100644 --- a/tosca-controlloop/participant/participant-impl/participant-impl-simulator/src/test/java/org/onap/policy/clamp/controlloop/participant/simulator/main/parameters/CommonTestData.java +++ b/tosca-controlloop/participant/participant-impl/participant-impl-simulator/src/test/java/org/onap/policy/clamp/controlloop/participant/simulator/main/parameters/CommonTestData.java @@ -182,9 +182,7 @@ public class CommonTestData { * @return participant Id */ public static ToscaConceptIdentifier getParticipantId() { - final ToscaConceptIdentifier participantId = new ToscaConceptIdentifier(); - participantId.setName("CDSParticipant0"); - participantId.setVersion("1.0.0"); + final ToscaConceptIdentifier participantId = new ToscaConceptIdentifier("org.onap.PM_CDS_Blueprint", "1.0.0"); return participantId; } diff --git a/tosca-controlloop/participant/participant-impl/participant-impl-simulator/src/test/java/org/onap/policy/clamp/controlloop/participant/simulator/main/parameters/TestParticipantSimulatorParameterHandler.java b/tosca-controlloop/participant/participant-impl/participant-impl-simulator/src/test/java/org/onap/policy/clamp/controlloop/participant/simulator/main/parameters/TestParticipantSimulatorParameterHandler.java index f8b11d723..e94939af8 100644 --- a/tosca-controlloop/participant/participant-impl/participant-impl-simulator/src/test/java/org/onap/policy/clamp/controlloop/participant/simulator/main/parameters/TestParticipantSimulatorParameterHandler.java +++ b/tosca-controlloop/participant/participant-impl/participant-impl-simulator/src/test/java/org/onap/policy/clamp/controlloop/participant/simulator/main/parameters/TestParticipantSimulatorParameterHandler.java @@ -20,6 +20,7 @@ package org.onap.policy.clamp.controlloop.participant.simulator.main.parameters; +import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatThrownBy; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; @@ -89,16 +90,15 @@ public class TestParticipantSimulatorParameterHandler { public void testParticipantVersion() throws ControlLoopException { final String[] participantConfigParameters = { "-v" }; final ParticipantSimulatorCommandLineArguments arguments = new ParticipantSimulatorCommandLineArguments(); - final String version = arguments.parse(participantConfigParameters); - assertTrue(version.startsWith("ONAP Tosca defined control loop Participant")); + assertThat(arguments.parse(participantConfigParameters)).startsWith( + "ONAP Tosca defined control loop Participant"); } @Test public void testParticipantHelp() throws ControlLoopException { final String[] participantConfigParameters = { "-h" }; final ParticipantSimulatorCommandLineArguments arguments = new ParticipantSimulatorCommandLineArguments(); - final String help = arguments.parse(participantConfigParameters); - assertTrue(help.startsWith("usage:")); + assertThat(arguments.parse(participantConfigParameters)).startsWith("usage:"); } @Test diff --git a/tosca-controlloop/participant/participant-impl/participant-impl-simulator/src/test/java/org/onap/policy/clamp/controlloop/participant/simulator/main/parameters/TestParticipantSimulatorParameters.java b/tosca-controlloop/participant/participant-impl/participant-impl-simulator/src/test/java/org/onap/policy/clamp/controlloop/participant/simulator/main/parameters/TestParticipantSimulatorParameters.java index dcfbe94b7..2f47641a9 100644 --- a/tosca-controlloop/participant/participant-impl/participant-impl-simulator/src/test/java/org/onap/policy/clamp/controlloop/participant/simulator/main/parameters/TestParticipantSimulatorParameters.java +++ b/tosca-controlloop/participant/participant-impl/participant-impl-simulator/src/test/java/org/onap/policy/clamp/controlloop/participant/simulator/main/parameters/TestParticipantSimulatorParameters.java @@ -23,8 +23,8 @@ package org.onap.policy.clamp.controlloop.participant.simulator.main.parameters; import static org.assertj.core.api.Assertions.assertThat; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; +import java.util.Map; import org.junit.Test; import org.onap.policy.common.parameters.GroupValidationResult; @@ -57,7 +57,7 @@ public class TestParticipantSimulatorParameters { final GroupValidationResult validationResult = participantParameters.validate(); assertFalse(validationResult.isValid()); assertEquals(null, participantParameters.getName()); - assertTrue(validationResult.getResult().contains("is null")); + assertThat(validationResult.getResult()).contains("is null"); } @Test @@ -68,8 +68,8 @@ public class TestParticipantSimulatorParameters { final GroupValidationResult validationResult = participantParameters.validate(); assertFalse(validationResult.isValid()); assertEquals("", participantParameters.getName()); - assertTrue(validationResult.getResult().contains( - "field \"name\" type \"java.lang.String\" value \"\" INVALID, " + "must be a non-blank string")); + assertThat(validationResult.getResult()).contains( + "field \"name\" type \"java.lang.String\" value \"\" INVALID, " + "must be a non-blank string"); } @Test @@ -81,4 +81,36 @@ public class TestParticipantSimulatorParameters { assertThat(participantParameters.validate().isValid()).isTrue(); assertEquals("ParticipantNewGroup", participantParameters.getName()); } + + @Test + public void testParticipantParameterGroup_EmptyParticipantIntermediaryParameters() { + final Map<String, Object> map = + commonTestData.getParticipantParameterGroupMap(CommonTestData.PARTICIPANT_GROUP_NAME); + map.replace("intermediaryParameters", commonTestData.getIntermediaryParametersMap(true)); + final ParticipantSimulatorParameters participantParameters = + commonTestData.toObject(map, ParticipantSimulatorParameters.class); + final GroupValidationResult validationResult = participantParameters.validate(); + assertFalse(validationResult.isValid()); + assertThat(validationResult.getResult()).contains( + "\"org.onap.policy.clamp.controlloop.participant.simulator.main.parameters." + + "ParticipantSimulatorParameters\"" + + " INVALID, parameter group has status INVALID"); + } + + @Test + public void testParticipantParameterGroupp_EmptyTopicParameters() { + final Map<String, Object> map = + commonTestData.getParticipantParameterGroupMap(CommonTestData.PARTICIPANT_GROUP_NAME); + final Map<String, Object> intermediaryParametersMap = commonTestData.getIntermediaryParametersMap(false); + intermediaryParametersMap.put("clampControlLoopTopics", commonTestData.getTopicParametersMap(true)); + map.replace("intermediaryParameters", intermediaryParametersMap); + + final ParticipantSimulatorParameters participantParameters = + commonTestData.toObject(map, ParticipantSimulatorParameters.class); + final GroupValidationResult validationResult = participantParameters.validate(); + assertFalse(validationResult.isValid()); + assertThat(validationResult.getResult()) + .contains("\"org.onap.policy.common.endpoints.parameters.TopicParameterGroup\" INVALID, " + + "parameter group has status INVALID"); + } } diff --git a/tosca-controlloop/participant/participant-impl/participant-impl-simulator/src/test/java/org/onap/policy/clamp/controlloop/participant/simulator/main/rest/CommonParticipantRestServer.java b/tosca-controlloop/participant/participant-impl/participant-impl-simulator/src/test/java/org/onap/policy/clamp/controlloop/participant/simulator/main/rest/CommonParticipantRestServer.java index 7aae32629..ae004de49 100644 --- a/tosca-controlloop/participant/participant-impl/participant-impl-simulator/src/test/java/org/onap/policy/clamp/controlloop/participant/simulator/main/rest/CommonParticipantRestServer.java +++ b/tosca-controlloop/participant/participant-impl/participant-impl-simulator/src/test/java/org/onap/policy/clamp/controlloop/participant/simulator/main/rest/CommonParticipantRestServer.java @@ -21,7 +21,7 @@ package org.onap.policy.clamp.controlloop.participant.simulator.main.rest; -import static org.junit.Assert.assertTrue; +import static org.assertj.core.api.Assertions.assertThat; import java.io.File; import java.io.FileNotFoundException; @@ -127,8 +127,7 @@ public class CommonParticipantRestServer { */ protected void testSwagger(final String endpoint) throws Exception { final Invocation.Builder invocationBuilder = sendFqeRequest(httpPrefix + "swagger.yaml", true); - final String resp = invocationBuilder.get(String.class); - assertTrue(resp.contains(ENDPOINT_PREFIX + endpoint + ":")); + assertThat(invocationBuilder.get(String.class)).contains(ENDPOINT_PREFIX + endpoint + ":"); } /** diff --git a/tosca-controlloop/participant/participant-impl/participant-impl-simulator/src/test/java/org/onap/policy/clamp/controlloop/participant/simulator/main/rest/RestControllerTest.java b/tosca-controlloop/participant/participant-impl/participant-impl-simulator/src/test/java/org/onap/policy/clamp/controlloop/participant/simulator/main/rest/RestControllerTest.java index c7a39c48b..1311eee35 100644 --- a/tosca-controlloop/participant/participant-impl/participant-impl-simulator/src/test/java/org/onap/policy/clamp/controlloop/participant/simulator/main/rest/RestControllerTest.java +++ b/tosca-controlloop/participant/participant-impl/participant-impl-simulator/src/test/java/org/onap/policy/clamp/controlloop/participant/simulator/main/rest/RestControllerTest.java @@ -27,14 +27,37 @@ import javax.ws.rs.Produces; import javax.ws.rs.core.MediaType; import javax.ws.rs.core.Response; import javax.ws.rs.core.Response.ResponseBuilder; +import org.junit.AfterClass; import org.junit.Before; +import org.junit.BeforeClass; import org.junit.Test; +import org.mockito.Mockito; +import org.onap.policy.clamp.controlloop.participant.simulator.simulation.SimulationHandler; +import org.onap.policy.common.utils.services.Registry; public class RestControllerTest { private RestController ctlr; private ResponseBuilder bldr; + /** + * Setup before class, instantiate SimulationHandler. + * + */ + @BeforeClass + public static void setUpBeforeClass() throws Exception { + Registry.newRegistry(); + Registry.register(SimulationHandler.class.getName(), Mockito.mock(SimulationHandler.class)); + } + + @AfterClass + public static void teardownAfterClass() throws Exception { + Registry.unregister(SimulationHandler.class.getName()); + } + + /** + * set Up. + */ @Before public void setUp() { ctlr = new RestController(); diff --git a/tosca-controlloop/participant/participant-impl/participant-impl-simulator/src/test/java/org/onap/policy/clamp/controlloop/participant/simulator/main/rest/TestListenerUtils.java b/tosca-controlloop/participant/participant-impl/participant-impl-simulator/src/test/java/org/onap/policy/clamp/controlloop/participant/simulator/main/rest/TestListenerUtils.java index 7b7dd2d84..3ee39d57e 100644 --- a/tosca-controlloop/participant/participant-impl/participant-impl-simulator/src/test/java/org/onap/policy/clamp/controlloop/participant/simulator/main/rest/TestListenerUtils.java +++ b/tosca-controlloop/participant/participant-impl/participant-impl-simulator/src/test/java/org/onap/policy/clamp/controlloop/participant/simulator/main/rest/TestListenerUtils.java @@ -22,18 +22,29 @@ package org.onap.policy.clamp.controlloop.participant.simulator.main.rest; import static org.junit.Assert.assertTrue; +import java.io.File; import java.io.FileNotFoundException; +import java.time.Instant; import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.Set; import java.util.UUID; +import lombok.Getter; import org.onap.policy.clamp.controlloop.models.controlloop.concepts.ControlLoop; import org.onap.policy.clamp.controlloop.models.controlloop.concepts.ControlLoopElement; import org.onap.policy.clamp.controlloop.models.controlloop.concepts.ControlLoopOrderedState; import org.onap.policy.clamp.controlloop.models.controlloop.concepts.ControlLoopState; +import org.onap.policy.clamp.controlloop.models.controlloop.concepts.ParticipantState; +import org.onap.policy.clamp.controlloop.models.messages.dmaap.participant.ParticipantControlLoopStateChange; +import org.onap.policy.clamp.controlloop.models.messages.dmaap.participant.ParticipantControlLoopUpdate; +import org.onap.policy.clamp.controlloop.models.messages.dmaap.participant.ParticipantStateChange; +import org.onap.policy.clamp.controlloop.participant.intermediary.handler.ParticipantHandler; import org.onap.policy.clamp.controlloop.participant.simulator.main.parameters.CommonTestData; +import org.onap.policy.clamp.controlloop.participant.simulator.main.parameters.ParticipantSimulatorParameters; +import org.onap.policy.clamp.controlloop.participant.simulator.simulation.SimulationProvider; import org.onap.policy.common.utils.coder.Coder; +import org.onap.policy.common.utils.coder.CoderException; import org.onap.policy.common.utils.coder.StandardCoder; import org.onap.policy.common.utils.coder.YamlJsonTranslator; import org.onap.policy.common.utils.resources.ResourceUtils; @@ -48,11 +59,28 @@ public class TestListenerUtils { private static final YamlJsonTranslator yamlTranslator = new YamlJsonTranslator(); private static final Coder CODER = new StandardCoder(); static CommonTestData commonTestData = new CommonTestData(); - private static RestController restController; private static final Logger LOGGER = LoggerFactory.getLogger(TestListenerUtils.class); private TestListenerUtils() {} + @Getter + private static ParticipantHandler participantHandler; + + /** + * Method to initialize participantHandler. + */ + public static void initParticipantHandler() { + + final ParticipantSimulatorParameters participantParameters = commonTestData.toObject( + commonTestData.getParticipantParameterGroupMap(CommonTestData.PARTICIPANT_GROUP_NAME), + ParticipantSimulatorParameters.class); + + SimulationProvider simulationProvider = + new SimulationProvider(participantParameters.getIntermediaryParameters()); + + participantHandler = simulationProvider.getIntermediaryApi().getParticipantHandler(); + } + /** * Method to create a controlLoop from a yaml file. * @@ -60,10 +88,10 @@ public class TestListenerUtils { */ public static ControlLoop createControlLoop() { ControlLoop controlLoop = new ControlLoop(); - List<ControlLoopElement> elements = new ArrayList<>(); + List<ControlLoopElement> elements = new ArrayList<>(); ToscaServiceTemplate toscaServiceTemplate = testControlLoopRead(); - Map<String, ToscaNodeTemplate> nodeTemplatesMap = toscaServiceTemplate - .getToscaTopologyTemplate().getNodeTemplates(); + Map<String, ToscaNodeTemplate> nodeTemplatesMap = + toscaServiceTemplate.getToscaTopologyTemplate().getNodeTemplates(); for (Map.Entry<String, ToscaNodeTemplate> toscaInputEntry : nodeTemplatesMap.entrySet()) { ControlLoopElement clElement = new ControlLoopElement(); clElement.setId(UUID.randomUUID()); @@ -91,9 +119,107 @@ public class TestListenerUtils { return controlLoop; } + /** + * Method to create ParticipantStateChange message from the arguments passed. + * + * @param participantState participant State + * + * @return ParticipantStateChange message + */ + public static ParticipantStateChange createParticipantStateChangeMsg(final ParticipantState participantState) { + final ParticipantStateChange participantStateChangeMsg = new ParticipantStateChange(); + ToscaConceptIdentifier participantId = new ToscaConceptIdentifier("org.onap.PM_CDS_Blueprint", "1.0.0"); + + participantStateChangeMsg.setParticipantId(participantId); + participantStateChangeMsg.setTimestamp(Instant.now()); + participantStateChangeMsg.setState(participantState); + + return participantStateChangeMsg; + } + + /** + * Method to create ControlLoopStateChange message from the arguments passed. + * + * @param controlLoopOrderedState controlLoopOrderedState + * + * @return ParticipantControlLoopStateChange message + */ + public static ParticipantControlLoopStateChange createControlLoopStateChangeMsg( + final ControlLoopOrderedState controlLoopOrderedState) { + final ParticipantControlLoopStateChange participantClStateChangeMsg = new ParticipantControlLoopStateChange(); + + ToscaConceptIdentifier controlLoopId = new ToscaConceptIdentifier("PMSHInstance0", "1.0.0"); + ToscaConceptIdentifier participantId = new ToscaConceptIdentifier("org.onap.PM_CDS_Blueprint", "1.0.0"); + + participantClStateChangeMsg.setControlLoopId(controlLoopId); + participantClStateChangeMsg.setParticipantId(participantId); + participantClStateChangeMsg.setTimestamp(Instant.now()); + participantClStateChangeMsg.setOrderedState(controlLoopOrderedState); + + return participantClStateChangeMsg; + } + + /** + * Method to create ControlLoopUpdateMsg. + * + * @return ParticipantControlLoopUpdate message + */ + public static ParticipantControlLoopUpdate createControlLoopUpdateMsg() { + final ParticipantControlLoopUpdate clUpdateMsg = new ParticipantControlLoopUpdate(); + ToscaConceptIdentifier controlLoopId = new ToscaConceptIdentifier("PMSHInstance0", "1.0.0."); + ToscaConceptIdentifier participantId = new ToscaConceptIdentifier("org.onap.PM_CDS_Blueprint", "1.0.0"); + + clUpdateMsg.setControlLoopId(controlLoopId); + clUpdateMsg.setParticipantId(participantId); + + ControlLoop controlLoop = new ControlLoop(); + List<ControlLoopElement> elements = new ArrayList<>(); + ToscaServiceTemplate toscaServiceTemplate = testControlLoopRead(); + Map<String, ToscaNodeTemplate> nodeTemplatesMap = + toscaServiceTemplate.getToscaTopologyTemplate().getNodeTemplates(); + for (Map.Entry<String, ToscaNodeTemplate> toscaInputEntry : nodeTemplatesMap.entrySet()) { + ControlLoopElement clElement = new ControlLoopElement(); + clElement.setId(UUID.randomUUID()); + + ToscaConceptIdentifier clElementParticipantId = new ToscaConceptIdentifier(); + clElementParticipantId.setName(toscaInputEntry.getKey()); + clElementParticipantId.setVersion(toscaInputEntry.getValue().getVersion()); + clElement.setParticipantId(clElementParticipantId); + + clElement.setDefinition(clElementParticipantId); + clElement.setState(ControlLoopState.UNINITIALISED); + clElement.setDescription(toscaInputEntry.getValue().getDescription()); + clElement.setOrderedState(ControlLoopOrderedState.UNINITIALISED); + elements.add(clElement); + } + controlLoop.setElements(elements); + controlLoop.setName("PMSHInstance0"); + controlLoop.setVersion("1.0.0"); + controlLoop.setDefinition(controlLoopId); + clUpdateMsg.setControlLoop(controlLoop); + clUpdateMsg.setControlLoopDefinition(toscaServiceTemplate); + + return clUpdateMsg; + } + + /** + * Method to create ParticipantControlLoopUpdate using the arguments passed. + * + * @param jsonFilePath the path of the controlloop content + * + * @return ParticipantControlLoopUpdate message + * @throws CoderException exception while reading the file to object + */ + public static ParticipantControlLoopUpdate createParticipantClUpdateMsgFromJson(String jsonFilePath) + throws CoderException { + ParticipantControlLoopUpdate participantControlLoopUpdateMsg = + CODER.decode(new File(jsonFilePath), ParticipantControlLoopUpdate.class); + return participantControlLoopUpdateMsg; + } + private static ToscaServiceTemplate testControlLoopRead() { - Set<String> controlLoopDirectoryContents = ResourceUtils - .getDirectoryContents("src/test/resources/rest/servicetemplates"); + Set<String> controlLoopDirectoryContents = + ResourceUtils.getDirectoryContents("src/test/resources/rest/servicetemplates"); boolean atLeastOneControlLoopTested = false; ToscaServiceTemplate toscaServiceTemplate = null; diff --git a/tosca-controlloop/participant/participant-impl/participant-impl-simulator/src/test/java/org/onap/policy/clamp/controlloop/participant/simulator/main/rest/TestSimulationRestController.java b/tosca-controlloop/participant/participant-impl/participant-impl-simulator/src/test/java/org/onap/policy/clamp/controlloop/participant/simulator/main/rest/TestSimulationRestController.java index 7adc88d09..1b2b87cfb 100644 --- a/tosca-controlloop/participant/participant-impl/participant-impl-simulator/src/test/java/org/onap/policy/clamp/controlloop/participant/simulator/main/rest/TestSimulationRestController.java +++ b/tosca-controlloop/participant/participant-impl/participant-impl-simulator/src/test/java/org/onap/policy/clamp/controlloop/participant/simulator/main/rest/TestSimulationRestController.java @@ -1,6 +1,6 @@ /*- * ============LICENSE_START======================================================= - * Copyright (C) 2019 Nordix Foundation. + * Copyright (C) 2021 Nordix Foundation. * ================================================================================ * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -20,12 +20,14 @@ package org.onap.policy.clamp.controlloop.participant.simulator.main.rest; +import static org.assertj.core.api.Assertions.assertThat; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; -import java.util.ArrayList; import java.util.List; import javax.ws.rs.client.Entity; import javax.ws.rs.client.Invocation; +import javax.ws.rs.core.GenericType; import javax.ws.rs.core.MediaType; import javax.ws.rs.core.Response; import org.junit.AfterClass; @@ -36,8 +38,12 @@ import org.onap.policy.clamp.controlloop.models.controlloop.concepts.ControlLoop import org.onap.policy.clamp.controlloop.models.controlloop.concepts.ControlLoopOrderedState; import org.onap.policy.clamp.controlloop.models.controlloop.concepts.Participant; import org.onap.policy.clamp.controlloop.models.controlloop.concepts.ParticipantState; +import org.onap.policy.clamp.controlloop.models.messages.dmaap.participant.ParticipantControlLoopUpdate; import org.onap.policy.clamp.controlloop.models.messages.rest.TypedSimpleResponse; +import org.onap.policy.clamp.controlloop.participant.intermediary.comm.ControlLoopUpdateListener; import org.onap.policy.clamp.controlloop.participant.simulator.main.parameters.CommonTestData; +import org.onap.policy.clamp.controlloop.participant.simulator.simulation.SimulationHandler; +import org.onap.policy.clamp.controlloop.participant.simulator.simulation.SimulationProvider; import org.onap.policy.common.endpoints.event.comm.Topic.CommInfrastructure; import org.onap.policy.models.tosca.authorative.concepts.ToscaConceptIdentifier; @@ -45,20 +51,30 @@ import org.onap.policy.models.tosca.authorative.concepts.ToscaConceptIdentifier; * Class to perform unit test of {@link TestSimulationRestController}. */ public class TestSimulationRestController extends CommonParticipantRestServer { + + private static ControlLoopUpdateListener clUpdateListener; private static final String PARTICIPANTS_ENDPOINT = "participants"; private static final String ELEMENTS_ENDPOINT = "elements"; private static final CommInfrastructure INFRA = CommInfrastructure.NOOP; private static final String TOPIC = "my-topic"; static CommonTestData commonTestData = new CommonTestData(); - private static RestController restController; /** - * Setup before class, instantiate SimulationProvider. + * Setup before class. * */ @BeforeClass public static void setUpBeforeClass() throws Exception { CommonParticipantRestServer.setUpBeforeClass(); + clUpdateListener = new ControlLoopUpdateListener( + SimulationHandler.getInstance() + .getSimulationProvider() + .getIntermediaryApi() + .getParticipantHandler()); + ParticipantControlLoopUpdate participantControlLoopUpdateMsg = + TestListenerUtils.createControlLoopUpdateMsg(); + participantControlLoopUpdateMsg.getControlLoop().setOrderedState(ControlLoopOrderedState.PASSIVE); + clUpdateListener.onTopicEvent(INFRA, TOPIC, null, participantControlLoopUpdateMsg); } @AfterClass @@ -88,35 +104,38 @@ public class TestSimulationRestController extends CommonParticipantRestServer { // GET REST call for querying the participants Invocation.Builder invocationBuilder = - super.sendRequest(PARTICIPANTS_ENDPOINT + "/" + participant.getKey().getName() - + "/" + participant.getVersion()); + super.sendRequest(PARTICIPANTS_ENDPOINT + "/" + participant.getKey().getName() + + "/" + participant.getVersion()); Response rawresp = invocationBuilder.buildGet().invoke(); - // Response is not OK, as handling is not done - assertEquals(Response.Status.INTERNAL_SERVER_ERROR.getStatusCode(), rawresp.getStatus()); + assertEquals(Response.Status.OK.getStatusCode(), rawresp.getStatus()); + List<Participant> returnValue = rawresp.readEntity(new GenericType<List<Participant>>() {}); + assertNotNull(returnValue); + assertThat(returnValue).hasSize(1); + // Verify the result of GET participants with what is stored + assertEquals(participant.getDefinition(), returnValue.get(0).getDefinition()); } @Test public void testQueryControlLoopElements() throws Exception { // GET REST call for querying the controlLoop elements - Invocation.Builder invocationBuilder = - super.sendRequest(ELEMENTS_ENDPOINT + "/" + "PMSHInstance0" + "/" + "1.0.0"); + Invocation.Builder invocationBuilder = super.sendRequest(ELEMENTS_ENDPOINT + "/" + + "PMSHInstance0" + "/" + "1.0.0"); Response rawresp = invocationBuilder.buildGet().invoke(); - // Response is not OK, as handling is not done - assertEquals(Response.Status.INTERNAL_SERVER_ERROR.getStatusCode(), rawresp.getStatus()); + assertEquals(Response.Status.OK.getStatusCode(), rawresp.getStatus()); + List<ControlLoopElement> returnValue = rawresp.readEntity(new GenericType<List<ControlLoopElement>>() {}); + assertNotNull(returnValue); + // Verify the result of GET controlloop elements with what is stored + assertThat(returnValue).hasSize(4); + assertEquals("org.onap.PM_Subscription_Handler", returnValue.get(0).getDefinition().getName()); } @Test public void testUpdateParticipant() throws Exception { - Participant participant = new Participant(); - ToscaConceptIdentifier participantId = CommonTestData.getParticipantId(); - participant.setDefinition(participantId); - participant.setName(participantId.getName()); - participant.setVersion(participantId.getVersion()); - - List<Participant> participants = new ArrayList<>(); - participants.add(participant); + SimulationProvider provider = SimulationHandler.getInstance().getSimulationProvider(); + List<Participant> participants = provider.getParticipants(CommonTestData.getParticipantId().getName(), + CommonTestData.getParticipantId().getVersion()); assertEquals(ParticipantState.UNKNOWN, participants.get(0).getParticipantState()); // Change the state of the participant to PASSIVE from UNKNOWN participants.get(0).setParticipantState(ParticipantState.PASSIVE); @@ -126,14 +145,19 @@ public class TestSimulationRestController extends CommonParticipantRestServer { Invocation.Builder invocationBuilder = sendRequest(PARTICIPANTS_ENDPOINT); Response rawresp = invocationBuilder.put(entParticipant); TypedSimpleResponse<Participant> resp = rawresp.readEntity(TypedSimpleResponse.class); - // Response is not OK, as handling is not done - assertEquals(Response.Status.INTERNAL_SERVER_ERROR.getStatusCode(), rawresp.getStatus()); + assertEquals(Response.Status.OK.getStatusCode(), rawresp.getStatus()); + assertNotNull(resp.getResponse()); + // Verify the response and state returned by PUT REST call for updating participants + assertThat(resp.toString()).contains("definition={name=org.onap.PM_CDS_Blueprint, version=1.0.0}"); + assertThat(resp.toString()).contains("participantState=PASSIVE"); } @Test public void testUpdateControlLoopElement() throws Exception { ControlLoop controlLoop = TestListenerUtils.createControlLoop(); - List<ControlLoopElement> controlLoopElements = controlLoop.getElements(); + SimulationProvider provider = SimulationHandler.getInstance().getSimulationProvider(); + List<ControlLoopElement> controlLoopElements = provider.getControlLoopElements( + controlLoop.getDefinition().getName(), controlLoop.getDefinition().getVersion()); // Check the initial state on the ControlLoopElement, which is UNINITIALISED assertEquals(ControlLoopOrderedState.UNINITIALISED, controlLoopElements.get(0).getOrderedState()); @@ -146,8 +170,10 @@ public class TestSimulationRestController extends CommonParticipantRestServer { Invocation.Builder invocationBuilder = sendRequest(ELEMENTS_ENDPOINT); Response rawresp = invocationBuilder.put(entClElement); TypedSimpleResponse<ControlLoopElement> resp = rawresp.readEntity(TypedSimpleResponse.class); - // Response is not OK, as handling is not done - assertEquals(Response.Status.INTERNAL_SERVER_ERROR.getStatusCode(), rawresp.getStatus()); + assertEquals(Response.Status.OK.getStatusCode(), rawresp.getStatus()); + assertNotNull(resp.getResponse()); + // Verify the response and state returned by PUT REST call for updating participants + assertThat(resp.toString()).contains("definition={name=org.onap.PM_Subscription_Handler, version=0.0.0}"); + assertThat(resp.toString()).contains("orderedState=PASSIVE"); } } - diff --git a/tosca-controlloop/participant/participant-impl/participant-impl-simulator/src/test/java/org/onap/policy/clamp/controlloop/participant/simulator/main/startstop/TestMain.java b/tosca-controlloop/participant/participant-impl/participant-impl-simulator/src/test/java/org/onap/policy/clamp/controlloop/participant/simulator/main/startstop/TestMain.java index 137bec205..5a5ad8931 100644 --- a/tosca-controlloop/participant/participant-impl/participant-impl-simulator/src/test/java/org/onap/policy/clamp/controlloop/participant/simulator/main/startstop/TestMain.java +++ b/tosca-controlloop/participant/participant-impl/participant-impl-simulator/src/test/java/org/onap/policy/clamp/controlloop/participant/simulator/main/startstop/TestMain.java @@ -23,13 +23,9 @@ package org.onap.policy.clamp.controlloop.participant.simulator.main.startstop; import static org.assertj.core.api.Assertions.assertThatCode; import static org.assertj.core.api.Assertions.assertThatThrownBy; import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; -import org.junit.AfterClass; -import org.junit.BeforeClass; import org.junit.Test; -import org.onap.policy.clamp.controlloop.common.ControlLoopConstants; import org.onap.policy.clamp.controlloop.common.exception.ControlLoopRuntimeException; import org.onap.policy.common.utils.resources.MessageConstants; diff --git a/tosca-controlloop/participant/participant-impl/participant-impl-simulator/src/test/resources/parameters/TestParameters.json b/tosca-controlloop/participant/participant-impl/participant-impl-simulator/src/test/resources/parameters/TestParameters.json index 82bb917a9..8c594044b 100644 --- a/tosca-controlloop/participant/participant-impl/participant-impl-simulator/src/test/resources/parameters/TestParameters.json +++ b/tosca-controlloop/participant/participant-impl/participant-impl-simulator/src/test/resources/parameters/TestParameters.json @@ -13,11 +13,11 @@ "reportingTimeInterval": 120000, "description": "Participant Description", "participantId": { - "name": "CDSParticipant0", + "name": "org.onap.PM_CDS_Blueprint", "version": "1.0.0" }, "participantType": { - "name": "CDSParticipant0", + "name": "org.onap.PM_CDS_Blueprint", "version": "1.0.0" }, "clampControlLoopTopics": { diff --git a/tosca-controlloop/participant/participant-impl/participant-impl-simulator/src/test/resources/parameters/TestParametersStd.json b/tosca-controlloop/participant/participant-impl/participant-impl-simulator/src/test/resources/parameters/TestParametersStd.json index 1599fc395..0295a8f91 100644 --- a/tosca-controlloop/participant/participant-impl/participant-impl-simulator/src/test/resources/parameters/TestParametersStd.json +++ b/tosca-controlloop/participant/participant-impl/participant-impl-simulator/src/test/resources/parameters/TestParametersStd.json @@ -13,11 +13,11 @@ "reportingTimeInterval": 120000, "description": "Participant Description", "participantId": { - "name": "CDSParticipant0", + "name": "org.onap.PM_CDS_Blueprint", "version": "1.0.0" }, "participantType": { - "name": "CDSParticipant0", + "name": "org.onap.PM_CDS_Blueprint", "version": "1.0.0" }, "clampControlLoopTopics": { diff --git a/tosca-controlloop/participant/participant-impl/participant-impl-simulator/src/test/resources/rest/servicetemplates/pm_control_loop_tosca.yaml b/tosca-controlloop/participant/participant-impl/participant-impl-simulator/src/test/resources/rest/servicetemplates/pm_control_loop_tosca.yaml index 01f825fc9..99dd0ed68 100644 --- a/tosca-controlloop/participant/participant-impl/participant-impl-simulator/src/test/resources/rest/servicetemplates/pm_control_loop_tosca.yaml +++ b/tosca-controlloop/participant/participant-impl/participant-impl-simulator/src/test/resources/rest/servicetemplates/pm_control_loop_tosca.yaml @@ -440,7 +440,7 @@ topology_template: occurrences: - 0.0 version: 0.0.0 - version: 0.0.0 + version: 1.0.0 org.onap.controlloop0: type: org.onap.APP properties: diff --git a/tosca-controlloop/participant/participant-intermediary/src/main/java/org/onap/policy/clamp/controlloop/participant/intermediary/api/ParticipantIntermediaryApi.java b/tosca-controlloop/participant/participant-intermediary/src/main/java/org/onap/policy/clamp/controlloop/participant/intermediary/api/ParticipantIntermediaryApi.java index 6c3e029fe..7ea8b4f35 100644 --- a/tosca-controlloop/participant/participant-intermediary/src/main/java/org/onap/policy/clamp/controlloop/participant/intermediary/api/ParticipantIntermediaryApi.java +++ b/tosca-controlloop/participant/participant-intermediary/src/main/java/org/onap/policy/clamp/controlloop/participant/intermediary/api/ParticipantIntermediaryApi.java @@ -30,6 +30,7 @@ import org.onap.policy.clamp.controlloop.models.controlloop.concepts.ControlLoop import org.onap.policy.clamp.controlloop.models.controlloop.concepts.Participant; import org.onap.policy.clamp.controlloop.models.controlloop.concepts.ParticipantState; import org.onap.policy.clamp.controlloop.models.controlloop.concepts.ParticipantStatistics; +import org.onap.policy.clamp.controlloop.participant.intermediary.handler.ParticipantHandler; import org.onap.policy.clamp.controlloop.participant.intermediary.parameters.ParticipantIntermediaryParameters; import org.onap.policy.models.tosca.authorative.concepts.ToscaConceptIdentifier; @@ -42,12 +43,12 @@ public interface ParticipantIntermediaryApi { * * @param parameters the parameters for the intermediary */ - public void init(ParticipantIntermediaryParameters parameters); + void init(ParticipantIntermediaryParameters parameters); /** * Close the intermediary. */ - public void close(); + void close(); /** * Get participants loops from the intermediary API. @@ -56,23 +57,23 @@ public interface ParticipantIntermediaryApi { * @param version the participant version, null for all * @return the participants */ - public List<Participant> getParticipants(String name, String version); + List<Participant> getParticipants(String name, String version); /** * Update the state of a participant. * * @param definition the definition of the participant to update the state on * @param state the state of the participant - * @return updated participant + * @return the participant */ - public Participant updateParticipantState(ToscaConceptIdentifier definition, ParticipantState state); + Participant updateParticipantState(ToscaConceptIdentifier definition, ParticipantState state); /** * Update the statistics of a participant. * * @param participantStatistics the statistics of the participant */ - public void updateParticipantStatistics(ParticipantStatistics participantStatistics); + void updateParticipantStatistics(ParticipantStatistics participantStatistics); /** * Get control loops from the intermediary API. @@ -81,7 +82,7 @@ public interface ParticipantIntermediaryApi { * @param version the control loop element version, null for all * @return the control loop elements */ - public ControlLoops getControlLoops(String name, String version); + ControlLoops getControlLoops(String name, String version); /** * Get control loop elements from the intermediary API. @@ -90,7 +91,7 @@ public interface ParticipantIntermediaryApi { * @param version the control loop element version, null for all * @return the control loop elements */ - public List<ControlLoopElement> getControlLoopElements(String name, String version); + List<ControlLoopElement> getControlLoopElements(String name, String version); /** * Update the state of a control loop. @@ -99,7 +100,7 @@ public interface ParticipantIntermediaryApi { * @param state the state of the control loop * @return ControlLoop updated control loop */ - public ControlLoop updateControlLoopState(ToscaConceptIdentifier definition, ControlLoopOrderedState state); + ControlLoop updateControlLoopState(ToscaConceptIdentifier definition, ControlLoopOrderedState state); /** * Update the state of a control loop element. @@ -108,12 +109,21 @@ public interface ParticipantIntermediaryApi { * @param state the state of the control loop element * @return ControlLoopElement updated control loop element */ - public ControlLoopElement updateControlLoopElementState(UUID id, ControlLoopOrderedState state); + ControlLoopElement updateControlLoopElementState(UUID id, ControlLoopOrderedState state); /** * Update the control loop element statistics. * * @param elementStatistics the updated statistics */ - public void updateControlLoopElementStatistics(ClElementStatistics elementStatistics); + void updateControlLoopElementStatistics(ClElementStatistics elementStatistics); + + /** + * Returns participantHandler, This will not be used in real world, but for junits, + * if participantHandler is not returned, there is no way to test state change messages + * without dmaap simulator. + * + * @return ParticipantHandler returns a participantHandler + */ + ParticipantHandler getParticipantHandler(); } diff --git a/tosca-controlloop/participant/participant-intermediary/src/main/java/org/onap/policy/clamp/controlloop/participant/intermediary/api/impl/ParticipantIntermediaryApiImpl.java b/tosca-controlloop/participant/participant-intermediary/src/main/java/org/onap/policy/clamp/controlloop/participant/intermediary/api/impl/ParticipantIntermediaryApiImpl.java index 939f927e6..9e494862e 100644 --- a/tosca-controlloop/participant/participant-intermediary/src/main/java/org/onap/policy/clamp/controlloop/participant/intermediary/api/impl/ParticipantIntermediaryApiImpl.java +++ b/tosca-controlloop/participant/participant-intermediary/src/main/java/org/onap/policy/clamp/controlloop/participant/intermediary/api/impl/ParticipantIntermediaryApiImpl.java @@ -32,6 +32,8 @@ import org.onap.policy.clamp.controlloop.models.controlloop.concepts.Participant import org.onap.policy.clamp.controlloop.models.controlloop.concepts.ParticipantState; import org.onap.policy.clamp.controlloop.models.controlloop.concepts.ParticipantStatistics; import org.onap.policy.clamp.controlloop.participant.intermediary.api.ParticipantIntermediaryApi; +import org.onap.policy.clamp.controlloop.participant.intermediary.handler.IntermediaryActivator; +import org.onap.policy.clamp.controlloop.participant.intermediary.handler.ParticipantHandler; import org.onap.policy.clamp.controlloop.participant.intermediary.parameters.ParticipantIntermediaryParameters; import org.onap.policy.models.tosca.authorative.concepts.ToscaConceptIdentifier; @@ -40,49 +42,74 @@ import org.onap.policy.models.tosca.authorative.concepts.ToscaConceptIdentifier; */ public class ParticipantIntermediaryApiImpl implements ParticipantIntermediaryApi { + // The activator for the participant intermediary + private IntermediaryActivator activator; + @Override public void init(ParticipantIntermediaryParameters parameters) { + activator = new IntermediaryActivator(parameters); + + activator.start(); } @Override public void close() { + activator.shutdown(); } @Override public List<Participant> getParticipants(String name, String version) { - return Collections.emptyList(); + return List.of(activator.getParticipantHandler().getParticipant(name, version)); } @Override public Participant updateParticipantState(ToscaConceptIdentifier definition, ParticipantState state) { - return null; + return activator.getParticipantHandler().updateParticipantState(definition, state); } @Override public void updateParticipantStatistics(ParticipantStatistics participantStatistics) { + // TODO Auto-generated method stub } @Override public ControlLoops getControlLoops(String name, String version) { - return null; + return activator.getParticipantHandler().getControlLoopHandler().getControlLoops(); } @Override public List<ControlLoopElement> getControlLoopElements(String name, String version) { + List<ControlLoop> controlLoops = activator.getParticipantHandler() + .getControlLoopHandler().getControlLoops().getControlLoopList(); + + for (ControlLoop controlLoop : controlLoops) { + if (controlLoop.getDefinition().getName().equals(name)) { + return controlLoop.getElements(); + } + } return Collections.emptyList(); } @Override public ControlLoop updateControlLoopState(ToscaConceptIdentifier definition, ControlLoopOrderedState state) { - return null; + return activator.getParticipantHandler().getControlLoopHandler() + .updateControlLoopState(definition, state); } @Override public ControlLoopElement updateControlLoopElementState(UUID id, ControlLoopOrderedState state) { - return null; + return activator.getParticipantHandler().getControlLoopHandler() + .updateControlLoopElementState(id, state); } @Override public void updateControlLoopElementStatistics(ClElementStatistics elementStatistics) { + activator.getParticipantHandler().getControlLoopHandler() + .updateControlLoopElementStatistics(elementStatistics); + } + + @Override + public ParticipantHandler getParticipantHandler() { + return activator.getParticipantHandler(); } } diff --git a/tosca-controlloop/participant/participant-intermediary/src/main/java/org/onap/policy/clamp/controlloop/participant/intermediary/comm/ControlLoopUpdateListener.java b/tosca-controlloop/participant/participant-intermediary/src/main/java/org/onap/policy/clamp/controlloop/participant/intermediary/comm/ControlLoopUpdateListener.java new file mode 100644 index 000000000..2ba98891f --- /dev/null +++ b/tosca-controlloop/participant/participant-intermediary/src/main/java/org/onap/policy/clamp/controlloop/participant/intermediary/comm/ControlLoopUpdateListener.java @@ -0,0 +1,61 @@ +/*- + * ============LICENSE_START======================================================= + * Copyright (C) 2021 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.controlloop.participant.intermediary.comm; + +import java.io.Closeable; +import org.onap.policy.clamp.controlloop.models.messages.dmaap.participant.ParticipantControlLoopUpdate; +import org.onap.policy.clamp.controlloop.participant.intermediary.handler.ParticipantHandler; +import org.onap.policy.common.endpoints.event.comm.Topic.CommInfrastructure; +import org.onap.policy.common.endpoints.listeners.ScoListener; +import org.onap.policy.common.utils.coder.StandardCoderObject; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Listener for Control Loop Update messages sent by CLAMP. + */ +public class ControlLoopUpdateListener extends ScoListener<ParticipantControlLoopUpdate> implements Closeable { + private static final Logger LOGGER = LoggerFactory.getLogger(ControlLoopUpdateListener.class); + + private final ParticipantHandler participantHandler; + + /** + * Constructs the object. + * + * @param participantHandler the handler for managing the state of the participant + */ + public ControlLoopUpdateListener(final ParticipantHandler participantHandler) { + super(ParticipantControlLoopUpdate.class); + this.participantHandler = participantHandler; + } + + @Override + public void onTopicEvent(final CommInfrastructure infra, final String topic, final StandardCoderObject sco, + final ParticipantControlLoopUpdate participantControlLoopUpdateMsg) { + LOGGER.debug("Control Loop update received from CLAMP - {}", participantControlLoopUpdateMsg); + participantHandler.getControlLoopHandler().handleControlLoopUpdate(participantControlLoopUpdateMsg); + } + + @Override + public void close() { + // No explicit action on this class + } +} diff --git a/tosca-controlloop/participant/participant-intermediary/src/main/java/org/onap/policy/clamp/controlloop/participant/intermediary/comm/MessageSender.java b/tosca-controlloop/participant/participant-intermediary/src/main/java/org/onap/policy/clamp/controlloop/participant/intermediary/comm/MessageSender.java new file mode 100644 index 000000000..20490f81d --- /dev/null +++ b/tosca-controlloop/participant/participant-intermediary/src/main/java/org/onap/policy/clamp/controlloop/participant/intermediary/comm/MessageSender.java @@ -0,0 +1,118 @@ +/*- + * ============LICENSE_START======================================================= + * Copyright (C) 2021 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.controlloop.participant.intermediary.comm; + +import java.io.Closeable; +import java.util.TimerTask; +import java.util.concurrent.Executors; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.TimeUnit; +import org.onap.policy.clamp.controlloop.models.messages.dmaap.participant.ParticipantResponseDetails; +import org.onap.policy.clamp.controlloop.models.messages.dmaap.participant.ParticipantResponseStatus; +import org.onap.policy.clamp.controlloop.models.messages.dmaap.participant.ParticipantStatus; +import org.onap.policy.clamp.controlloop.participant.intermediary.handler.ParticipantHandler; +import org.onap.policy.models.tosca.authorative.concepts.ToscaConceptIdentifier; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * This class sends messages from participants to CLAMP. + */ +public class MessageSender extends TimerTask implements Closeable { + private static final Logger LOGGER = LoggerFactory.getLogger(MessageSender.class); + + private final ParticipantHandler participantHandler; + private final ParticipantStatusPublisher publisher; + private ScheduledExecutorService timerPool; + + /** + * Constructor, set the publisher. + * + * @param participantHandler the participant handler to use for gathering information + * @param publisher the publisher to use for sending messages + * @param interval time interval to send Participant Status periodic messages + */ + public MessageSender(ParticipantHandler participantHandler, ParticipantStatusPublisher publisher, + long interval) { + this.participantHandler = participantHandler; + this.publisher = publisher; + + // Kick off the timer + timerPool = makeTimerPool(); + timerPool.scheduleAtFixedRate(this, 0, interval, TimeUnit.SECONDS); + } + + @Override + public void run() { + LOGGER.debug("Sent heartbeat to CLAMP"); + + ParticipantResponseDetails response = new ParticipantResponseDetails(); + + response.setResponseTo(null); + response.setResponseStatus(ParticipantResponseStatus.PERIODIC); + response.setResponseMessage("Periodic response from participant"); + } + + @Override + public void close() { + timerPool.shutdown(); + } + + /** + * Send a response message for this participant. + * + * @param response the details to include in the response message + */ + public void sendResponse(ParticipantResponseDetails response) { + sendResponse(null, response); + } + + /** + * Send a response message for this participant. + * + * @param controlLoopId the control loop to which this message is a response + * @param response the details to include in the response message + */ + public void sendResponse(ToscaConceptIdentifier controlLoopId, ParticipantResponseDetails response) { + ParticipantStatus status = new ParticipantStatus(); + + // Participant related fields + status.setParticipantId(participantHandler.getParticipantId()); + status.setState(participantHandler.getState()); + status.setHealthStatus(participantHandler.getHealthStatus()); + + // Control loop related fields + status.setControlLoopId(controlLoopId); + status.setControlLoops(participantHandler.getControlLoopHandler().getControlLoops()); + status.setResponse(response); + + publisher.send(status); + } + + /** + * Makes a new timer pool. + * + * @return a new timer pool + */ + protected ScheduledExecutorService makeTimerPool() { + return Executors.newScheduledThreadPool(1); + } +} diff --git a/tosca-controlloop/participant/participant-intermediary/src/main/java/org/onap/policy/clamp/controlloop/participant/intermediary/comm/ParticipantStatusPublisher.java b/tosca-controlloop/participant/participant-intermediary/src/main/java/org/onap/policy/clamp/controlloop/participant/intermediary/comm/ParticipantStatusPublisher.java new file mode 100644 index 000000000..e909327cd --- /dev/null +++ b/tosca-controlloop/participant/participant-intermediary/src/main/java/org/onap/policy/clamp/controlloop/participant/intermediary/comm/ParticipantStatusPublisher.java @@ -0,0 +1,62 @@ +/*- + * ============LICENSE_START======================================================= + * Copyright (C) 2021 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.controlloop.participant.intermediary.comm; + +import java.io.Closeable; +import java.util.List; +import org.onap.policy.clamp.controlloop.models.messages.dmaap.participant.ParticipantStatus; +import org.onap.policy.common.endpoints.event.comm.TopicSink; +import org.onap.policy.common.endpoints.event.comm.client.TopicSinkClient; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * This class is used to send Participant Status messages to clamp using TopicSinkClient. + */ +public class ParticipantStatusPublisher implements Closeable { + private static final Logger LOGGER = LoggerFactory.getLogger(ParticipantStatusPublisher.class); + + private final TopicSinkClient topicSinkClient; + + /** + * Constructor for instantiating ParticipantStatusPublisher. + * + * @param topicSinks the topic sinks + */ + public ParticipantStatusPublisher(List<TopicSink> topicSinks) { + this.topicSinkClient = new TopicSinkClient(topicSinks.get(0)); + } + + /** + * Method to send Participant Status message to clamp on demand. + * + * @param participantStatus the Participant Status + */ + public void send(final ParticipantStatus participantStatus) { + topicSinkClient.send(participantStatus); + LOGGER.debug("Sent Participant Status message to CLAMP - {}", participantStatus); + } + + @Override + public void close() { + // No explicit action on this class + } +} diff --git a/tosca-controlloop/participant/participant-intermediary/src/main/java/org/onap/policy/clamp/controlloop/participant/intermediary/handler/ControlLoopHandler.java b/tosca-controlloop/participant/participant-intermediary/src/main/java/org/onap/policy/clamp/controlloop/participant/intermediary/handler/ControlLoopHandler.java new file mode 100644 index 000000000..f27be961b --- /dev/null +++ b/tosca-controlloop/participant/participant-intermediary/src/main/java/org/onap/policy/clamp/controlloop/participant/intermediary/handler/ControlLoopHandler.java @@ -0,0 +1,282 @@ +/*- + * ============LICENSE_START======================================================= + * Copyright (C) 2021 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.controlloop.participant.intermediary.handler; + +import java.io.Closeable; +import java.util.ArrayList; +import java.util.LinkedHashMap; +import java.util.Map; +import java.util.UUID; +import org.apache.commons.collections4.CollectionUtils; +import org.onap.policy.clamp.controlloop.models.controlloop.concepts.ClElementStatistics; +import org.onap.policy.clamp.controlloop.models.controlloop.concepts.ControlLoop; +import org.onap.policy.clamp.controlloop.models.controlloop.concepts.ControlLoopElement; +import org.onap.policy.clamp.controlloop.models.controlloop.concepts.ControlLoopOrderedState; +import org.onap.policy.clamp.controlloop.models.controlloop.concepts.ControlLoopState; +import org.onap.policy.clamp.controlloop.models.controlloop.concepts.ControlLoops; +import org.onap.policy.clamp.controlloop.models.messages.dmaap.participant.ParticipantControlLoopStateChange; +import org.onap.policy.clamp.controlloop.models.messages.dmaap.participant.ParticipantControlLoopUpdate; +import org.onap.policy.clamp.controlloop.models.messages.dmaap.participant.ParticipantResponseDetails; +import org.onap.policy.clamp.controlloop.models.messages.dmaap.participant.ParticipantResponseStatus; +import org.onap.policy.clamp.controlloop.participant.intermediary.comm.MessageSender; +import org.onap.policy.clamp.controlloop.participant.intermediary.parameters.ParticipantIntermediaryParameters; +import org.onap.policy.models.tosca.authorative.concepts.ToscaConceptIdentifier; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/* + * This class is responsible for managing the state of all control loops in the participant. + */ +public class ControlLoopHandler implements Closeable { + private static final Logger LOGGER = LoggerFactory.getLogger(ControlLoopHandler.class); + + private ToscaConceptIdentifier participantId = null; + private MessageSender sender = null; + + private final Map<ToscaConceptIdentifier, ControlLoop> controlLoopMap = new LinkedHashMap<>(); + private final Map<UUID, ControlLoopElement> elementsOnThisParticipant = new LinkedHashMap<>(); + + public ControlLoopHandler() { + } + + /** + * Constructor, set the participant ID and sender. + * + * @param parameters the parameters of the participant + * @param sender the sender for sending responses to messages + */ + public ControlLoopHandler(ParticipantIntermediaryParameters parameters, MessageSender sender) { + this.participantId = parameters.getParticipantId(); + this.sender = sender; + } + + @Override + public void close() { + // No explicit action on this class + } + + /** + * Handle a control loop element state change message. + * + * @param id controlloop element id + * @param state the updated state + * @return controlLoopElement the updated controlloop element + */ + public ControlLoopElement updateControlLoopElementState(UUID id, ControlLoopOrderedState state) { + + if (id == null) { + return null; + } + + ControlLoopElement clElement = elementsOnThisParticipant.get(id); + if (clElement != null) { + clElement.setOrderedState(state); + LOGGER.debug("Control loop element {} ordered state changed to {}", id, state); + ParticipantResponseDetails response = new ParticipantResponseDetails(); + sender.sendResponse(response); + return elementsOnThisParticipant.get(id); + } + + return null; + } + + public void updateControlLoopElementStatistics(ClElementStatistics elementStatistics) { + // TODO Handle statistics coming from a participant implementation + } + + /** + * Handle a control loop state change message. + * + * @param definition controlloop id + * @param state the updated state + * @return controlLoop the updated controlloop + */ + public ControlLoop updateControlLoopState(ToscaConceptIdentifier definition, ControlLoopOrderedState state) { + if (definition == null) { + return null; + } + + ControlLoop controlLoop = controlLoopMap.get(definition); + if (controlLoop == null) { + LOGGER.debug("Control loop {} does not use this participant", definition.getName()); + return null; + } + + ParticipantResponseDetails response = new ParticipantResponseDetails(); + handleState(controlLoop, response, state); + sender.sendResponse(response); + return controlLoop; + } + + /** + * Handle a control loop state change message. + * + * @param stateChangeMsg the state change message + */ + public void handleControlLoopStateChange(ParticipantControlLoopStateChange stateChangeMsg) { + if (stateChangeMsg.getControlLoopId() == null) { + return; + } + + ControlLoop controlLoop = controlLoopMap.get(stateChangeMsg.getControlLoopId()); + + if (controlLoop == null) { + LOGGER.debug("Control loop {} does not use this participant", stateChangeMsg.getControlLoopId()); + return; + } + + ParticipantResponseDetails response = new ParticipantResponseDetails(stateChangeMsg); + handleState(controlLoop, response, stateChangeMsg.getOrderedState()); + sender.sendResponse(response); + } + + /** + * Method to handle state changes. + * + * @param controlLoop participant response + * @param response participant response + * @param state controlloop ordered state + */ + private void handleState(final ControlLoop controlLoop, final ParticipantResponseDetails response, + ControlLoopOrderedState state) { + switch (state) { + case UNINITIALISED: + handleUninitialisedState(controlLoop, response); + break; + case PASSIVE: + handlePassiveState(controlLoop, response); + break; + case RUNNING: + handleRunningState(controlLoop, response); + break; + default: + LOGGER.debug("StateChange message has no state, state is null {}", controlLoop.getDefinition()); + break; + } + } + + /** + * Handle a control loop update message. + * + * @param updateMsg the update message + */ + public void handleControlLoopUpdate(ParticipantControlLoopUpdate updateMsg) { + if (!updateMsg.appliesTo(participantId)) { + return; + } + + ControlLoop controlLoop = controlLoopMap.get(updateMsg.getControlLoopId()); + + ParticipantResponseDetails response = new ParticipantResponseDetails(updateMsg); + + // TODO: Updates to existing ControlLoops are not supported yet (Addition/Removal of ControlLoop + // elements to existing ControlLoop has to be supported). + if (controlLoop != null) { + response.setResponseStatus(ParticipantResponseStatus.FAIL); + response.setResponseMessage("Control loop " + updateMsg.getControlLoopId() + + " already defined on participant " + participantId); + + sender.sendResponse(response); + return; + } + + controlLoop = updateMsg.getControlLoop(); + controlLoop.getElements().removeIf(element -> participantId.equals(element.getParticipantId())); + + controlLoopMap.put(updateMsg.getControlLoopId(), controlLoop); + for (ControlLoopElement element : updateMsg.getControlLoop().getElements()) { + element.setState(element.getOrderedState().asState()); + elementsOnThisParticipant.put(element.getId(), element); + } + + response.setResponseStatus(ParticipantResponseStatus.SUCCESS); + response.setResponseMessage( + "Control loop " + updateMsg.getControlLoopId() + " defined on participant " + participantId); + + sender.sendResponse(response); + } + + /** + * Method to handle when the new state from participant is UNINITIALISED state. + * + * @param controlLoop participant response + * @param response participant response + */ + private void handleUninitialisedState(final ControlLoop controlLoop, final ParticipantResponseDetails response) { + handleStateChange(controlLoop, ControlLoopState.UNINITIALISED, response); + controlLoopMap.remove(controlLoop.getKey().asIdentifier()); + } + + /** + * Method to handle when the new state from participant is PASSIVE state. + * + * @param controlLoop participant response + * @param response participant response + */ + private void handlePassiveState(final ControlLoop controlLoop, final ParticipantResponseDetails response) { + handleStateChange(controlLoop, ControlLoopState.PASSIVE, response); + } + + /** + * Method to handle when the new state from participant is RUNNING state. + * + * @param controlLoop participant response + * @param response participant response + */ + private void handleRunningState(final ControlLoop controlLoop, final ParticipantResponseDetails response) { + handleStateChange(controlLoop, ControlLoopState.RUNNING, response); + } + + /** + * Method to update the state of control loop elements. + * + * @param controlLoop participant status in memory + * @param state new state of the control loop elements + */ + private void handleStateChange(ControlLoop controlLoop, ControlLoopState newState, + ParticipantResponseDetails response) { + + if (newState.equals(controlLoop.getState())) { + response.setResponseStatus(ParticipantResponseStatus.SUCCESS); + response.setResponseMessage("Control loop is already in state " + newState); + return; + } + + if (!CollectionUtils.isEmpty(controlLoop.getElements())) { + controlLoop.getElements().forEach(element -> element.setState(newState)); + } + + response.setResponseStatus(ParticipantResponseStatus.SUCCESS); + response.setResponseMessage("ControlLoop state changed from " + controlLoop.getState() + " to " + newState); + controlLoop.setState(newState); + } + + /** + * Get control loops as a {@link ConrolLoops} class. + * + * @return the control loops + */ + public ControlLoops getControlLoops() { + ControlLoops controlLoops = new ControlLoops(); + controlLoops.setControlLoopList(new ArrayList<>(controlLoopMap.values())); + return controlLoops; + } +} diff --git a/tosca-controlloop/participant/participant-intermediary/src/main/java/org/onap/policy/clamp/controlloop/participant/intermediary/handler/IntermediaryActivator.java b/tosca-controlloop/participant/participant-intermediary/src/main/java/org/onap/policy/clamp/controlloop/participant/intermediary/handler/IntermediaryActivator.java new file mode 100644 index 000000000..dd0cf30a8 --- /dev/null +++ b/tosca-controlloop/participant/participant-intermediary/src/main/java/org/onap/policy/clamp/controlloop/participant/intermediary/handler/IntermediaryActivator.java @@ -0,0 +1,129 @@ +/*- + * ============LICENSE_START======================================================= + * Copyright (C) 2021 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.controlloop.participant.intermediary.handler; + +import java.util.List; +import java.util.concurrent.atomic.AtomicReference; +import javax.ws.rs.core.Response.Status; +import lombok.Getter; +import lombok.experimental.Delegate; +import org.onap.policy.clamp.controlloop.common.exception.ControlLoopRuntimeException; +import org.onap.policy.clamp.controlloop.participant.intermediary.comm.ControlLoopUpdateListener; +import org.onap.policy.clamp.controlloop.participant.intermediary.comm.ParticipantStatusPublisher; +import org.onap.policy.clamp.controlloop.participant.intermediary.parameters.ParticipantIntermediaryParameters; +import org.onap.policy.common.endpoints.event.comm.TopicEndpointManager; +import org.onap.policy.common.endpoints.event.comm.TopicSink; +import org.onap.policy.common.endpoints.event.comm.TopicSource; +import org.onap.policy.common.endpoints.listeners.MessageTypeDispatcher; +import org.onap.policy.common.utils.services.ServiceManagerContainer; + +/** + * This class activates the Participant Intermediary together with all its handlers. + */ +public class IntermediaryActivator extends ServiceManagerContainer { + // Name of the message type for messages on topics + private static final String[] MSG_TYPE_NAMES = {"messageType"}; + + @Getter + private final ParticipantIntermediaryParameters parameters; + + // Topics from which the participant receives and to which the participant sends messages + private List<TopicSink> topicSinks; + private List<TopicSource> topicSources; + + // The participant handler for this intermediary + final AtomicReference<ParticipantHandler> participantHandler = new AtomicReference<>(); + + /** + * Listens for messages on the topic, decodes them into a message, and then dispatches them. + */ + private final MessageTypeDispatcher msgDispatcher; + + /** + * Instantiate the activator for participant. + * + * @param parameters the parameters for the participant intermediary + */ + public IntermediaryActivator(final ParticipantIntermediaryParameters parameters) { + this.parameters = parameters; + + topicSinks = + TopicEndpointManager.getManager().addTopicSinks(parameters.getClampControlLoopTopics().getTopicSinks()); + + topicSources = TopicEndpointManager.getManager() + .addTopicSources(parameters.getClampControlLoopTopics().getTopicSources()); + + try { + this.msgDispatcher = new MessageTypeDispatcher(MSG_TYPE_NAMES); + } catch (final RuntimeException e) { + throw new ControlLoopRuntimeException(Status.INTERNAL_SERVER_ERROR, + "topic message dispatcher failed to start", e); + } + + // @formatter:off + final AtomicReference<ParticipantStatusPublisher> statusPublisher = new AtomicReference<>(); + final AtomicReference<ControlLoopUpdateListener> controlLoopUpdateListener = new AtomicReference<>(); + + addAction("Topic endpoint management", + () -> TopicEndpointManager.getManager().start(), + () -> TopicEndpointManager.getManager().shutdown()); + + addAction("Participant Status Publisher", + () -> statusPublisher.set(new ParticipantStatusPublisher(topicSinks)), + () -> statusPublisher.get().close()); + + addAction("Participant Handler", + () -> participantHandler.set(new ParticipantHandler(parameters, statusPublisher.get())), + () -> participantHandler.get().close()); + + addAction("Control Loop Update Listener", + () -> controlLoopUpdateListener.set(new ControlLoopUpdateListener(participantHandler.get())), + () -> controlLoopUpdateListener.get().close()); + + addAction("Topic Message Dispatcher", this::registerMsgDispatcher, this::unregisterMsgDispatcher); + // @formatter:on + } + + /** + * Registers the dispatcher with the topic source(s). + */ + private void registerMsgDispatcher() { + for (final TopicSource source : topicSources) { + source.register(msgDispatcher); + } + } + + /** + * Unregisters the dispatcher from the topic source(s). + */ + private void unregisterMsgDispatcher() { + for (final TopicSource source : topicSources) { + source.unregister(msgDispatcher); + } + } + + /** + * Return the participant handler. + */ + public ParticipantHandler getParticipantHandler() { + return participantHandler.get(); + } +} diff --git a/tosca-controlloop/participant/participant-intermediary/src/main/java/org/onap/policy/clamp/controlloop/participant/intermediary/handler/ParticipantHandler.java b/tosca-controlloop/participant/participant-intermediary/src/main/java/org/onap/policy/clamp/controlloop/participant/intermediary/handler/ParticipantHandler.java new file mode 100644 index 000000000..1150471ae --- /dev/null +++ b/tosca-controlloop/participant/participant-intermediary/src/main/java/org/onap/policy/clamp/controlloop/participant/intermediary/handler/ParticipantHandler.java @@ -0,0 +1,204 @@ +/*- + * ============LICENSE_START======================================================= + * Copyright (C) 2021 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.controlloop.participant.intermediary.handler; + +import java.io.Closeable; +import java.util.Objects; +import lombok.Getter; +import lombok.Setter; +import org.onap.policy.clamp.controlloop.models.controlloop.concepts.Participant; +import org.onap.policy.clamp.controlloop.models.controlloop.concepts.ParticipantHealthStatus; +import org.onap.policy.clamp.controlloop.models.controlloop.concepts.ParticipantState; +import org.onap.policy.clamp.controlloop.models.messages.dmaap.participant.ParticipantResponseDetails; +import org.onap.policy.clamp.controlloop.models.messages.dmaap.participant.ParticipantResponseStatus; +import org.onap.policy.clamp.controlloop.models.messages.dmaap.participant.ParticipantStateChange; +import org.onap.policy.clamp.controlloop.participant.intermediary.comm.MessageSender; +import org.onap.policy.clamp.controlloop.participant.intermediary.comm.ParticipantStatusPublisher; +import org.onap.policy.clamp.controlloop.participant.intermediary.parameters.ParticipantIntermediaryParameters; +import org.onap.policy.models.tosca.authorative.concepts.ToscaConceptIdentifier; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * This class is responsible for managing the state of a participant. + */ +@Getter +public class ParticipantHandler implements Closeable { + private static final Logger LOGGER = LoggerFactory.getLogger(ParticipantHandler.class); + + private final ToscaConceptIdentifier participantId; + private final MessageSender sender; + private final ControlLoopHandler controlLoopHandler; + + @Setter + private ParticipantState state = ParticipantState.UNKNOWN; + + @Setter + private ParticipantHealthStatus healthStatus = ParticipantHealthStatus.UNKNOWN; + + /** + * Constructor, set the participant ID and sender. + * + * @param parameters the parameters of the participant + * @param publisher the publisher for sending responses to messages + */ + public ParticipantHandler(ParticipantIntermediaryParameters parameters, ParticipantStatusPublisher publisher) { + this.participantId = parameters.getParticipantId(); + this.sender = new MessageSender(this, publisher, parameters.getReportingTimeInterval()); + this.controlLoopHandler = new ControlLoopHandler(parameters, sender); + } + + @Override + public void close() { + sender.close(); + controlLoopHandler.close(); + } + + /** + * Method which handles a participant state change event from clamp. + * + * @param stateChangeMsg participant state change message + */ + public void handleParticipantStateChange(final ParticipantStateChange stateChangeMsg) { + + if (!stateChangeMsg.appliesTo(participantId)) { + return; + } + + ParticipantResponseDetails response = new ParticipantResponseDetails(stateChangeMsg); + + switch (stateChangeMsg.getState()) { + case PASSIVE: + handlePassiveState(response); + break; + case ACTIVE: + handleActiveState(response); + break; + case SAFE: + handleSafeState(response); + break; + case TEST: + handleTestState(response); + break; + case TERMINATED: + handleTerminatedState(response); + break; + default: + LOGGER.debug("StateChange message has no state, state is null {}", stateChangeMsg.getParticipantId()); + response.setResponseStatus(ParticipantResponseStatus.FAIL); + response.setResponseMessage("StateChange message has invalid state for participantId " + + stateChangeMsg.getParticipantId()); + break; + } + + sender.sendResponse(response); + } + + /** + * Method to handle when the new state from participant is active. + * + * @param response participant response + */ + private void handleActiveState(final ParticipantResponseDetails response) { + handleStateChange(ParticipantState.ACTIVE, response); + } + + /** + * Method to handle when the new state from participant is passive. + * + * @param response participant response + */ + private void handlePassiveState(final ParticipantResponseDetails response) { + handleStateChange(ParticipantState.PASSIVE, response); + } + + /** + * Method to handle when the new state from participant is safe. + * + * @param response participant response + */ + private void handleSafeState(final ParticipantResponseDetails response) { + handleStateChange(ParticipantState.SAFE, response); + } + + /** + * Method to handle when the new state from participant is TEST. + * + * @param response participant response + */ + private void handleTestState(final ParticipantResponseDetails response) { + handleStateChange(ParticipantState.TEST, response); + } + + /** + * Method to handle when the new state from participant is Terminated. + * + * @param response participant response + */ + private void handleTerminatedState(final ParticipantResponseDetails response) { + handleStateChange(ParticipantState.TERMINATED, response); + } + + private void handleStateChange(ParticipantState newParticipantState, ParticipantResponseDetails response) { + if (state.equals(newParticipantState)) { + response.setResponseStatus(ParticipantResponseStatus.SUCCESS); + response.setResponseMessage("Participant already in state " + newParticipantState); + } else { + response.setResponseStatus(ParticipantResponseStatus.SUCCESS); + response.setResponseMessage("Participant state changed from " + state + " to " + newParticipantState); + state = newParticipantState; + } + } + + /** + * Method to update participant state. + * + * @param definition participant definition + * @param participantState participant state + */ + public Participant updateParticipantState(ToscaConceptIdentifier definition, + ParticipantState participantState) { + if (!Objects.equals(definition, participantId)) { + LOGGER.debug("No participant with this ID {}", definition.getName()); + return null; + } + ParticipantResponseDetails response = new ParticipantResponseDetails(); + handleStateChange(participantState, response); + sender.sendResponse(response); + return getParticipant(definition.getName(), definition.getVersion()); + } + + /** + * Get participants as a {@link Participant} class. + * + * @return the participant + */ + public Participant getParticipant(String name, String version) { + if (participantId.getName().equals(name)) { + Participant participant = new Participant(); + participant.setDefinition(participantId); + participant.setParticipantState(state); + participant.setHealthStatus(healthStatus); + return participant; + } + return null; + } +} |