summaryrefslogtreecommitdiffstats
path: root/runtime-acm/src/main/java
diff options
context:
space:
mode:
authorliamfallon <liam.fallon@est.tech>2022-01-25 19:55:43 +0000
committerliamfallon <liam.fallon@est.tech>2022-02-18 15:54:40 +0000
commit43098043c4ef31d9d5dead66568d7d9482a6b165 (patch)
tree6f6ea4812ff93d65e7c64e12a3ec6ab4462a64e2 /runtime-acm/src/main/java
parentf401b5099bcb64f3e21de608d0207dd69d8043cd (diff)
Rename TOSCA Control Loop to ACM
This commit renames the TOSCA Control Loop functionality in CLAMP to Automation Composition Management. This review is a direct renaming review and, as everything is renamed together it is large. Issue-ID: POLICY-3939 Change-Id: I28f0a6dd889bf3570a4c1365ae9e71fc58db6d6c Signed-off-by: liamfallon <liam.fallon@est.tech>
Diffstat (limited to 'runtime-acm/src/main/java')
-rw-r--r--runtime-acm/src/main/java/org/onap/policy/clamp/acm/runtime/Application.java53
-rw-r--r--runtime-acm/src/main/java/org/onap/policy/clamp/acm/runtime/commissioning/CommissioningProvider.java383
-rw-r--r--runtime-acm/src/main/java/org/onap/policy/clamp/acm/runtime/config/AafConfiguration.java43
-rw-r--r--runtime-acm/src/main/java/org/onap/policy/clamp/acm/runtime/config/ConverterConfiguration.java44
-rw-r--r--runtime-acm/src/main/java/org/onap/policy/clamp/acm/runtime/config/FilterConfig.java45
-rw-r--r--runtime-acm/src/main/java/org/onap/policy/clamp/acm/runtime/config/SecurityConfig.java47
-rw-r--r--runtime-acm/src/main/java/org/onap/policy/clamp/acm/runtime/config/SpringFoxConfig.java45
-rw-r--r--runtime-acm/src/main/java/org/onap/policy/clamp/acm/runtime/config/messaging/Listener.java41
-rw-r--r--runtime-acm/src/main/java/org/onap/policy/clamp/acm/runtime/config/messaging/MessageDispatcherActivator.java137
-rw-r--r--runtime-acm/src/main/java/org/onap/policy/clamp/acm/runtime/config/messaging/Publisher.java34
-rw-r--r--runtime-acm/src/main/java/org/onap/policy/clamp/acm/runtime/instantiation/AutomationCompositionInstantiationProvider.java637
-rw-r--r--runtime-acm/src/main/java/org/onap/policy/clamp/acm/runtime/main/parameters/AcRuntimeParameterGroup.java49
-rw-r--r--runtime-acm/src/main/java/org/onap/policy/clamp/acm/runtime/main/parameters/ParticipantParameters.java45
-rw-r--r--runtime-acm/src/main/java/org/onap/policy/clamp/acm/runtime/main/parameters/ParticipantUpdateParameters.java46
-rw-r--r--runtime-acm/src/main/java/org/onap/policy/clamp/acm/runtime/main/rest/CommissioningController.java501
-rw-r--r--runtime-acm/src/main/java/org/onap/policy/clamp/acm/runtime/main/rest/InstantiationController.java623
-rw-r--r--runtime-acm/src/main/java/org/onap/policy/clamp/acm/runtime/main/rest/MonitoringQueryController.java334
-rw-r--r--runtime-acm/src/main/java/org/onap/policy/clamp/acm/runtime/main/web/AbstractRestController.java91
-rw-r--r--runtime-acm/src/main/java/org/onap/policy/clamp/acm/runtime/main/web/AutomationConfiguraitonAafFilter.java38
-rw-r--r--runtime-acm/src/main/java/org/onap/policy/clamp/acm/runtime/main/web/GlobalControllerExceptionHandler.java67
-rw-r--r--runtime-acm/src/main/java/org/onap/policy/clamp/acm/runtime/main/web/RuntimeErrorController.java104
-rw-r--r--runtime-acm/src/main/java/org/onap/policy/clamp/acm/runtime/monitoring/MonitoringProvider.java247
-rw-r--r--runtime-acm/src/main/java/org/onap/policy/clamp/acm/runtime/supervision/HandleCounter.java106
-rw-r--r--runtime-acm/src/main/java/org/onap/policy/clamp/acm/runtime/supervision/MessageIntercept.java32
-rw-r--r--runtime-acm/src/main/java/org/onap/policy/clamp/acm/runtime/supervision/SupervisionAspect.java105
-rw-r--r--runtime-acm/src/main/java/org/onap/policy/clamp/acm/runtime/supervision/SupervisionHandler.java518
-rw-r--r--runtime-acm/src/main/java/org/onap/policy/clamp/acm/runtime/supervision/SupervisionScanner.java307
-rw-r--r--runtime-acm/src/main/java/org/onap/policy/clamp/acm/runtime/supervision/comm/AbstractParticipantAckPublisher.java62
-rw-r--r--runtime-acm/src/main/java/org/onap/policy/clamp/acm/runtime/supervision/comm/AbstractParticipantPublisher.java62
-rw-r--r--runtime-acm/src/main/java/org/onap/policy/clamp/acm/runtime/supervision/comm/AutomationCompositionStateChangeAckListener.java70
-rw-r--r--runtime-acm/src/main/java/org/onap/policy/clamp/acm/runtime/supervision/comm/AutomationCompositionStateChangePublisher.java50
-rw-r--r--runtime-acm/src/main/java/org/onap/policy/clamp/acm/runtime/supervision/comm/AutomationCompositionUpdateAckListener.java70
-rw-r--r--runtime-acm/src/main/java/org/onap/policy/clamp/acm/runtime/supervision/comm/AutomationCompositionUpdatePublisher.java91
-rw-r--r--runtime-acm/src/main/java/org/onap/policy/clamp/acm/runtime/supervision/comm/ParticipantDeregisterAckPublisher.java45
-rw-r--r--runtime-acm/src/main/java/org/onap/policy/clamp/acm/runtime/supervision/comm/ParticipantDeregisterListener.java69
-rw-r--r--runtime-acm/src/main/java/org/onap/policy/clamp/acm/runtime/supervision/comm/ParticipantRegisterAckPublisher.java50
-rw-r--r--runtime-acm/src/main/java/org/onap/policy/clamp/acm/runtime/supervision/comm/ParticipantRegisterListener.java69
-rw-r--r--runtime-acm/src/main/java/org/onap/policy/clamp/acm/runtime/supervision/comm/ParticipantStatusListener.java68
-rw-r--r--runtime-acm/src/main/java/org/onap/policy/clamp/acm/runtime/supervision/comm/ParticipantStatusReqPublisher.java48
-rw-r--r--runtime-acm/src/main/java/org/onap/policy/clamp/acm/runtime/supervision/comm/ParticipantUpdateAckListener.java69
-rw-r--r--runtime-acm/src/main/java/org/onap/policy/clamp/acm/runtime/supervision/comm/ParticipantUpdatePublisher.java127
41 files changed, 5672 insertions, 0 deletions
diff --git a/runtime-acm/src/main/java/org/onap/policy/clamp/acm/runtime/Application.java b/runtime-acm/src/main/java/org/onap/policy/clamp/acm/runtime/Application.java
new file mode 100644
index 000000000..d9298b15e
--- /dev/null
+++ b/runtime-acm/src/main/java/org/onap/policy/clamp/acm/runtime/Application.java
@@ -0,0 +1,53 @@
+/*-
+ * ============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.acm.runtime;
+
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.boot.autoconfigure.domain.EntityScan;
+import org.springframework.boot.context.properties.ConfigurationPropertiesScan;
+import org.springframework.context.annotation.ComponentScan;
+import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
+import org.springframework.scheduling.annotation.EnableScheduling;
+
+// @formatter:off
+@EnableScheduling
+@SpringBootApplication
+@EnableJpaRepositories({
+ "org.onap.policy.clamp.models.acm.persistence.repository"
+})
+@ComponentScan({
+ "org.onap.policy.clamp.models.acm.persistence.provider",
+ "org.onap.policy.clamp.acm.runtime",
+ "org.onap.policy.clamp.common.acm.rest"
+})
+@ConfigurationPropertiesScan("org.onap.policy.clamp.acm.runtime.main.parameters")
+@EntityScan({
+ "org.onap.policy.models.tosca.simple.concepts",
+ "org.onap.policy.clamp.models.acm.persistence.concepts"
+})
+//@formatter:on
+public class Application {
+
+ public static void main(String[] args) {
+ SpringApplication.run(Application.class, args);
+ }
+}
diff --git a/runtime-acm/src/main/java/org/onap/policy/clamp/acm/runtime/commissioning/CommissioningProvider.java b/runtime-acm/src/main/java/org/onap/policy/clamp/acm/runtime/commissioning/CommissioningProvider.java
new file mode 100644
index 000000000..dfb9d151b
--- /dev/null
+++ b/runtime-acm/src/main/java/org/onap/policy/clamp/acm/runtime/commissioning/CommissioningProvider.java
@@ -0,0 +1,383 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * Copyright (C) 2021 Nordix Foundation.
+ * Modifications Copyright (C) 2021 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * 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.acm.runtime.commissioning;
+
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.PropertyNamingStrategies;
+import com.fasterxml.jackson.module.jsonSchema.factories.SchemaFactoryWrapper;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
+import javax.ws.rs.core.Response.Status;
+import org.apache.commons.collections4.CollectionUtils;
+import org.apache.commons.collections4.MapUtils;
+import org.onap.policy.clamp.acm.runtime.supervision.SupervisionHandler;
+import org.onap.policy.clamp.models.acm.concepts.Participant;
+import org.onap.policy.clamp.models.acm.messages.rest.commissioning.CommissioningResponse;
+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.persistence.provider.ServiceTemplateProvider;
+import org.onap.policy.models.base.PfModelException;
+import org.onap.policy.models.tosca.authorative.concepts.ToscaCapabilityType;
+import org.onap.policy.models.tosca.authorative.concepts.ToscaConceptIdentifier;
+import org.onap.policy.models.tosca.authorative.concepts.ToscaDataType;
+import org.onap.policy.models.tosca.authorative.concepts.ToscaNodeTemplate;
+import org.onap.policy.models.tosca.authorative.concepts.ToscaNodeType;
+import org.onap.policy.models.tosca.authorative.concepts.ToscaPolicyType;
+import org.onap.policy.models.tosca.authorative.concepts.ToscaRelationshipType;
+import org.onap.policy.models.tosca.authorative.concepts.ToscaServiceTemplate;
+import org.onap.policy.models.tosca.authorative.concepts.ToscaServiceTemplates;
+import org.onap.policy.models.tosca.authorative.concepts.ToscaTopologyTemplate;
+import org.onap.policy.models.tosca.authorative.concepts.ToscaTypedEntityFilter;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+/**
+ * This class provides the create, read and delete actions on Commissioning of automation composition concepts in the
+ * database to the callers.
+ */
+@Service
+@Transactional
+public class CommissioningProvider {
+ public static final String AUTOMATION_COMPOSITION_NODE_TYPE = "org.onap.policy.clamp.acm.AutomationComposition";
+ private static final String INSTANCE_TEXT = "_Instance";
+
+ private final ServiceTemplateProvider serviceTemplateProvider;
+ private final AutomationCompositionProvider acProvider;
+ private final ObjectMapper mapper = new ObjectMapper();
+ private final ParticipantProvider participantProvider;
+ private final SupervisionHandler supervisionHandler;
+
+ /**
+ * Create a commissioning provider.
+ *
+ * @param serviceTemplateProvider the ServiceTemplate Provider
+ * @param acProvider the AutomationComposition Provider
+ * @param supervisionHandler the Supervision Handler
+ * @param participantProvider the Participant Provider
+ */
+ public CommissioningProvider(ServiceTemplateProvider serviceTemplateProvider,
+ AutomationCompositionProvider acProvider, SupervisionHandler supervisionHandler,
+ ParticipantProvider participantProvider) {
+ this.serviceTemplateProvider = serviceTemplateProvider;
+ this.acProvider = acProvider;
+ this.supervisionHandler = supervisionHandler;
+ this.participantProvider = participantProvider;
+ mapper.setPropertyNamingStrategy(PropertyNamingStrategies.SNAKE_CASE);
+ }
+
+ /**
+ * Create automation compositions from a service template.
+ *
+ * @param serviceTemplate the service template
+ * @return the result of the commissioning operation
+ * @throws PfModelException on creation errors
+ */
+ public CommissioningResponse createAutomationCompositionDefinitions(ToscaServiceTemplate serviceTemplate)
+ throws PfModelException {
+
+ if (verifyIfInstancePropertiesExists()) {
+ throw new PfModelException(Status.BAD_REQUEST,
+ "Delete instances, to commission automation composition definitions");
+ }
+ serviceTemplate = serviceTemplateProvider.createServiceTemplate(serviceTemplate);
+ List<Participant> participantList = participantProvider.getParticipants();
+ if (!participantList.isEmpty()) {
+ supervisionHandler.handleSendCommissionMessage(serviceTemplate.getName(), serviceTemplate.getVersion());
+ }
+ var response = new CommissioningResponse();
+ // @formatter:off
+ response.setAffectedAutomationCompositionDefinitions(
+ serviceTemplate.getToscaTopologyTemplate().getNodeTemplates()
+ .values()
+ .stream()
+ .map(template -> template.getKey().asIdentifier())
+ .collect(Collectors.toList()));
+ // @formatter:on
+
+ return response;
+ }
+
+ /**
+ * Delete the automation composition definition with the given name and version.
+ *
+ * @param name the name of the automation composition definition to delete
+ * @param version the version of the automation composition to delete
+ * @return the result of the deletion
+ * @throws PfModelException on deletion errors
+ */
+ public CommissioningResponse deleteAutomationCompositionDefinition(String name, String version)
+ throws PfModelException {
+
+ if (verifyIfInstancePropertiesExists()) {
+ throw new PfModelException(Status.BAD_REQUEST,
+ "Delete instances, to commission automation composition definitions");
+ }
+ List<Participant> participantList = participantProvider.getParticipants();
+ if (!participantList.isEmpty()) {
+ supervisionHandler.handleSendDeCommissionMessage();
+ }
+ serviceTemplateProvider.deleteServiceTemplate(name, version);
+ var response = new CommissioningResponse();
+ response.setAffectedAutomationCompositionDefinitions(List.of(new ToscaConceptIdentifier(name, version)));
+
+ return response;
+ }
+
+ /**
+ * Get automation composition node templates.
+ *
+ * @param acName the name of the automation composition, null for all
+ * @param acVersion the version of the automation composition, null for all
+ * @return list of automation composition node templates
+ * @throws PfModelException on errors getting automation composition definitions
+ */
+ @Transactional(readOnly = true)
+ public List<ToscaNodeTemplate> getAutomationCompositionDefinitions(String acName, String acVersion)
+ throws PfModelException {
+
+ // @formatter:off
+ ToscaTypedEntityFilter<ToscaNodeTemplate> nodeTemplateFilter = ToscaTypedEntityFilter
+ .<ToscaNodeTemplate>builder()
+ .name(acName)
+ .version(acVersion)
+ .type(AUTOMATION_COMPOSITION_NODE_TYPE)
+ .build();
+ // @formatter:on
+
+ return acProvider.getFilteredNodeTemplates(nodeTemplateFilter);
+ }
+
+ /**
+ * Get the automation composition elements from a automation composition node template.
+ *
+ * @param automationCompositionNodeTemplate the automation composition node template
+ * @return a list of the automation composition element node templates in a automation composition node template
+ * @throws PfModelException on errors get automation composition element node templates
+ */
+ @Transactional(readOnly = true)
+ public List<ToscaNodeTemplate> getAutomationCompositionElementDefinitions(
+ ToscaNodeTemplate automationCompositionNodeTemplate) throws PfModelException {
+ if (!AUTOMATION_COMPOSITION_NODE_TYPE.equals(automationCompositionNodeTemplate.getType())) {
+ return Collections.emptyList();
+ }
+
+ if (MapUtils.isEmpty(automationCompositionNodeTemplate.getProperties())) {
+ return Collections.emptyList();
+ }
+
+ @SuppressWarnings("unchecked")
+ List<Map<String, String>> automationCompositionElements =
+ (List<Map<String, String>>) automationCompositionNodeTemplate.getProperties().get("elements");
+
+ if (CollectionUtils.isEmpty(automationCompositionElements)) {
+ return Collections.emptyList();
+ }
+
+ List<ToscaNodeTemplate> automationCompositionElementList = new ArrayList<>();
+ // @formatter:off
+ automationCompositionElementList.addAll(
+ automationCompositionElements
+ .stream()
+ .map(elementMap -> acProvider.getNodeTemplates(elementMap.get("name"),
+ elementMap.get("version")))
+ .flatMap(List::stream)
+ .collect(Collectors.toList())
+ );
+ // @formatter:on
+
+ return automationCompositionElementList;
+ }
+
+ /**
+ * Get node templates with common properties added.
+ *
+ * @param common boolean indicating common or instance properties to be used
+ * @param name the name of the definition to use, null for all definitions
+ * @param version the version of the definition to use, null for all definitions
+ * @return the nodes templates with common or instance properties
+ * @throws PfModelException on errors getting common or instance properties from node_templates
+ */
+ @Transactional(readOnly = true)
+ public Map<String, ToscaNodeTemplate> getNodeTemplatesWithCommonOrInstanceProperties(boolean common, String name,
+ String version) throws PfModelException {
+
+ if (common && verifyIfInstancePropertiesExists()) {
+ throw new PfModelException(Status.BAD_REQUEST,
+ "Cannot create or edit common properties, delete all the instantiations first");
+ }
+
+ var serviceTemplateList = serviceTemplateProvider.getServiceTemplateList(name, version);
+ var commonOrInstanceNodeTypeProps =
+ serviceTemplateProvider.getCommonOrInstancePropertiesFromNodeTypes(common, serviceTemplateList.get(0));
+
+ var serviceTemplates = new ToscaServiceTemplates();
+ serviceTemplates.setServiceTemplates(filterToscaNodeTemplateInstance(serviceTemplateList));
+
+ return serviceTemplateProvider.getDerivedCommonOrInstanceNodeTemplates(
+ serviceTemplates.getServiceTemplates().get(0).getToscaTopologyTemplate().getNodeTemplates(),
+ commonOrInstanceNodeTypeProps);
+ }
+
+ /**
+ * Get the requested automation composition definitions.
+ *
+ * @param name the name of the definition to get, null for all definitions
+ * @param version the version of the definition to get, null for all definitions
+ * @return the automation composition definitions
+ * @throws PfModelException on errors getting automation composition definitions
+ */
+ @Transactional(readOnly = true)
+ public ToscaServiceTemplate getToscaServiceTemplate(String name, String version) throws PfModelException {
+ return serviceTemplateProvider.getToscaServiceTemplate(name, version);
+ }
+
+ /**
+ * Get All the requested automation composition definitions.
+ *
+ * @return the automation composition definitions
+ * @throws PfModelException on errors getting automation composition definitions
+ */
+ @Transactional(readOnly = true)
+ public List<ToscaServiceTemplate> getAllToscaServiceTemplate() throws PfModelException {
+ return serviceTemplateProvider.getAllServiceTemplates();
+ }
+
+ /**
+ * Get the tosca service template with only required sections.
+ *
+ * @param name the name of the template to get, null for all definitions
+ * @param version the version of the template to get, null for all definitions
+ * @return the tosca service template
+ * @throws PfModelException on errors getting tosca service template
+ */
+ @Transactional(readOnly = true)
+ public String getToscaServiceTemplateReduced(String name, String version) throws PfModelException {
+ var serviceTemplateList = serviceTemplateProvider.getServiceTemplateList(name, version);
+
+ List<ToscaServiceTemplate> filteredServiceTemplateList = filterToscaNodeTemplateInstance(serviceTemplateList);
+
+ if (filteredServiceTemplateList.isEmpty()) {
+ throw new PfModelException(Status.BAD_REQUEST, "Invalid Service Template");
+ }
+
+ ToscaServiceTemplate fullTemplate = filteredServiceTemplateList.get(0);
+
+ var template = new HashMap<String, Object>();
+ template.put("tosca_definitions_version", fullTemplate.getToscaDefinitionsVersion());
+ template.put("data_types", fullTemplate.getDataTypes());
+ template.put("policy_types", fullTemplate.getPolicyTypes());
+ template.put("node_types", fullTemplate.getNodeTypes());
+ template.put("topology_template", fullTemplate.getToscaTopologyTemplate());
+
+ try {
+ return mapper.writerWithDefaultPrettyPrinter().writeValueAsString(template);
+
+ } catch (JsonProcessingException e) {
+ throw new PfModelException(Status.BAD_REQUEST, "Converion to Json Schema failed", e);
+ }
+ }
+
+ /**
+ * Get the requested json schema.
+ *
+ * @param section section of the tosca service template to get schema for
+ * @return the specified tosca service template or section Json Schema
+ * @throws PfModelException on errors with retrieving the classes
+ */
+ @Transactional(readOnly = true)
+ public String getToscaServiceTemplateSchema(String section) throws PfModelException {
+ var visitor = new SchemaFactoryWrapper();
+
+ try {
+ switch (section) {
+ case "data_types":
+ mapper.acceptJsonFormatVisitor(mapper.constructType(ToscaDataType.class), visitor);
+ break;
+ case "capability_types":
+ mapper.acceptJsonFormatVisitor(mapper.constructType(ToscaCapabilityType.class), visitor);
+ break;
+ case "node_types":
+ mapper.acceptJsonFormatVisitor(mapper.constructType(ToscaNodeType.class), visitor);
+ break;
+ case "relationship_types":
+ mapper.acceptJsonFormatVisitor(mapper.constructType(ToscaRelationshipType.class), visitor);
+ break;
+ case "policy_types":
+ mapper.acceptJsonFormatVisitor(mapper.constructType(ToscaPolicyType.class), visitor);
+ break;
+ case "topology_template":
+ mapper.acceptJsonFormatVisitor(mapper.constructType(ToscaTopologyTemplate.class), visitor);
+ break;
+ case "node_templates":
+ mapper.acceptJsonFormatVisitor(
+ mapper.getTypeFactory().constructCollectionType(List.class, ToscaNodeTemplate.class), visitor);
+ break;
+ default:
+ mapper.acceptJsonFormatVisitor(mapper.constructType(ToscaServiceTemplate.class), visitor);
+ }
+
+ var jsonSchema = visitor.finalSchema();
+ return mapper.writerWithDefaultPrettyPrinter().writeValueAsString(jsonSchema);
+ } catch (JsonProcessingException e) {
+ throw new PfModelException(Status.BAD_REQUEST, "Converion to Json Schema failed", e);
+ }
+ }
+
+ private List<ToscaServiceTemplate> filterToscaNodeTemplateInstance(List<ToscaServiceTemplate> serviceTemplates) {
+
+ List<ToscaServiceTemplate> toscaServiceTemplates = new ArrayList<>();
+
+ serviceTemplates.stream().forEach(serviceTemplate -> {
+
+ Map<String, ToscaNodeTemplate> toscaNodeTemplates = new HashMap<>();
+
+ serviceTemplate.getToscaTopologyTemplate().getNodeTemplates().forEach((key, nodeTemplate) -> {
+ if (!nodeTemplate.getName().contains(INSTANCE_TEXT)) {
+ toscaNodeTemplates.put(key, nodeTemplate);
+ }
+ });
+
+ serviceTemplate.getToscaTopologyTemplate().getNodeTemplates().clear();
+ serviceTemplate.getToscaTopologyTemplate().setNodeTemplates(toscaNodeTemplates);
+
+ toscaServiceTemplates.add(serviceTemplate);
+ });
+
+ return toscaServiceTemplates;
+ }
+
+ /**
+ * Validates to see if there is any instance properties saved.
+ *
+ * @return true if exists instance properties
+ */
+ private boolean verifyIfInstancePropertiesExists() {
+ return acProvider.getAllNodeTemplates().stream()
+ .anyMatch(nodeTemplate -> nodeTemplate.getKey().getName().contains(INSTANCE_TEXT));
+
+ }
+}
diff --git a/runtime-acm/src/main/java/org/onap/policy/clamp/acm/runtime/config/AafConfiguration.java b/runtime-acm/src/main/java/org/onap/policy/clamp/acm/runtime/config/AafConfiguration.java
new file mode 100644
index 000000000..b1f408048
--- /dev/null
+++ b/runtime-acm/src/main/java/org/onap/policy/clamp/acm/runtime/config/AafConfiguration.java
@@ -0,0 +1,43 @@
+/*-
+ * ============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.
+ * ============LICENSE_END============================================
+ * ===================================================================
+ *
+ */
+
+package org.onap.policy.clamp.acm.runtime.config;
+
+import javax.servlet.Filter;
+import org.onap.policy.clamp.acm.runtime.main.web.AutomationConfiguraitonAafFilter;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.context.annotation.Profile;
+
+@Configuration
+@Profile("clamp-aaf-authentication")
+public class AafConfiguration {
+
+ /**
+ * Method to return AAF filter.
+ *
+ * @return Filter
+ */
+ @Bean
+ public Filter aafFilter() {
+ return new AutomationConfiguraitonAafFilter();
+ }
+
+}
diff --git a/runtime-acm/src/main/java/org/onap/policy/clamp/acm/runtime/config/ConverterConfiguration.java b/runtime-acm/src/main/java/org/onap/policy/clamp/acm/runtime/config/ConverterConfiguration.java
new file mode 100644
index 000000000..f51497266
--- /dev/null
+++ b/runtime-acm/src/main/java/org/onap/policy/clamp/acm/runtime/config/ConverterConfiguration.java
@@ -0,0 +1,44 @@
+/*-
+ * ============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.acm.runtime.config;
+
+import java.util.Arrays;
+import java.util.List;
+import org.onap.policy.clamp.common.acm.rest.CoderHttpMesageConverter;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.http.MediaType;
+import org.springframework.http.converter.HttpMessageConverter;
+import org.springframework.http.converter.StringHttpMessageConverter;
+import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
+
+@Configuration
+public class ConverterConfiguration implements WebMvcConfigurer {
+
+ @Override
+ public void extendMessageConverters(List<HttpMessageConverter<?>> converters) {
+ converters.add(new CoderHttpMesageConverter<>("yaml"));
+ converters.add(new CoderHttpMesageConverter<>("json"));
+
+ StringHttpMessageConverter converter = new StringHttpMessageConverter();
+ converter.setSupportedMediaTypes(Arrays.asList(MediaType.TEXT_PLAIN));
+ converters.add(converter);
+ }
+}
diff --git a/runtime-acm/src/main/java/org/onap/policy/clamp/acm/runtime/config/FilterConfig.java b/runtime-acm/src/main/java/org/onap/policy/clamp/acm/runtime/config/FilterConfig.java
new file mode 100644
index 000000000..4dcd94c25
--- /dev/null
+++ b/runtime-acm/src/main/java/org/onap/policy/clamp/acm/runtime/config/FilterConfig.java
@@ -0,0 +1,45 @@
+/*-
+ * ============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.acm.runtime.config;
+
+import org.onap.policy.clamp.common.acm.rest.RequestResponseLoggingFilter;
+import org.springframework.boot.web.servlet.FilterRegistrationBean;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+@Configuration
+public class FilterConfig {
+
+ /**
+ * Logging Filter configuration.
+ *
+ * @return FilterRegistrationBean
+ */
+ @Bean
+ public FilterRegistrationBean<RequestResponseLoggingFilter> loggingFilter() {
+ FilterRegistrationBean<RequestResponseLoggingFilter> registrationBean = new FilterRegistrationBean<>();
+
+ registrationBean.setFilter(new RequestResponseLoggingFilter());
+ registrationBean.addUrlPatterns("/onap/policy/clamp/acm/v2/*");
+
+ return registrationBean;
+ }
+}
diff --git a/runtime-acm/src/main/java/org/onap/policy/clamp/acm/runtime/config/SecurityConfig.java b/runtime-acm/src/main/java/org/onap/policy/clamp/acm/runtime/config/SecurityConfig.java
new file mode 100644
index 000000000..ade7c56b3
--- /dev/null
+++ b/runtime-acm/src/main/java/org/onap/policy/clamp/acm/runtime/config/SecurityConfig.java
@@ -0,0 +1,47 @@
+/*-
+ * ============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.acm.runtime.config;
+
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.security.config.annotation.web.builders.HttpSecurity;
+import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
+
+@Configuration
+public class SecurityConfig extends WebSecurityConfigurerAdapter {
+
+ @Value("${security.enable-csrf:true}")
+ private boolean csrfEnabled = true;
+
+ @Override
+ protected void configure(HttpSecurity http) throws Exception {
+ // @formatter:off
+ http.authorizeRequests()
+ .antMatchers().authenticated()
+ .anyRequest().authenticated()
+ .and().httpBasic();
+ // @formatter:on
+
+ if (!csrfEnabled) {
+ http.csrf().disable();
+ }
+ }
+}
diff --git a/runtime-acm/src/main/java/org/onap/policy/clamp/acm/runtime/config/SpringFoxConfig.java b/runtime-acm/src/main/java/org/onap/policy/clamp/acm/runtime/config/SpringFoxConfig.java
new file mode 100644
index 000000000..94c8bce06
--- /dev/null
+++ b/runtime-acm/src/main/java/org/onap/policy/clamp/acm/runtime/config/SpringFoxConfig.java
@@ -0,0 +1,45 @@
+/*-
+ * ============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.acm.runtime.config;
+
+import org.onap.policy.clamp.acm.runtime.main.rest.MonitoringQueryController;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import springfox.documentation.builders.PathSelectors;
+import springfox.documentation.builders.RequestHandlerSelectors;
+import springfox.documentation.spi.DocumentationType;
+import springfox.documentation.spring.web.plugins.Docket;
+
+@Configuration
+public class SpringFoxConfig {
+
+ /**
+ * Docket Spring Fox Config.
+ *
+ * @return Docket
+ */
+ @Bean
+ public Docket api() {
+ return new Docket(DocumentationType.SWAGGER_2).select()
+ .apis(RequestHandlerSelectors.basePackage(MonitoringQueryController.class.getPackageName()))
+ .paths(PathSelectors.any()).build();
+ }
+}
diff --git a/runtime-acm/src/main/java/org/onap/policy/clamp/acm/runtime/config/messaging/Listener.java b/runtime-acm/src/main/java/org/onap/policy/clamp/acm/runtime/config/messaging/Listener.java
new file mode 100644
index 000000000..23240ab8a
--- /dev/null
+++ b/runtime-acm/src/main/java/org/onap/policy/clamp/acm/runtime/config/messaging/Listener.java
@@ -0,0 +1,41 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * Copyright (C) 2021 Nordix Foundation.
+ * Modifications Copyright (C) 2021 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * 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.acm.runtime.config.messaging;
+
+import org.onap.policy.common.endpoints.listeners.ScoListener;
+
+public interface Listener<T> {
+
+ /**
+ * Get the type of message of interest to the listener.
+ *
+ * @return type of message of interest to the listener
+ */
+ String getType();
+
+ /**
+ * Get listener to register.
+ *
+ * @return listener to register
+ */
+ ScoListener<T> getScoListener();
+}
diff --git a/runtime-acm/src/main/java/org/onap/policy/clamp/acm/runtime/config/messaging/MessageDispatcherActivator.java b/runtime-acm/src/main/java/org/onap/policy/clamp/acm/runtime/config/messaging/MessageDispatcherActivator.java
new file mode 100644
index 000000000..0d9de205e
--- /dev/null
+++ b/runtime-acm/src/main/java/org/onap/policy/clamp/acm/runtime/config/messaging/MessageDispatcherActivator.java
@@ -0,0 +1,137 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * Copyright (C) 2021 Nordix Foundation.
+ * Modifications Copyright (C) 2021 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * 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.acm.runtime.config.messaging;
+
+import java.io.Closeable;
+import java.io.IOException;
+import java.util.List;
+import lombok.Getter;
+import org.onap.policy.clamp.acm.runtime.main.parameters.AcRuntimeParameterGroup;
+import org.onap.policy.clamp.common.acm.exception.AutomationCompositionRuntimeException;
+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;
+import org.springframework.context.event.ContextClosedEvent;
+import org.springframework.context.event.ContextRefreshedEvent;
+import org.springframework.context.event.EventListener;
+import org.springframework.stereotype.Component;
+
+@Component
+public class MessageDispatcherActivator extends ServiceManagerContainer implements Closeable {
+
+ private static final String[] MSG_TYPE_NAMES = {"messageType"};
+
+ // Topics from which the application receives and to which the application sends messages
+ private List<TopicSink> topicSinks;
+ private List<TopicSource> topicSources;
+
+ @Getter
+ private final MessageTypeDispatcher msgDispatcher;
+
+ /**
+ * Constructor.
+ *
+ * @param acRuntimeParameterGroup the parameters for the automation composition runtime service
+ * @param publishers list of Publishers
+ * @param listeners list of Listeners
+ * @throws AutomationCompositionRuntimeException if the activator does not start
+ */
+ public <T> MessageDispatcherActivator(final AcRuntimeParameterGroup acRuntimeParameterGroup,
+ List<Publisher> publishers, List<Listener<T>> listeners) {
+ topicSinks = TopicEndpointManager.getManager()
+ .addTopicSinks(acRuntimeParameterGroup.getTopicParameterGroup().getTopicSinks());
+
+ topicSources = TopicEndpointManager.getManager()
+ .addTopicSources(acRuntimeParameterGroup.getTopicParameterGroup().getTopicSources());
+
+ msgDispatcher = new MessageTypeDispatcher(MSG_TYPE_NAMES);
+
+ // @formatter:off
+ addAction("Topic endpoint management",
+ () -> TopicEndpointManager.getManager().start(),
+ () -> TopicEndpointManager.getManager().shutdown());
+
+ publishers.forEach(publisher ->
+ addAction("Publisher " + publisher.getClass().getSimpleName(),
+ () -> publisher.active(topicSinks),
+ publisher::stop));
+
+ listeners.forEach(listener ->
+ addAction("Listener " + listener.getClass().getSimpleName(),
+ () -> msgDispatcher.register(listener.getType(), listener.getScoListener()),
+ () -> msgDispatcher.unregister(listener.getType())));
+
+ 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);
+ }
+ }
+
+ /**
+ * Start Manager after the application is Started.
+ *
+ * @param cre Refreshed Event
+ */
+ @EventListener
+ public void handleContextStart(ContextRefreshedEvent cre) {
+ if (!isAlive()) {
+ start();
+ }
+ }
+
+ /**
+ * Handle ContextClosedEvent.
+ *
+ * @param ctxClosedEvent ContextClosedEvent
+ */
+ @EventListener
+ public void handleContextClosedEvent(ContextClosedEvent ctxClosedEvent) {
+ if (isAlive()) {
+ stop();
+ }
+ }
+
+ @Override
+ public void close() throws IOException {
+ if (isAlive()) {
+ super.shutdown();
+ }
+ }
+}
diff --git a/runtime-acm/src/main/java/org/onap/policy/clamp/acm/runtime/config/messaging/Publisher.java b/runtime-acm/src/main/java/org/onap/policy/clamp/acm/runtime/config/messaging/Publisher.java
new file mode 100644
index 000000000..a7acc47b3
--- /dev/null
+++ b/runtime-acm/src/main/java/org/onap/policy/clamp/acm/runtime/config/messaging/Publisher.java
@@ -0,0 +1,34 @@
+/*-
+ * ============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.acm.runtime.config.messaging;
+
+import java.util.List;
+import org.onap.policy.common.endpoints.event.comm.TopicSink;
+
+/**
+ * Publisher.
+ */
+public interface Publisher {
+
+ void active(List<TopicSink> topicSinks);
+
+ void stop();
+}
diff --git a/runtime-acm/src/main/java/org/onap/policy/clamp/acm/runtime/instantiation/AutomationCompositionInstantiationProvider.java b/runtime-acm/src/main/java/org/onap/policy/clamp/acm/runtime/instantiation/AutomationCompositionInstantiationProvider.java
new file mode 100644
index 000000000..39d84026b
--- /dev/null
+++ b/runtime-acm/src/main/java/org/onap/policy/clamp/acm/runtime/instantiation/AutomationCompositionInstantiationProvider.java
@@ -0,0 +1,637 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * Copyright (C) 2021 Nordix Foundation.
+ * Modifications Copyright (C) 2021 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * 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.acm.runtime.instantiation;
+
+import com.google.gson.Gson;
+import com.google.gson.internal.LinkedTreeMap;
+import com.google.gson.reflect.TypeToken;
+import java.lang.reflect.Type;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.UUID;
+import java.util.function.Function;
+import java.util.function.UnaryOperator;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.Response.Status;
+import lombok.AllArgsConstructor;
+import org.onap.policy.clamp.acm.runtime.commissioning.CommissioningProvider;
+import org.onap.policy.clamp.acm.runtime.supervision.SupervisionHandler;
+import org.onap.policy.clamp.common.acm.exception.AutomationCompositionException;
+import org.onap.policy.clamp.models.acm.concepts.AutomationComposition;
+import org.onap.policy.clamp.models.acm.concepts.AutomationCompositionElement;
+import org.onap.policy.clamp.models.acm.concepts.AutomationCompositionOrderedState;
+import org.onap.policy.clamp.models.acm.concepts.AutomationCompositionState;
+import org.onap.policy.clamp.models.acm.concepts.AutomationCompositions;
+import org.onap.policy.clamp.models.acm.concepts.Participant;
+import org.onap.policy.clamp.models.acm.messages.rest.GenericNameVersion;
+import org.onap.policy.clamp.models.acm.messages.rest.instantiation.AutomationCompositionOrderStateResponse;
+import org.onap.policy.clamp.models.acm.messages.rest.instantiation.AutomationCompositionPrimed;
+import org.onap.policy.clamp.models.acm.messages.rest.instantiation.AutomationCompositionPrimedResponse;
+import org.onap.policy.clamp.models.acm.messages.rest.instantiation.InstancePropertiesResponse;
+import org.onap.policy.clamp.models.acm.messages.rest.instantiation.InstantiationCommand;
+import org.onap.policy.clamp.models.acm.messages.rest.instantiation.InstantiationResponse;
+import org.onap.policy.clamp.models.acm.persistence.provider.AutomationCompositionProvider;
+import org.onap.policy.clamp.models.acm.persistence.provider.ParticipantProvider;
+import org.onap.policy.common.parameters.BeanValidationResult;
+import org.onap.policy.common.parameters.ObjectValidationResult;
+import org.onap.policy.common.parameters.ValidationResult;
+import org.onap.policy.common.parameters.ValidationStatus;
+import org.onap.policy.models.base.PfModelException;
+import org.onap.policy.models.tosca.authorative.concepts.ToscaConceptIdentifier;
+import org.onap.policy.models.tosca.authorative.concepts.ToscaNameVersion;
+import org.onap.policy.models.tosca.authorative.concepts.ToscaNodeTemplate;
+import org.onap.policy.models.tosca.authorative.concepts.ToscaServiceTemplate;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+/**
+ * This class is dedicated to the Instantiation of Commissioned automation composition.
+ */
+@Service
+@Transactional
+@AllArgsConstructor
+public class AutomationCompositionInstantiationProvider {
+ private static final String AUTOMATION_COMPOSITION_NODE_TYPE = "org.onap.policy.clamp.acm.AutomationComposition";
+ private static final String AUTOMATION_COMPOSITION_NODE_ELEMENT_TYPE = "AutomationCompositionElement";
+ private static final String PARTICIPANT_ID_PROPERTY_KEY = "participant_id";
+ private static final String PARTICIPANT_TYPE_PROPERTY_KEY = "participantType";
+ private static final String AC_ELEMENT_NAME = "name";
+ private static final String AC_ELEMENT_VERSION = "version";
+ private static final String INSTANCE_TEXT = "_Instance";
+
+ private static final Gson GSON = new Gson();
+
+ private final AutomationCompositionProvider automationCompositionProvider;
+ private final CommissioningProvider commissioningProvider;
+ private final SupervisionHandler supervisionHandler;
+ private final ParticipantProvider participantProvider;
+ private static final String ENTRY = "entry ";
+
+ /**
+ * Creates Instance Properties and automation composition.
+ *
+ * @param serviceTemplate the service template
+ * @return the result of the instantiation operation
+ * @throws PfModelException on creation errors
+ */
+ public InstancePropertiesResponse createInstanceProperties(ToscaServiceTemplate serviceTemplate)
+ throws PfModelException {
+
+ String instanceName = generateSequentialInstanceName();
+ AutomationComposition automationComposition = new AutomationComposition();
+ Map<UUID, AutomationCompositionElement> automationCompositionElements = new HashMap<>();
+
+ ToscaServiceTemplate toscaServiceTemplate = commissioningProvider.getAllToscaServiceTemplate().get(0);
+
+ Map<String, ToscaNodeTemplate> persistedNodeTemplateMap =
+ toscaServiceTemplate.getToscaTopologyTemplate().getNodeTemplates();
+
+ Map<String, ToscaNodeTemplate> nodeTemplates = deepCloneNodeTemplate(serviceTemplate);
+
+ nodeTemplates.forEach((key, template) -> {
+ ToscaNodeTemplate newNodeTemplate = new ToscaNodeTemplate();
+ String name = key + instanceName;
+ String version = template.getVersion();
+ String description = template.getDescription() + instanceName;
+ newNodeTemplate.setName(name);
+ newNodeTemplate.setVersion(version);
+ newNodeTemplate.setDescription(description);
+ newNodeTemplate.setProperties(new HashMap<>(template.getProperties()));
+ newNodeTemplate.setType(template.getType());
+ newNodeTemplate.setTypeVersion(template.getTypeVersion());
+ newNodeTemplate.setMetadata(template.getMetadata());
+
+ crateNewAutomationCompositionInstance(instanceName, automationComposition, automationCompositionElements,
+ template, newNodeTemplate);
+
+ persistedNodeTemplateMap.put(name, newNodeTemplate);
+ });
+
+ AutomationCompositions automationCompositions = new AutomationCompositions();
+
+ serviceTemplate.getToscaTopologyTemplate().getNodeTemplates().putAll(persistedNodeTemplateMap);
+
+ automationComposition.setElements(automationCompositionElements);
+ automationCompositions.getAutomationCompositionList().add(automationComposition);
+
+ return saveInstancePropertiesAndAutomationComposition(serviceTemplate, automationCompositions);
+ }
+
+ /**
+ * Deletes Instance Properties.
+ *
+ * @param name the name of the automation composition to delete
+ * @param version the version of the automation composition to delete
+ * @return the result of the deletion
+ * @throws PfModelException on deletion errors
+ */
+ public InstantiationResponse deleteInstanceProperties(String name, String version) throws PfModelException {
+
+ String instanceName = getInstancePropertyName(name, version);
+
+ Map<String, ToscaNodeTemplate> filteredToscaNodeTemplateMap = new HashMap<>();
+
+ ToscaServiceTemplate toscaServiceTemplate = commissioningProvider.getAllToscaServiceTemplate().get(0);
+
+ toscaServiceTemplate.getToscaTopologyTemplate().getNodeTemplates().forEach((key, nodeTemplate) -> {
+ if (!nodeTemplate.getName().contains(instanceName)) {
+ filteredToscaNodeTemplateMap.put(key, nodeTemplate);
+ }
+ });
+
+ List<ToscaNodeTemplate> filteredToscaNodeTemplateList =
+ toscaServiceTemplate.getToscaTopologyTemplate().getNodeTemplates().values().stream()
+ .filter(nodeTemplate -> nodeTemplate.getName().contains(instanceName)).collect(Collectors.toList());
+
+ InstantiationResponse response = this.deleteAutomationComposition(name, version);
+
+ automationCompositionProvider.deleteInstanceProperties(filteredToscaNodeTemplateMap,
+ filteredToscaNodeTemplateList);
+
+ return response;
+ }
+
+ /**
+ * Create automation compositions.
+ *
+ * @param automationCompositions the automation composition
+ * @return the result of the instantiation operation
+ * @throws PfModelException on creation errors
+ */
+ public InstantiationResponse createAutomationCompositions(AutomationCompositions automationCompositions)
+ throws PfModelException {
+ for (AutomationComposition automationComposition : automationCompositions.getAutomationCompositionList()) {
+ var checkAutomationCompositionOpt =
+ automationCompositionProvider.findAutomationComposition(automationComposition.getKey().asIdentifier());
+ if (checkAutomationCompositionOpt.isPresent()) {
+ throw new PfModelException(Response.Status.BAD_REQUEST,
+ automationComposition.getKey().asIdentifier() + " already defined");
+ }
+ }
+ BeanValidationResult validationResult = validateAutomationCompositions(automationCompositions);
+ if (!validationResult.isValid()) {
+ throw new PfModelException(Response.Status.BAD_REQUEST, validationResult.getResult());
+ }
+ automationCompositionProvider.saveAutomationCompositions(automationCompositions.getAutomationCompositionList());
+
+ var response = new InstantiationResponse();
+ response.setAffectedAutomationCompositions(automationCompositions.getAutomationCompositionList().stream()
+ .map(ac -> ac.getKey().asIdentifier()).collect(Collectors.toList()));
+
+ return response;
+ }
+
+ /**
+ * Update automation compositions.
+ *
+ * @param automationCompositions the automation composition
+ * @return the result of the instantiation operation
+ * @throws PfModelException on update errors
+ */
+ public InstantiationResponse updateAutomationCompositions(AutomationCompositions automationCompositions)
+ throws PfModelException {
+ BeanValidationResult validationResult = validateAutomationCompositions(automationCompositions);
+ if (!validationResult.isValid()) {
+ throw new PfModelException(Response.Status.BAD_REQUEST, validationResult.getResult());
+ }
+ automationCompositionProvider.saveAutomationCompositions(automationCompositions.getAutomationCompositionList());
+
+ var response = new InstantiationResponse();
+ response.setAffectedAutomationCompositions(automationCompositions.getAutomationCompositionList().stream()
+ .map(ac -> ac.getKey().asIdentifier()).collect(Collectors.toList()));
+
+ return response;
+ }
+
+ /**
+ * Validate AutomationCompositions.
+ *
+ * @param automationCompositions AutomationCompositions to validate
+ * @return the result of validation
+ * @throws PfModelException if automationCompositions is not valid
+ */
+ private BeanValidationResult validateAutomationCompositions(AutomationCompositions automationCompositions)
+ throws PfModelException {
+
+ var result = new BeanValidationResult("AutomationCompositions", automationCompositions);
+
+ for (AutomationComposition automationComposition : automationCompositions.getAutomationCompositionList()) {
+ var subResult = new BeanValidationResult(ENTRY + automationComposition.getDefinition().getName(),
+ automationComposition);
+
+ List<ToscaNodeTemplate> toscaNodeTemplates = commissioningProvider.getAutomationCompositionDefinitions(
+ automationComposition.getDefinition().getName(), automationComposition.getDefinition().getVersion());
+
+ if (toscaNodeTemplates.isEmpty()) {
+ subResult.addResult(
+ new ObjectValidationResult("AutomationComposition", automationComposition.getDefinition().getName(),
+ ValidationStatus.INVALID, "Commissioned automation composition definition not found"));
+ } else if (toscaNodeTemplates.size() > 1) {
+ subResult.addResult(
+ new ObjectValidationResult("AutomationComposition", automationComposition.getDefinition().getName(),
+ ValidationStatus.INVALID, "Commissioned automation composition definition not valid"));
+ } else {
+
+ List<ToscaNodeTemplate> acElementDefinitions =
+ commissioningProvider.getAutomationCompositionElementDefinitions(toscaNodeTemplates.get(0));
+
+ // @formatter:off
+ Map<String, ToscaConceptIdentifier> definitions = acElementDefinitions
+ .stream()
+ .map(nodeTemplate -> nodeTemplate.getKey().asIdentifier())
+ .collect(Collectors.toMap(ToscaConceptIdentifier::getName, UnaryOperator.identity()));
+ // @formatter:on
+
+ for (AutomationCompositionElement element : automationComposition.getElements().values()) {
+ subResult.addResult(validateDefinition(definitions, element.getDefinition()));
+ }
+ }
+ result.addResult(subResult);
+ }
+ return result;
+ }
+
+ /**
+ * Validate ToscaConceptIdentifier, checking if exist in ToscaConceptIdentifiers map.
+ *
+ * @param definitions map of all ToscaConceptIdentifiers
+ * @param definition ToscaConceptIdentifier to validate
+ * @return the validation result
+ */
+ private ValidationResult validateDefinition(Map<String, ToscaConceptIdentifier> definitions,
+ ToscaConceptIdentifier definition) {
+ var result = new BeanValidationResult(ENTRY + definition.getName(), definition);
+ ToscaConceptIdentifier identifier = definitions.get(definition.getName());
+ if (identifier == null) {
+ result.setResult(ValidationStatus.INVALID, "Not found");
+ } else if (!identifier.equals(definition)) {
+ result.setResult(ValidationStatus.INVALID, "Version not matching");
+ }
+ return (result.isClean() ? null : result);
+ }
+
+ /**
+ * Delete the automation composition with the given name and version.
+ *
+ * @param name the name of the automation composition to delete
+ * @param version the version of the automation composition to delete
+ * @return the result of the deletion
+ * @throws PfModelException on deletion errors
+ */
+ public InstantiationResponse deleteAutomationComposition(String name, String version) throws PfModelException {
+ var automationCompositionOpt = automationCompositionProvider.findAutomationComposition(name, version);
+ if (automationCompositionOpt.isEmpty()) {
+ throw new PfModelException(Response.Status.NOT_FOUND, "Automation composition not found");
+ }
+ var automationComposition = automationCompositionOpt.get();
+ if (!AutomationCompositionState.UNINITIALISED.equals(automationComposition.getState())) {
+ throw new PfModelException(Response.Status.BAD_REQUEST,
+ "Automation composition state is still " + automationComposition.getState());
+ }
+ var response = new InstantiationResponse();
+ response.setAffectedAutomationCompositions(
+ List.of(automationCompositionProvider.deleteAutomationComposition(name, version).getKey().asIdentifier()));
+ return response;
+ }
+
+ /**
+ * Get the requested automation compositions.
+ *
+ * @param name the name of the automation composition to get, null for all automation compositions
+ * @param version the version of the automation composition to get, null for all automation compositions
+ * @return the automation compositions
+ * @throws PfModelException on errors getting automation compositions
+ */
+ @Transactional(readOnly = true)
+ public AutomationCompositions getAutomationCompositions(String name, String version) throws PfModelException {
+ var automationCompositions = new AutomationCompositions();
+ automationCompositions
+ .setAutomationCompositionList(automationCompositionProvider.getAutomationCompositions(name, version));
+
+ return automationCompositions;
+ }
+
+ /**
+ * Issue a command to automation compositions, setting their ordered state.
+ *
+ * @param command the command to issue to automation compositions
+ * @return the result of the initiation command
+ * @throws PfModelException on errors setting the ordered state on the automation compositions
+ * @throws AutomationCompositionException on ordered state invalid
+ */
+ public InstantiationResponse issueAutomationCompositionCommand(InstantiationCommand command)
+ throws AutomationCompositionException, PfModelException {
+
+ if (command.getOrderedState() == null) {
+ throw new AutomationCompositionException(Status.BAD_REQUEST,
+ "ordered state invalid or not specified on command");
+ }
+
+ var participants = participantProvider.getParticipants();
+ if (participants.isEmpty()) {
+ throw new AutomationCompositionException(Status.BAD_REQUEST, "No participants registered");
+ }
+ var validationResult = new BeanValidationResult("InstantiationCommand", command);
+ List<AutomationComposition> automationCompositions =
+ new ArrayList<>(command.getAutomationCompositionIdentifierList().size());
+ for (ToscaConceptIdentifier id : command.getAutomationCompositionIdentifierList()) {
+ var automationCompositionOpt = automationCompositionProvider.findAutomationComposition(id);
+ if (automationCompositionOpt.isEmpty()) {
+ validationResult.addResult("ToscaConceptIdentifier", id, ValidationStatus.INVALID,
+ "AutomationComposition with id " + id + " not found");
+ } else {
+ var automationComposition = automationCompositionOpt.get();
+ automationComposition.setCascadedOrderedState(command.getOrderedState());
+ automationCompositions.add(automationComposition);
+ }
+ }
+ if (validationResult.isValid()) {
+ validationResult = validateIssueAutomationCompositions(automationCompositions, participants);
+ }
+ if (!validationResult.isValid()) {
+ throw new PfModelException(Response.Status.BAD_REQUEST, validationResult.getResult());
+ }
+ automationCompositionProvider.saveAutomationCompositions(automationCompositions);
+
+ supervisionHandler.triggerAutomationCompositionSupervision(command.getAutomationCompositionIdentifierList());
+ var response = new InstantiationResponse();
+ response.setAffectedAutomationCompositions(command.getAutomationCompositionIdentifierList());
+
+ return response;
+ }
+
+ private BeanValidationResult validateIssueAutomationCompositions(List<AutomationComposition> automationCompositions,
+ List<Participant> participants) {
+ var result = new BeanValidationResult("AutomationCompositions", automationCompositions);
+
+ Map<ToscaConceptIdentifier, Participant> participantMap = participants.stream()
+ .collect(Collectors.toMap(participant -> participant.getKey().asIdentifier(), Function.identity()));
+
+ for (AutomationComposition automationComposition : automationCompositions) {
+
+ for (var element : automationComposition.getElements().values()) {
+
+ var subResult = new BeanValidationResult(ENTRY + element.getDefinition().getName(), element);
+ Participant p = participantMap.get(element.getParticipantId());
+ if (p == null) {
+ subResult.addResult(new ObjectValidationResult(AUTOMATION_COMPOSITION_NODE_ELEMENT_TYPE,
+ element.getDefinition().getName(), ValidationStatus.INVALID,
+ "Participant with ID " + element.getParticipantId() + " is not registered"));
+ } else if (!p.getParticipantType().equals(element.getParticipantType())) {
+ subResult.addResult(new ObjectValidationResult(AUTOMATION_COMPOSITION_NODE_ELEMENT_TYPE,
+ element.getDefinition().getName(), ValidationStatus.INVALID,
+ "Participant with ID " + element.getParticipantType() + " - " + element.getParticipantId()
+ + " is not registered"));
+ }
+ result.addResult(subResult);
+ }
+
+ }
+
+ return result;
+ }
+
+ /**
+ * Gets a list of automation compositions with it's ordered state.
+ *
+ * @param name the name of the automation composition to get, null for all automation compositions
+ * @param version the version of the automation composition to get, null for all automation compositions
+ * @return a list of Instantiation Command
+ * @throws PfModelException on errors getting automation compositions
+ */
+ @Transactional(readOnly = true)
+ public AutomationCompositionOrderStateResponse getInstantiationOrderState(String name, String version)
+ throws PfModelException {
+
+ List<AutomationComposition> automationCompositions =
+ automationCompositionProvider.getAutomationCompositions(name, version);
+
+ var response = new AutomationCompositionOrderStateResponse();
+
+ automationCompositions.forEach(automationComposition -> {
+ var genericNameVersion = new GenericNameVersion();
+ genericNameVersion.setName(automationComposition.getName());
+ genericNameVersion.setVersion(automationComposition.getVersion());
+ response.getAutomationCompositionIdentifierList().add(genericNameVersion);
+ });
+
+ return response;
+ }
+
+ /**
+ * Saves Instance Properties and automation composition.
+ * Gets a list of automation compositions which are primed or de-primed.
+ *
+ * @param name the name of the automation composition to get, null for all automation compositions
+ * @param version the version of the automation composition to get, null for all automation compositions
+ * @return a list of Instantiation Command
+ * @throws PfModelException on errors getting automation compositions
+ */
+ @Transactional(readOnly = true)
+ public AutomationCompositionPrimedResponse getAutomationCompositionPriming(String name, String version)
+ throws PfModelException {
+
+ List<AutomationComposition> automationCompositions =
+ automationCompositionProvider.getAutomationCompositions(name, version);
+
+ var response = new AutomationCompositionPrimedResponse();
+
+ automationCompositions.forEach(automationComposition -> {
+ var primed = new AutomationCompositionPrimed();
+ primed.setName(automationComposition.getName());
+ primed.setVersion(automationComposition.getVersion());
+ primed.setPrimed(automationComposition.getPrimed());
+ response.getPrimedAutomationCompositionsList().add(primed);
+ });
+
+ return response;
+ }
+
+ /**
+ * Creates instance element name.
+ *
+ * @param serviceTemplate the service template
+ * @param automationCompositions a list of automation compositions
+ * @return the result of the instance properties and instantiation operation
+ * @throws PfModelException on creation errors
+ */
+ private InstancePropertiesResponse saveInstancePropertiesAndAutomationComposition(
+ ToscaServiceTemplate serviceTemplate, AutomationCompositions automationCompositions) throws PfModelException {
+
+ for (var automationComposition : automationCompositions.getAutomationCompositionList()) {
+ var checkAutomationCompositionOpt =
+ automationCompositionProvider.findAutomationComposition(automationComposition.getKey().asIdentifier());
+ if (checkAutomationCompositionOpt.isPresent()) {
+ throw new PfModelException(Response.Status.BAD_REQUEST, "Automation composition with id "
+ + automationComposition.getKey().asIdentifier() + " already defined");
+ }
+ }
+ Map<String, ToscaNodeTemplate> toscaSavedNodeTemplate =
+ automationCompositionProvider.saveInstanceProperties(serviceTemplate);
+ automationCompositionProvider.saveAutomationCompositions(automationCompositions.getAutomationCompositionList());
+ List<ToscaConceptIdentifier> affectedAutomationCompositions = automationCompositions
+ .getAutomationCompositionList().stream().map(ac -> ac.getKey().asIdentifier()).collect(Collectors.toList());
+
+ List<ToscaConceptIdentifier> toscaAffectedProperties = toscaSavedNodeTemplate.values().stream()
+ .map(template -> template.getKey().asIdentifier()).collect(Collectors.toList());
+
+ var response = new InstancePropertiesResponse();
+ response.setAffectedInstanceProperties(Stream.of(affectedAutomationCompositions, toscaAffectedProperties)
+ .flatMap(Collection::stream).collect(Collectors.toList()));
+
+ return response;
+ }
+
+ /**
+ * Crates a new automation composition instance.
+ *
+ * @param instanceName automation composition Instance name
+ * @param automationComposition empty automation composition
+ * @param automationCompositionElements new automation composition Element map
+ * @param template original Cloned Tosca Node Template
+ * @param newNodeTemplate new Tosca Node Template
+ */
+ private void crateNewAutomationCompositionInstance(String instanceName, AutomationComposition automationComposition,
+ Map<UUID, AutomationCompositionElement> automationCompositionElements, ToscaNodeTemplate template,
+ ToscaNodeTemplate newNodeTemplate) {
+ if (template.getType().equals(AUTOMATION_COMPOSITION_NODE_TYPE)) {
+ automationComposition.setDefinition(getAutomationCompositionDefinition(newNodeTemplate));
+ }
+
+ if (template.getType().contains(AUTOMATION_COMPOSITION_NODE_ELEMENT_TYPE)) {
+ AutomationCompositionElement automationCompositionElement =
+ getAutomationCompositionElement(newNodeTemplate);
+ automationCompositionElements.put(automationCompositionElement.getId(), automationCompositionElement);
+ }
+
+ automationComposition.setName("PMSH" + instanceName);
+ automationComposition.setVersion(template.getVersion());
+ automationComposition.setDescription("PMSH automation composition " + instanceName);
+ automationComposition.setState(AutomationCompositionState.UNINITIALISED);
+ automationComposition.setOrderedState(AutomationCompositionOrderedState.UNINITIALISED);
+ }
+
+ /**
+ * Get's the instance property name of the automation composition.
+ *
+ * @param name the name of the automation composition to get, null for all automation compositions
+ * @param version the version of the automation composition to get, null for all automation compositions
+ * @return the instance name of the automation composition instance properties
+ * @throws PfModelException on errors getting automation compositions
+ */
+ private String getInstancePropertyName(String name, String version) throws PfModelException {
+ List<String> toscaDefinitionsNames =
+ automationCompositionProvider.getAutomationCompositions(name, version).stream()
+ .map(AutomationComposition::getDefinition).map(ToscaNameVersion::getName).collect(Collectors.toList());
+
+ return toscaDefinitionsNames.stream().reduce("", (s1, s2) -> {
+
+ if (s2.contains(INSTANCE_TEXT)) {
+ String[] instances = s2.split(INSTANCE_TEXT);
+
+ return INSTANCE_TEXT + instances[1];
+ }
+
+ return s1;
+ });
+ }
+
+ /**
+ * Generates Instance Name in sequential order and return it to append to the Node Template Name.
+ *
+ * @return instanceName
+ */
+ private String generateSequentialInstanceName() {
+ List<ToscaNodeTemplate> nodeTemplates = automationCompositionProvider.getAllNodeTemplates();
+
+ int instanceNumber = nodeTemplates.stream().map(ToscaNodeTemplate::getName)
+ .filter(name -> name.contains(INSTANCE_TEXT)).map(n -> {
+ String[] defNameArr = n.split(INSTANCE_TEXT);
+
+ return Integer.parseInt(defNameArr[1]);
+ }).reduce(0, Math::max);
+
+ return INSTANCE_TEXT + (instanceNumber + 1);
+ }
+
+ /**
+ * Retrieves automation composition Definition.
+ *
+ * @param template tosca node template
+ * @return automation composition definition
+ */
+ private ToscaConceptIdentifier getAutomationCompositionDefinition(ToscaNodeTemplate template) {
+ ToscaConceptIdentifier definition = new ToscaConceptIdentifier();
+ definition.setName(template.getName());
+ definition.setVersion(template.getVersion());
+ return definition;
+ }
+
+ /**
+ * Retrieves automation composition Element.
+ *
+ * @param template tosca node template
+ * @return a automation composition element
+ */
+ @SuppressWarnings("unchecked")
+ private AutomationCompositionElement getAutomationCompositionElement(ToscaNodeTemplate template) {
+ AutomationCompositionElement automationCompositionElement = new AutomationCompositionElement();
+ ToscaConceptIdentifier definition = new ToscaConceptIdentifier();
+ definition.setName(template.getName());
+ definition.setVersion(template.getVersion());
+ automationCompositionElement.setDefinition(definition);
+ LinkedTreeMap<String, Object> participantId =
+ (LinkedTreeMap<String, Object>) template.getProperties().get(PARTICIPANT_ID_PROPERTY_KEY);
+ if (participantId != null) {
+ ToscaConceptIdentifier participantIdProperty = new ToscaConceptIdentifier();
+ participantIdProperty.setName(String.valueOf(participantId.get(AC_ELEMENT_NAME)));
+ participantIdProperty.setVersion(String.valueOf(participantId.get(AC_ELEMENT_VERSION)));
+ automationCompositionElement.setParticipantId(participantIdProperty);
+ }
+ LinkedTreeMap<String, Object> participantType =
+ (LinkedTreeMap<String, Object>) template.getProperties().get(PARTICIPANT_TYPE_PROPERTY_KEY);
+ if (participantType != null) {
+ ToscaConceptIdentifier participantTypeProperty = new ToscaConceptIdentifier();
+ participantTypeProperty.setName(String.valueOf(participantType.get(AC_ELEMENT_NAME)));
+ participantTypeProperty.setVersion(participantType.get(AC_ELEMENT_VERSION).toString());
+ automationCompositionElement.setParticipantType(participantTypeProperty);
+ }
+ return automationCompositionElement;
+ }
+
+ /**
+ * Deep clones ToscaNodeTemplate.
+ *
+ * @param serviceTemplate ToscaServiceTemplate
+ * @return a cloned Hash Map of ToscaNodeTemplate
+ */
+ private Map<String, ToscaNodeTemplate> deepCloneNodeTemplate(ToscaServiceTemplate serviceTemplate) {
+ String jsonString = GSON.toJson(serviceTemplate.getToscaTopologyTemplate().getNodeTemplates());
+ Type type = new TypeToken<HashMap<String, ToscaNodeTemplate>>() {}.getType();
+ return GSON.fromJson(jsonString, type);
+ }
+}
diff --git a/runtime-acm/src/main/java/org/onap/policy/clamp/acm/runtime/main/parameters/AcRuntimeParameterGroup.java b/runtime-acm/src/main/java/org/onap/policy/clamp/acm/runtime/main/parameters/AcRuntimeParameterGroup.java
new file mode 100644
index 000000000..563da1268
--- /dev/null
+++ b/runtime-acm/src/main/java/org/onap/policy/clamp/acm/runtime/main/parameters/AcRuntimeParameterGroup.java
@@ -0,0 +1,49 @@
+/*-
+ * ============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.acm.runtime.main.parameters;
+
+import javax.validation.Valid;
+import javax.validation.constraints.NotNull;
+import lombok.Getter;
+import lombok.Setter;
+import org.onap.policy.common.endpoints.parameters.TopicParameterGroup;
+import org.onap.policy.common.parameters.validation.ParameterGroupConstraint;
+import org.springframework.boot.context.properties.ConfigurationProperties;
+import org.springframework.validation.annotation.Validated;
+
+/**
+ * Class to hold all parameters needed for the ACM runtime component.
+ *
+ */
+@Validated
+@Getter
+@Setter
+@ConfigurationProperties(prefix = "runtime")
+public class AcRuntimeParameterGroup {
+
+ @Valid
+ @NotNull
+ private ParticipantParameters participantParameters;
+
+ @NotNull
+ @ParameterGroupConstraint
+ private TopicParameterGroup topicParameterGroup;
+}
diff --git a/runtime-acm/src/main/java/org/onap/policy/clamp/acm/runtime/main/parameters/ParticipantParameters.java b/runtime-acm/src/main/java/org/onap/policy/clamp/acm/runtime/main/parameters/ParticipantParameters.java
new file mode 100644
index 000000000..248824f11
--- /dev/null
+++ b/runtime-acm/src/main/java/org/onap/policy/clamp/acm/runtime/main/parameters/ParticipantParameters.java
@@ -0,0 +1,45 @@
+/*-
+ * ============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.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.policy.clamp.acm.runtime.main.parameters;
+
+import javax.validation.Valid;
+import javax.validation.constraints.Min;
+import javax.validation.constraints.NotNull;
+import lombok.Getter;
+import lombok.Setter;
+import org.springframework.validation.annotation.Validated;
+
+/**
+ * Parameters for communicating with participants.
+ */
+@Getter
+@Setter
+@Validated
+public class ParticipantParameters {
+
+ @Min(100)
+ private long heartBeatMs;
+
+ @Min(100)
+ private long maxStatusWaitMs;
+
+ @Valid
+ @NotNull
+ private ParticipantUpdateParameters updateParameters;
+}
diff --git a/runtime-acm/src/main/java/org/onap/policy/clamp/acm/runtime/main/parameters/ParticipantUpdateParameters.java b/runtime-acm/src/main/java/org/onap/policy/clamp/acm/runtime/main/parameters/ParticipantUpdateParameters.java
new file mode 100644
index 000000000..5ffaf39c0
--- /dev/null
+++ b/runtime-acm/src/main/java/org/onap/policy/clamp/acm/runtime/main/parameters/ParticipantUpdateParameters.java
@@ -0,0 +1,46 @@
+/*
+ * ============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.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.policy.clamp.acm.runtime.main.parameters;
+
+import javax.validation.constraints.Min;
+import lombok.Getter;
+import lombok.Setter;
+import org.springframework.validation.annotation.Validated;
+
+/**
+ * Parameters for Participant UPDATE requests.
+ */
+@Getter
+@Setter
+@Validated
+public class ParticipantUpdateParameters {
+
+ /**
+ * Maximum number of times to re-send a request to a PDP.
+ */
+ @Min(value = 1)
+ private int maxRetryCount;
+
+ /**
+ * Maximum time to wait, in milliseconds, for a PDP response.
+ */
+ @Min(value = 100)
+ private long maxWaitMs;
+
+}
diff --git a/runtime-acm/src/main/java/org/onap/policy/clamp/acm/runtime/main/rest/CommissioningController.java b/runtime-acm/src/main/java/org/onap/policy/clamp/acm/runtime/main/rest/CommissioningController.java
new file mode 100644
index 000000000..0fd8661b4
--- /dev/null
+++ b/runtime-acm/src/main/java/org/onap/policy/clamp/acm/runtime/main/rest/CommissioningController.java
@@ -0,0 +1,501 @@
+/*-
+ * ============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.acm.runtime.main.rest;
+
+import io.swagger.annotations.ApiOperation;
+import io.swagger.annotations.ApiParam;
+import io.swagger.annotations.ApiResponse;
+import io.swagger.annotations.ApiResponses;
+import io.swagger.annotations.Authorization;
+import io.swagger.annotations.Extension;
+import io.swagger.annotations.ExtensionProperty;
+import io.swagger.annotations.ResponseHeader;
+import java.util.List;
+import java.util.Map;
+import java.util.UUID;
+import javax.ws.rs.core.Response.Status;
+import lombok.RequiredArgsConstructor;
+import org.onap.policy.clamp.acm.runtime.commissioning.CommissioningProvider;
+import org.onap.policy.clamp.acm.runtime.main.web.AbstractRestController;
+import org.onap.policy.clamp.common.acm.exception.AutomationCompositionException;
+import org.onap.policy.clamp.models.acm.messages.rest.commissioning.CommissioningResponse;
+import org.onap.policy.models.base.PfModelException;
+import org.onap.policy.models.tosca.authorative.concepts.ToscaNodeTemplate;
+import org.onap.policy.models.tosca.authorative.concepts.ToscaServiceTemplate;
+import org.springframework.http.MediaType;
+import org.springframework.http.ResponseEntity;
+import org.springframework.web.bind.annotation.DeleteMapping;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestHeader;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.bind.annotation.RestController;
+
+/**
+ * Class to provide REST end points for creating, deleting, querying commissioned automation compositions.
+ */
+@RestController
+@RequiredArgsConstructor
+public class CommissioningController extends AbstractRestController {
+
+ private static final String TAGS = "Clamp Automation Composition Commissioning API";
+
+ private final CommissioningProvider provider;
+
+ /**
+ * Creates a automation composition definition.
+ *
+ * @param requestId request ID used in ONAP logging
+ * @param body the body of automation composition following TOSCA definition
+ * @return a response
+ * @throws PfModelException on errors creating a automation composition definition
+ */
+ // @formatter:off
+ @PostMapping(value = "/commission",
+ consumes = {MediaType.APPLICATION_JSON_VALUE, APPLICATION_YAML},
+ produces = {MediaType.APPLICATION_JSON_VALUE, APPLICATION_YAML})
+ @ApiOperation(
+ value = "Commissions automation composition definitions",
+ notes = "Commissions automation composition definitions, returning commissioned definition IDs",
+ response = CommissioningResponse.class,
+ tags = {TAGS},
+ authorizations = @Authorization(value = AUTHORIZATION_TYPE),
+ responseHeaders = {
+ @ResponseHeader(
+ name = VERSION_MINOR_NAME,
+ description = VERSION_MINOR_DESCRIPTION,
+ response = String.class),
+ @ResponseHeader(
+ name = VERSION_PATCH_NAME,
+ description = VERSION_PATCH_DESCRIPTION,
+ response = String.class),
+ @ResponseHeader(
+ name = VERSION_LATEST_NAME,
+ description = VERSION_LATEST_DESCRIPTION,
+ response = String.class),
+ @ResponseHeader(
+ name = REQUEST_ID_NAME,
+ description = REQUEST_ID_HDR_DESCRIPTION,
+ response = UUID.class)
+ },
+ extensions = {
+ @Extension
+ (
+ name = EXTENSION_NAME,
+ properties = {
+ @ExtensionProperty(name = API_VERSION_NAME, value = API_VERSION),
+ @ExtensionProperty(name = LAST_MOD_NAME, value = LAST_MOD_RELEASE)
+ }
+ )
+ }
+ )
+ @ApiResponses(
+ value = {
+ @ApiResponse(code = AUTHENTICATION_ERROR_CODE, message = AUTHENTICATION_ERROR_MESSAGE),
+ @ApiResponse(code = AUTHORIZATION_ERROR_CODE, message = AUTHORIZATION_ERROR_MESSAGE),
+ @ApiResponse(code = SERVER_ERROR_CODE, message = SERVER_ERROR_MESSAGE)
+ }
+ )
+ // @formatter:on
+ public ResponseEntity<CommissioningResponse> create(
+ @RequestHeader(name = REQUEST_ID_NAME, required = false) @ApiParam(REQUEST_ID_PARAM_DESCRIPTION) UUID requestId,
+ @ApiParam(
+ value = "Entity Body of Automation Composition",
+ required = true) @RequestBody ToscaServiceTemplate body)
+ throws PfModelException {
+
+ return ResponseEntity.ok().body(provider.createAutomationCompositionDefinitions(body));
+ }
+
+ /**
+ * Deletes a automation composition definition.
+ *
+ * @param requestId request ID used in ONAP logging
+ * @param name the name of the automation composition definition to delete
+ * @param version the version of the automation composition definition to delete
+ * @return a response
+ * @throws PfModelException on errors deleting a automation composition definition
+ */
+ // @formatter:off
+ @DeleteMapping(value = "/commission",
+ produces = {MediaType.APPLICATION_JSON_VALUE, APPLICATION_YAML})
+ @ApiOperation(value = "Delete a commissioned automation composition",
+ notes = "Deletes a Commissioned Automation Composition, returning optional error details",
+ response = CommissioningResponse.class,
+ tags = {TAGS},
+ authorizations = @Authorization(value = AUTHORIZATION_TYPE),
+ responseHeaders = {
+ @ResponseHeader(
+ name = VERSION_MINOR_NAME,
+ description = VERSION_MINOR_DESCRIPTION,
+ response = String.class),
+ @ResponseHeader(
+ name = VERSION_PATCH_NAME,
+ description = VERSION_PATCH_DESCRIPTION,
+ response = String.class),
+ @ResponseHeader(
+ name = VERSION_LATEST_NAME,
+ description = VERSION_LATEST_DESCRIPTION,
+ response = String.class),
+ @ResponseHeader(
+ name = REQUEST_ID_NAME,
+ description = REQUEST_ID_HDR_DESCRIPTION,
+ response = UUID.class)},
+ extensions = {
+ @Extension
+ (
+ name = EXTENSION_NAME,
+ properties = {
+ @ExtensionProperty(name = API_VERSION_NAME, value = API_VERSION),
+ @ExtensionProperty(name = LAST_MOD_NAME, value = LAST_MOD_RELEASE)
+ }
+ )
+ }
+ )
+ @ApiResponses(
+ value = {
+ @ApiResponse(code = AUTHENTICATION_ERROR_CODE, message = AUTHENTICATION_ERROR_MESSAGE),
+ @ApiResponse(code = AUTHORIZATION_ERROR_CODE, message = AUTHORIZATION_ERROR_MESSAGE),
+ @ApiResponse(code = SERVER_ERROR_CODE, message = SERVER_ERROR_MESSAGE)
+ }
+ )
+ // @formatter:on
+ public ResponseEntity<CommissioningResponse> delete(
+ @RequestHeader(name = REQUEST_ID_NAME, required = false) @ApiParam(REQUEST_ID_PARAM_DESCRIPTION) UUID requestId,
+ @ApiParam(value = "Automation composition definition name", required = true) @RequestParam(
+ value = "name") String name,
+ @ApiParam(
+ value = "Automation composition definition version",
+ required = true) @RequestParam("version") String version)
+ throws PfModelException {
+
+ return ResponseEntity.ok().body(provider.deleteAutomationCompositionDefinition(name, version));
+ }
+
+ /**
+ * Queries details of all or specific automation composition definitions.
+ *
+ * @param requestId request ID used in ONAP logging
+ * @param name the name of the automation composition definition to get, null for all definitions
+ * @param version the version of the automation composition definition to get, null for all definitions
+ * @return the automation composition definitions
+ * @throws PfModelException on errors getting details of all or specific automation composition definitions
+ */
+ // @formatter:off
+ @GetMapping(value = "/commission",
+ produces = {MediaType.APPLICATION_JSON_VALUE, APPLICATION_YAML})
+ @ApiOperation(value = "Query details of the requested commissioned automation composition definitions",
+ notes = "Queries details of the requested commissioned automation composition definitions, "
+ + "returning all automation composition details",
+ response = ToscaNodeTemplate.class,
+ tags = {TAGS},
+ authorizations = @Authorization(value = AUTHORIZATION_TYPE),
+ responseHeaders = {
+ @ResponseHeader(
+ name = VERSION_MINOR_NAME, description = VERSION_MINOR_DESCRIPTION,
+ response = String.class),
+ @ResponseHeader(name = VERSION_PATCH_NAME, description = VERSION_PATCH_DESCRIPTION,
+ response = String.class),
+ @ResponseHeader(name = VERSION_LATEST_NAME, description = VERSION_LATEST_DESCRIPTION,
+ response = String.class),
+ @ResponseHeader(name = REQUEST_ID_NAME, description = REQUEST_ID_HDR_DESCRIPTION,
+ response = UUID.class)},
+ extensions = {
+ @Extension
+ (
+ name = EXTENSION_NAME,
+ properties = {
+ @ExtensionProperty(name = API_VERSION_NAME, value = API_VERSION),
+ @ExtensionProperty(name = LAST_MOD_NAME, value = LAST_MOD_RELEASE)
+ }
+ )
+ }
+ )
+ @ApiResponses(
+ value = {
+ @ApiResponse(code = AUTHENTICATION_ERROR_CODE, message = AUTHENTICATION_ERROR_MESSAGE),
+ @ApiResponse(code = AUTHORIZATION_ERROR_CODE, message = AUTHORIZATION_ERROR_MESSAGE),
+ @ApiResponse(code = SERVER_ERROR_CODE, message = SERVER_ERROR_MESSAGE)
+ }
+ )
+ // @formatter:on
+ public ResponseEntity<List<ToscaNodeTemplate>> query(
+ @RequestHeader(name = REQUEST_ID_NAME, required = false) @ApiParam(REQUEST_ID_PARAM_DESCRIPTION) UUID requestId,
+ @ApiParam(value = "Automation composition definition name", required = false) @RequestParam(
+ value = "name",
+ required = false) String name,
+ @ApiParam(value = "Automation composition definition version", required = false) @RequestParam(
+ value = "version",
+ required = false) String version)
+ throws PfModelException {
+
+ return ResponseEntity.ok().body(provider.getAutomationCompositionDefinitions(name, version));
+ }
+
+ /**
+ * Retrieves the Tosca Service Template.
+ *
+ * @param requestId request ID used in ONAP logging
+ * @param name the name of the tosca service template to retrieve
+ * @param version the version of the tosca service template to get
+ * @return the specified tosca service template
+ * @throws PfModelException on errors getting the Tosca Service Template
+ */
+ // @formatter:off
+ @GetMapping(value = "/commission/toscaservicetemplate",
+ produces = {MediaType.APPLICATION_JSON_VALUE, APPLICATION_YAML})
+ @ApiOperation(value = "Query details of the requested tosca service templates",
+ notes = "Queries details of the requested commissioned tosca service template, "
+ + "returning all tosca service template details",
+ response = ToscaServiceTemplate.class,
+ tags = {TAGS},
+ authorizations = @Authorization(value = AUTHORIZATION_TYPE),
+ responseHeaders = {
+ @ResponseHeader(
+ name = VERSION_MINOR_NAME, description = VERSION_MINOR_DESCRIPTION,
+ response = String.class),
+ @ResponseHeader(name = VERSION_PATCH_NAME, description = VERSION_PATCH_DESCRIPTION,
+ response = String.class),
+ @ResponseHeader(name = VERSION_LATEST_NAME, description = VERSION_LATEST_DESCRIPTION,
+ response = String.class),
+ @ResponseHeader(name = REQUEST_ID_NAME, description = REQUEST_ID_HDR_DESCRIPTION,
+ response = UUID.class)},
+ extensions = {
+ @Extension
+ (
+ name = EXTENSION_NAME,
+ properties = {
+ @ExtensionProperty(name = API_VERSION_NAME, value = API_VERSION),
+ @ExtensionProperty(name = LAST_MOD_NAME, value = LAST_MOD_RELEASE)
+ }
+ )
+ }
+ )
+ @ApiResponses(
+ value = {
+ @ApiResponse(code = AUTHENTICATION_ERROR_CODE, message = AUTHENTICATION_ERROR_MESSAGE),
+ @ApiResponse(code = AUTHORIZATION_ERROR_CODE, message = AUTHORIZATION_ERROR_MESSAGE),
+ @ApiResponse(code = SERVER_ERROR_CODE, message = SERVER_ERROR_MESSAGE)
+ }
+ )
+ // @formatter:on
+ public ResponseEntity<String> queryToscaServiceTemplate(
+ @RequestHeader(name = REQUEST_ID_NAME, required = false) @ApiParam(REQUEST_ID_PARAM_DESCRIPTION) UUID requestId,
+ @ApiParam(value = "Tosca service template name", required = false) @RequestParam(
+ value = "name",
+ required = false) String name,
+ @ApiParam(value = "Tosca service template version", required = false) @RequestParam(
+ value = "version",
+ required = false) String version)
+ throws PfModelException {
+
+ return ResponseEntity.ok().body(provider.getToscaServiceTemplateReduced(name, version));
+ }
+
+ /**
+ * Retrieves the Json Schema for the specified Tosca Service Template.
+ *
+ * @param requestId request ID used in ONAP logging
+ * @param section section of the tosca service template to get schema for
+ * @return the specified tosca service template or section Json Schema
+ * @throws PfModelException on errros getting the Json Schema for the specified Tosca Service Template
+ */
+ // @formatter:off
+ @GetMapping(value = "/commission/toscaServiceTemplateSchema",
+ produces = {MediaType.APPLICATION_JSON_VALUE, APPLICATION_YAML})
+ @ApiOperation(value = "Query details of the requested tosca service template json schema",
+ notes = "Queries details of the requested commissioned tosca service template json schema, "
+ + "returning all tosca service template json schema details",
+ response = ToscaServiceTemplate.class,
+ tags = {TAGS},
+ authorizations = @Authorization(value = AUTHORIZATION_TYPE),
+ responseHeaders = {
+ @ResponseHeader(
+ name = VERSION_MINOR_NAME, description = VERSION_MINOR_DESCRIPTION,
+ response = String.class),
+ @ResponseHeader(name = VERSION_PATCH_NAME, description = VERSION_PATCH_DESCRIPTION,
+ response = String.class),
+ @ResponseHeader(name = VERSION_LATEST_NAME, description = VERSION_LATEST_DESCRIPTION,
+ response = String.class),
+ @ResponseHeader(name = REQUEST_ID_NAME, description = REQUEST_ID_HDR_DESCRIPTION,
+ response = UUID.class)},
+ extensions = {
+ @Extension
+ (
+ name = EXTENSION_NAME,
+ properties = {
+ @ExtensionProperty(name = API_VERSION_NAME, value = API_VERSION),
+ @ExtensionProperty(name = LAST_MOD_NAME, value = LAST_MOD_RELEASE)
+ }
+ )
+ }
+ )
+ @ApiResponses(
+ value = {
+ @ApiResponse(code = AUTHENTICATION_ERROR_CODE, message = AUTHENTICATION_ERROR_MESSAGE),
+ @ApiResponse(code = AUTHORIZATION_ERROR_CODE, message = AUTHORIZATION_ERROR_MESSAGE),
+ @ApiResponse(code = SERVER_ERROR_CODE, message = SERVER_ERROR_MESSAGE)
+ }
+ )
+ // @formatter:on
+ public ResponseEntity<String> queryToscaServiceTemplateJsonSchema(
+ @RequestHeader(name = REQUEST_ID_NAME, required = false) @ApiParam(REQUEST_ID_PARAM_DESCRIPTION) UUID requestId,
+ @ApiParam(
+ value = "Section of Template schema is desired for",
+ required = false) @RequestParam(value = "section", required = false, defaultValue = "all") String section)
+ throws PfModelException {
+
+ return ResponseEntity.ok().body(provider.getToscaServiceTemplateSchema(section));
+ }
+
+ /**
+ * Retrieves the Common or Instance Properties for the specified Tosca Service Template.
+ *
+ * @param requestId request ID used in ONAP logging
+ * @param common a flag, true to get common properties, false to get instance properties
+ * @param name the name of the tosca service template to retrieve
+ * @param version the version of the tosca service template to get
+ * @return the specified tosca service template or section Json Schema
+ * @throws PfModelException on errors getting the Common or Instance Properties
+ * @throws AutomationCompositionException on error getting the Common or Instance Properties
+ */
+ // @formatter:off
+ @GetMapping(value = "/commission/getCommonOrInstanceProperties",
+ produces = {MediaType.APPLICATION_JSON_VALUE, APPLICATION_YAML})
+ @ApiOperation(value = "Query details of the requested tosca service template common or instance properties",
+ notes = "Queries details of the requested commissioned tosca service template json common"
+ + "or instance properties, returning all tosca service template common or instance property details",
+ response = ToscaServiceTemplate.class,
+ tags = {"Clamp Automation Composition Commissioning API"},
+ authorizations = @Authorization(value = AUTHORIZATION_TYPE),
+ responseHeaders = {
+ @ResponseHeader(
+ name = VERSION_MINOR_NAME, description = VERSION_MINOR_DESCRIPTION,
+ response = String.class),
+ @ResponseHeader(name = VERSION_PATCH_NAME, description = VERSION_PATCH_DESCRIPTION,
+ response = String.class),
+ @ResponseHeader(name = VERSION_LATEST_NAME, description = VERSION_LATEST_DESCRIPTION,
+ response = String.class),
+ @ResponseHeader(name = REQUEST_ID_NAME, description = REQUEST_ID_HDR_DESCRIPTION,
+ response = UUID.class)},
+ extensions = {
+ @Extension
+ (
+ name = EXTENSION_NAME,
+ properties = {
+ @ExtensionProperty(name = API_VERSION_NAME, value = API_VERSION),
+ @ExtensionProperty(name = LAST_MOD_NAME, value = LAST_MOD_RELEASE)
+ }
+ )
+ }
+ )
+ @ApiResponses(
+ value = {
+ @ApiResponse(code = AUTHENTICATION_ERROR_CODE, message = AUTHENTICATION_ERROR_MESSAGE),
+ @ApiResponse(code = AUTHORIZATION_ERROR_CODE, message = AUTHORIZATION_ERROR_MESSAGE),
+ @ApiResponse(code = SERVER_ERROR_CODE, message = SERVER_ERROR_MESSAGE)
+ }
+ )
+ // @formatter:on
+ public ResponseEntity<Map<String, ToscaNodeTemplate>> queryToscaServiceCommonOrInstanceProperties(
+ @RequestHeader(name = REQUEST_ID_NAME, required = false) @ApiParam(REQUEST_ID_PARAM_DESCRIPTION) UUID requestId,
+ @ApiParam(
+ value = "Flag, true for common properties, false for instance",
+ required = false) @RequestParam(value = "common", defaultValue = "false", required = false) boolean common,
+ @ApiParam(value = "Tosca service template name", required = false) @RequestParam(
+ value = "name",
+ required = false) String name,
+ @ApiParam(value = "Tosca service template version", required = false) @RequestParam(
+ value = "version",
+ required = false) String version)
+ throws PfModelException {
+
+ return ResponseEntity.ok().body(provider.getNodeTemplatesWithCommonOrInstanceProperties(common, name, version));
+ }
+
+ /**
+ * Queries the elements of a specific automation composition.
+ *
+ * @param requestId request ID used in ONAP logging
+ * @param name the name of the automation composition definition to get
+ * @param version the version of the automation composition definition to get
+ * @return the automation composition element definitions
+ * @throws PfModelException on errors getting the elements of a specific automation composition
+ */
+ // @formatter:off
+ @GetMapping(value = "/commission/elements",
+ produces = {MediaType.APPLICATION_JSON_VALUE, APPLICATION_YAML})
+ @ApiOperation(value = "Query details of the requested commissioned automation composition element definitions",
+ notes = "Queries details of the requested commissioned automation composition element definitions, "
+ + "returning all automation composition elements' details",
+ response = ToscaNodeTemplate.class,
+ tags = {TAGS},
+ authorizations = @Authorization(value = AUTHORIZATION_TYPE),
+ responseHeaders = {
+ @ResponseHeader(
+ name = VERSION_MINOR_NAME, description = VERSION_MINOR_DESCRIPTION,
+ response = String.class),
+ @ResponseHeader(name = VERSION_PATCH_NAME, description = VERSION_PATCH_DESCRIPTION,
+ response = String.class),
+ @ResponseHeader(name = VERSION_LATEST_NAME, description = VERSION_LATEST_DESCRIPTION,
+ response = String.class),
+ @ResponseHeader(name = REQUEST_ID_NAME, description = REQUEST_ID_HDR_DESCRIPTION,
+ response = UUID.class)},
+ extensions = {
+ @Extension
+ (
+ name = EXTENSION_NAME,
+ properties = {
+ @ExtensionProperty(name = API_VERSION_NAME, value = API_VERSION),
+ @ExtensionProperty(name = LAST_MOD_NAME, value = LAST_MOD_RELEASE)
+ }
+ )
+ }
+ )
+ @ApiResponses(
+ value = {
+ @ApiResponse(code = AUTHENTICATION_ERROR_CODE, message = AUTHENTICATION_ERROR_MESSAGE),
+ @ApiResponse(code = AUTHORIZATION_ERROR_CODE, message = AUTHORIZATION_ERROR_MESSAGE),
+ @ApiResponse(code = SERVER_ERROR_CODE, message = SERVER_ERROR_MESSAGE)
+ }
+ )
+ // @formatter:on
+ public ResponseEntity<List<ToscaNodeTemplate>> queryElements(
+ @RequestHeader(name = REQUEST_ID_NAME, required = false) @ApiParam(REQUEST_ID_PARAM_DESCRIPTION) UUID requestId,
+ @ApiParam(value = "Automation composition definition name", required = false) @RequestParam(
+ value = "name",
+ required = false) String name,
+ @ApiParam(value = "Automation composition definition version", required = false) @RequestParam(
+ value = "version",
+ required = false) String version)
+ throws PfModelException {
+
+ List<ToscaNodeTemplate> nodeTemplate = provider.getAutomationCompositionDefinitions(name, version);
+ // Prevent ambiguous queries with multiple returns
+ if (nodeTemplate.size() > 1) {
+ throw new PfModelException(Status.NOT_ACCEPTABLE, "Multiple automation compositions are not supported");
+ }
+
+ List<ToscaNodeTemplate> response = provider.getAutomationCompositionElementDefinitions(nodeTemplate.get(0));
+ return ResponseEntity.ok().body(response);
+ }
+}
diff --git a/runtime-acm/src/main/java/org/onap/policy/clamp/acm/runtime/main/rest/InstantiationController.java b/runtime-acm/src/main/java/org/onap/policy/clamp/acm/runtime/main/rest/InstantiationController.java
new file mode 100644
index 000000000..dc56c77e7
--- /dev/null
+++ b/runtime-acm/src/main/java/org/onap/policy/clamp/acm/runtime/main/rest/InstantiationController.java
@@ -0,0 +1,623 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * Copyright (C) 2021 Nordix Foundation.
+ * Modifications Copyright (C) 2021 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * 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.acm.runtime.main.rest;
+
+import io.swagger.annotations.ApiOperation;
+import io.swagger.annotations.ApiParam;
+import io.swagger.annotations.ApiResponse;
+import io.swagger.annotations.ApiResponses;
+import io.swagger.annotations.Authorization;
+import io.swagger.annotations.Extension;
+import io.swagger.annotations.ExtensionProperty;
+import io.swagger.annotations.ResponseHeader;
+import java.util.UUID;
+import lombok.RequiredArgsConstructor;
+import org.onap.policy.clamp.acm.runtime.instantiation.AutomationCompositionInstantiationProvider;
+import org.onap.policy.clamp.acm.runtime.main.web.AbstractRestController;
+import org.onap.policy.clamp.common.acm.exception.AutomationCompositionException;
+import org.onap.policy.clamp.models.acm.concepts.AutomationCompositions;
+import org.onap.policy.clamp.models.acm.messages.rest.instantiation.AutomationCompositionOrderStateResponse;
+import org.onap.policy.clamp.models.acm.messages.rest.instantiation.AutomationCompositionPrimedResponse;
+import org.onap.policy.clamp.models.acm.messages.rest.instantiation.InstancePropertiesResponse;
+import org.onap.policy.clamp.models.acm.messages.rest.instantiation.InstantiationCommand;
+import org.onap.policy.clamp.models.acm.messages.rest.instantiation.InstantiationResponse;
+import org.onap.policy.models.base.PfModelException;
+import org.onap.policy.models.tosca.authorative.concepts.ToscaServiceTemplate;
+import org.springframework.http.MediaType;
+import org.springframework.http.ResponseEntity;
+import org.springframework.web.bind.annotation.DeleteMapping;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.PutMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestHeader;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.bind.annotation.RestController;
+
+/**
+ * Class to provide REST end points for creating, deleting, query and commanding a automation composition definition.
+ */
+@RestController
+@RequiredArgsConstructor
+public class InstantiationController extends AbstractRestController {
+
+ private static final String TAGS = "Clamp Automation Composition Instantiation API";
+
+ // The Automation Composition provider for instantiation requests
+ private final AutomationCompositionInstantiationProvider provider;
+
+ /**
+ * Creates a automation composition.
+ *
+ * @param requestId request ID used in ONAP logging
+ * @param automationCompositions the automation compositions
+ * @return a response
+ * @throws PfModelException on errors creating a automation composition
+ */
+ // @formatter:off
+ @PostMapping(value = "/instantiation",
+ produces = {MediaType.APPLICATION_JSON_VALUE, APPLICATION_YAML},
+ consumes = {MediaType.APPLICATION_JSON_VALUE, APPLICATION_YAML})
+ @ApiOperation(
+ value = "Commissions automation composition definitions",
+ notes = "Commissions automation composition definitions, returning the automation composition IDs",
+ response = InstantiationResponse.class,
+ tags = {TAGS},
+ authorizations = @Authorization(value = AUTHORIZATION_TYPE),
+ responseHeaders = {
+ @ResponseHeader(
+ name = VERSION_MINOR_NAME,
+ description = VERSION_MINOR_DESCRIPTION,
+ response = String.class),
+ @ResponseHeader(
+ name = VERSION_PATCH_NAME,
+ description = VERSION_PATCH_DESCRIPTION,
+ response = String.class),
+ @ResponseHeader(
+ name = VERSION_LATEST_NAME,
+ description = VERSION_LATEST_DESCRIPTION,
+ response = String.class),
+ @ResponseHeader(
+ name = REQUEST_ID_NAME,
+ description = REQUEST_ID_HDR_DESCRIPTION,
+ response = UUID.class)
+ },
+ extensions = {
+ @Extension
+ (
+ name = EXTENSION_NAME,
+ properties = {
+ @ExtensionProperty(name = API_VERSION_NAME, value = API_VERSION),
+ @ExtensionProperty(name = LAST_MOD_NAME, value = LAST_MOD_RELEASE)
+ }
+ )
+ }
+ )
+ @ApiResponses(
+ value = {
+ @ApiResponse(code = AUTHENTICATION_ERROR_CODE, message = AUTHENTICATION_ERROR_MESSAGE),
+ @ApiResponse(code = AUTHORIZATION_ERROR_CODE, message = AUTHORIZATION_ERROR_MESSAGE),
+ @ApiResponse(code = SERVER_ERROR_CODE, message = SERVER_ERROR_MESSAGE)
+ }
+ )
+ // @formatter:on
+ public ResponseEntity<InstantiationResponse> create(
+ @RequestHeader(name = REQUEST_ID_NAME, required = false) @ApiParam(REQUEST_ID_PARAM_DESCRIPTION) UUID requestId,
+ @ApiParam(
+ value = "Entity Body of automation composition",
+ required = true) @RequestBody AutomationCompositions automationCompositions)
+ throws PfModelException {
+
+ return ResponseEntity.ok().body(provider.createAutomationCompositions(automationCompositions));
+ }
+
+ /**
+ * Saves instance properties.
+ *
+ * @param requestId request ID used in ONAP logging
+ * @param body the body of automation composition following TOSCA definition
+ * @return a response
+ */
+ // @formatter:off
+ @PostMapping(value = "/instanceProperties",
+ consumes = {MediaType.APPLICATION_JSON_VALUE, APPLICATION_YAML},
+ produces = {MediaType.APPLICATION_JSON_VALUE, APPLICATION_YAML})
+ @ApiOperation(
+ value = "Saves instance properties",
+ notes = "Saves instance properties, returning the saved instances properties and it's version",
+ response = InstancePropertiesResponse.class,
+ tags = {TAGS},
+ authorizations = @Authorization(value = AUTHORIZATION_TYPE),
+ responseHeaders = {
+ @ResponseHeader(
+ name = VERSION_MINOR_NAME,
+ description = VERSION_MINOR_DESCRIPTION,
+ response = String.class),
+ @ResponseHeader(
+ name = VERSION_PATCH_NAME,
+ description = VERSION_PATCH_DESCRIPTION,
+ response = String.class),
+ @ResponseHeader(
+ name = VERSION_LATEST_NAME,
+ description = VERSION_LATEST_DESCRIPTION,
+ response = String.class),
+ @ResponseHeader(
+ name = REQUEST_ID_NAME,
+ description = REQUEST_ID_HDR_DESCRIPTION,
+ response = UUID.class)
+ },
+ extensions = {
+ @Extension
+ (
+ name = EXTENSION_NAME,
+ properties = {
+ @ExtensionProperty(name = API_VERSION_NAME, value = API_VERSION),
+ @ExtensionProperty(name = LAST_MOD_NAME, value = LAST_MOD_RELEASE)
+ }
+ )
+ }
+ )
+ @ApiResponses(
+ value = {
+ @ApiResponse(code = AUTHENTICATION_ERROR_CODE, message = AUTHENTICATION_ERROR_MESSAGE),
+ @ApiResponse(code = AUTHORIZATION_ERROR_CODE, message = AUTHORIZATION_ERROR_MESSAGE),
+ @ApiResponse(code = SERVER_ERROR_CODE, message = SERVER_ERROR_MESSAGE)
+ }
+ )
+ // @formatter:on
+ public ResponseEntity<InstancePropertiesResponse> createInstanceProperties(
+ @RequestHeader(name = REQUEST_ID_NAME, required = false) @ApiParam(REQUEST_ID_PARAM_DESCRIPTION) UUID requestId,
+ @ApiParam(value = "Body of instance properties", required = true) @RequestBody ToscaServiceTemplate body)
+ throws PfModelException {
+
+ return ResponseEntity.ok().body(provider.createInstanceProperties(body));
+ }
+
+ /**
+ * Deletes a automation composition definition and instance properties.
+ *
+ * @param requestId request ID used in ONAP logging
+ * @param name the name of the automation composition to delete
+ * @param version the version of the automation composition to delete
+ * @return a response
+ * @throws PfModelException on errors deleting of automation composition and instance properties
+ */
+ // @formatter:off
+ @DeleteMapping(value = "/instanceProperties",
+ produces = {MediaType.APPLICATION_JSON_VALUE, APPLICATION_YAML})
+ @ApiOperation(value = "Delete a automation composition and instance properties",
+ notes = "Deletes a automation composition and instance properties, returning optional error details",
+ response = InstantiationResponse.class,
+ tags = {TAGS},
+ authorizations = @Authorization(value = AUTHORIZATION_TYPE),
+ responseHeaders = {
+ @ResponseHeader(
+ name = VERSION_MINOR_NAME,
+ description = VERSION_MINOR_DESCRIPTION,
+ response = String.class),
+ @ResponseHeader(
+ name = VERSION_PATCH_NAME,
+ description = VERSION_PATCH_DESCRIPTION,
+ response = String.class),
+ @ResponseHeader(
+ name = VERSION_LATEST_NAME,
+ description = VERSION_LATEST_DESCRIPTION,
+ response = String.class),
+ @ResponseHeader(
+ name = REQUEST_ID_NAME,
+ description = REQUEST_ID_HDR_DESCRIPTION,
+ response = UUID.class)},
+ extensions = {
+ @Extension
+ (
+ name = EXTENSION_NAME,
+ properties = {
+ @ExtensionProperty(name = API_VERSION_NAME, value = API_VERSION),
+ @ExtensionProperty(name = LAST_MOD_NAME, value = LAST_MOD_RELEASE)
+ }
+ )
+ }
+ )
+ @ApiResponses(
+ value = {
+ @ApiResponse(code = AUTHENTICATION_ERROR_CODE, message = AUTHENTICATION_ERROR_MESSAGE),
+ @ApiResponse(code = AUTHORIZATION_ERROR_CODE, message = AUTHORIZATION_ERROR_MESSAGE),
+ @ApiResponse(code = SERVER_ERROR_CODE, message = SERVER_ERROR_MESSAGE)
+ }
+ )
+ // @formatter:on
+
+ public ResponseEntity<InstantiationResponse> deleteInstanceProperties(
+ @RequestHeader(name = REQUEST_ID_NAME, required = false) @ApiParam(REQUEST_ID_PARAM_DESCRIPTION) UUID requestId,
+ @ApiParam(value = "Automation composition definition name", required = true) @RequestParam("name") String name,
+ @ApiParam(value = "Automation composition definition version") @RequestParam(
+ value = "version",
+ required = true) String version)
+ throws PfModelException {
+
+ return ResponseEntity.ok().body(provider.deleteInstanceProperties(name, version));
+ }
+
+ /**
+ * Queries details of all automation compositions.
+ *
+ * @param requestId request ID used in ONAP logging
+ * @param name the name of the automation composition to get, null for all automation compositions
+ * @param version the version of the automation composition to get, null for all automation compositions
+ * @return the automation compositions
+ * @throws PfModelException on errors getting commissioning of automation composition
+ */
+ // @formatter:off
+ @GetMapping(value = "/instantiation",
+ produces = {MediaType.APPLICATION_JSON_VALUE, APPLICATION_YAML})
+ @ApiOperation(value = "Query details of the requested automation compositions",
+ notes = "Queries details of the requested automation compositions, returning all composition details",
+ response = AutomationCompositions.class,
+ tags = {TAGS},
+ authorizations = @Authorization(value = AUTHORIZATION_TYPE),
+ responseHeaders = {
+ @ResponseHeader(
+ name = VERSION_MINOR_NAME, description = VERSION_MINOR_DESCRIPTION,
+ response = String.class),
+ @ResponseHeader(name = VERSION_PATCH_NAME, description = VERSION_PATCH_DESCRIPTION,
+ response = String.class),
+ @ResponseHeader(name = VERSION_LATEST_NAME, description = VERSION_LATEST_DESCRIPTION,
+ response = String.class),
+ @ResponseHeader(name = REQUEST_ID_NAME, description = REQUEST_ID_HDR_DESCRIPTION,
+ response = UUID.class)},
+ extensions = {
+ @Extension
+ (
+ name = EXTENSION_NAME,
+ properties = {
+ @ExtensionProperty(name = API_VERSION_NAME, value = API_VERSION),
+ @ExtensionProperty(name = LAST_MOD_NAME, value = LAST_MOD_RELEASE)
+ }
+ )
+ }
+ )
+ @ApiResponses(
+ value = {
+ @ApiResponse(code = AUTHENTICATION_ERROR_CODE, message = AUTHENTICATION_ERROR_MESSAGE),
+ @ApiResponse(code = AUTHORIZATION_ERROR_CODE, message = AUTHORIZATION_ERROR_MESSAGE),
+ @ApiResponse(code = SERVER_ERROR_CODE, message = SERVER_ERROR_MESSAGE)
+ }
+ )
+ // @formatter:on
+ public ResponseEntity<AutomationCompositions> query(
+ @RequestHeader(name = REQUEST_ID_NAME, required = false) @ApiParam(REQUEST_ID_PARAM_DESCRIPTION) UUID requestId,
+ @ApiParam(value = "Automation composition definition name", required = false) @RequestParam(
+ value = "name",
+ required = false) String name,
+ @ApiParam(value = "Automation composition definition version", required = false) @RequestParam(
+ value = "version",
+ required = false) String version)
+ throws PfModelException {
+
+ return ResponseEntity.ok().body(provider.getAutomationCompositions(name, version));
+ }
+
+ /**
+ * Updates a automation composition.
+ *
+ * @param requestId request ID used in ONAP logging
+ * @param automationCompositions the automation compositions
+ * @return a response
+ * @throws PfModelException on errors updating of automation compositions
+ */
+ // @formatter:off
+ @PutMapping(value = "/instantiation",
+ produces = {MediaType.APPLICATION_JSON_VALUE, APPLICATION_YAML},
+ consumes = {MediaType.APPLICATION_JSON_VALUE, APPLICATION_YAML})
+ @ApiOperation(
+ value = "Updates automation composition definitions",
+ notes = "Updates automation composition definitions, returning the updated composition definition IDs",
+ response = InstantiationResponse.class,
+ tags = {TAGS},
+ authorizations = @Authorization(value = AUTHORIZATION_TYPE),
+ responseHeaders = {
+ @ResponseHeader(
+ name = VERSION_MINOR_NAME,
+ description = VERSION_MINOR_DESCRIPTION,
+ response = String.class),
+ @ResponseHeader(
+ name = VERSION_PATCH_NAME,
+ description = VERSION_PATCH_DESCRIPTION,
+ response = String.class),
+ @ResponseHeader(
+ name = VERSION_LATEST_NAME,
+ description = VERSION_LATEST_DESCRIPTION,
+ response = String.class),
+ @ResponseHeader(
+ name = REQUEST_ID_NAME,
+ description = REQUEST_ID_HDR_DESCRIPTION,
+ response = UUID.class)
+ },
+ extensions = {
+ @Extension
+ (
+ name = EXTENSION_NAME,
+ properties = {
+ @ExtensionProperty(name = API_VERSION_NAME, value = API_VERSION),
+ @ExtensionProperty(name = LAST_MOD_NAME, value = LAST_MOD_RELEASE)
+ }
+ )
+ }
+ )
+ @ApiResponses(
+ value = {
+ @ApiResponse(code = AUTHENTICATION_ERROR_CODE, message = AUTHENTICATION_ERROR_MESSAGE),
+ @ApiResponse(code = AUTHORIZATION_ERROR_CODE, message = AUTHORIZATION_ERROR_MESSAGE),
+ @ApiResponse(code = SERVER_ERROR_CODE, message = SERVER_ERROR_MESSAGE)
+ }
+ )
+ // @formatter:on
+ public ResponseEntity<InstantiationResponse> update(
+ @RequestHeader(name = REQUEST_ID_NAME, required = false) @ApiParam(REQUEST_ID_PARAM_DESCRIPTION) UUID requestId,
+ @ApiParam(
+ value = "Entity Body of Automation Composition",
+ required = true) @RequestBody AutomationCompositions automationCompositions)
+ throws PfModelException {
+
+ return ResponseEntity.ok().body(provider.updateAutomationCompositions(automationCompositions));
+ }
+
+ /**
+ * Deletes a automation composition definition.
+ *
+ * @param requestId request ID used in ONAP logging
+ * @param name the name of the automation composition to delete
+ * @param version the version of the automation composition to delete
+ * @return a response
+ * @throws PfModelException on errors deleting of automation composition
+ */
+ // @formatter:off
+ @DeleteMapping(value = "/instantiation",
+ produces = {MediaType.APPLICATION_JSON_VALUE, APPLICATION_YAML})
+ @ApiOperation(value = "Delete a automation composition",
+ notes = "Deletes a automation composition, returning optional error details",
+ response = InstantiationResponse.class,
+ tags = {TAGS},
+ authorizations = @Authorization(value = AUTHORIZATION_TYPE),
+ responseHeaders = {
+ @ResponseHeader(
+ name = VERSION_MINOR_NAME,
+ description = VERSION_MINOR_DESCRIPTION,
+ response = String.class),
+ @ResponseHeader(
+ name = VERSION_PATCH_NAME,
+ description = VERSION_PATCH_DESCRIPTION,
+ response = String.class),
+ @ResponseHeader(
+ name = VERSION_LATEST_NAME,
+ description = VERSION_LATEST_DESCRIPTION,
+ response = String.class),
+ @ResponseHeader(
+ name = REQUEST_ID_NAME,
+ description = REQUEST_ID_HDR_DESCRIPTION,
+ response = UUID.class)},
+ extensions = {
+ @Extension
+ (
+ name = EXTENSION_NAME,
+ properties = {
+ @ExtensionProperty(name = API_VERSION_NAME, value = API_VERSION),
+ @ExtensionProperty(name = LAST_MOD_NAME, value = LAST_MOD_RELEASE)
+ }
+ )
+ }
+ )
+ @ApiResponses(
+ value = {
+ @ApiResponse(code = AUTHENTICATION_ERROR_CODE, message = AUTHENTICATION_ERROR_MESSAGE),
+ @ApiResponse(code = AUTHORIZATION_ERROR_CODE, message = AUTHORIZATION_ERROR_MESSAGE),
+ @ApiResponse(code = SERVER_ERROR_CODE, message = SERVER_ERROR_MESSAGE)
+ }
+ )
+ // @formatter:on
+
+ public ResponseEntity<InstantiationResponse> delete(
+ @RequestHeader(name = REQUEST_ID_NAME, required = false) @ApiParam(REQUEST_ID_PARAM_DESCRIPTION) UUID requestId,
+ @ApiParam(value = "Automation composition definition name", required = true) @RequestParam("name") String name,
+ @ApiParam(value = "Automation composition definition version") @RequestParam(
+ value = "version",
+ required = true) String version)
+ throws PfModelException {
+
+ return ResponseEntity.ok().body(provider.deleteAutomationComposition(name, version));
+ }
+
+ /**
+ * Issues automation composition commands to automation compositions.
+ *
+ * @param requestId request ID used in ONAP logging
+ * @param command the command to issue to automation compositions
+ * @return the automation composition definitions
+ * @throws PfModelException on errors issuing a command
+ * @throws AutomationCompositionException on errors issuing a command
+ */
+ // @formatter:off
+ @PutMapping(value = "/instantiation/command",
+ produces = {MediaType.APPLICATION_JSON_VALUE, APPLICATION_YAML},
+ consumes = {MediaType.APPLICATION_JSON_VALUE, APPLICATION_YAML})
+ @ApiOperation(value = "Issue a command to the requested automation compositions",
+ notes = "Issues a command to an automation composition, ordering a state change on the composition",
+ response = InstantiationResponse.class,
+ tags = {TAGS},
+ authorizations = @Authorization(value = AUTHORIZATION_TYPE),
+ responseHeaders = {
+ @ResponseHeader(
+ name = VERSION_MINOR_NAME, description = VERSION_MINOR_DESCRIPTION,
+ response = String.class),
+ @ResponseHeader(name = VERSION_PATCH_NAME, description = VERSION_PATCH_DESCRIPTION,
+ response = String.class),
+ @ResponseHeader(name = VERSION_LATEST_NAME, description = VERSION_LATEST_DESCRIPTION,
+ response = String.class),
+ @ResponseHeader(name = REQUEST_ID_NAME, description = REQUEST_ID_HDR_DESCRIPTION,
+ response = UUID.class)},
+ extensions = {
+ @Extension
+ (
+ name = EXTENSION_NAME,
+ properties = {
+ @ExtensionProperty(name = API_VERSION_NAME, value = API_VERSION),
+ @ExtensionProperty(name = LAST_MOD_NAME, value = LAST_MOD_RELEASE)
+ }
+ )
+ }
+ )
+ @ApiResponses(
+ value = {
+ @ApiResponse(code = AUTHENTICATION_ERROR_CODE, message = AUTHENTICATION_ERROR_MESSAGE),
+ @ApiResponse(code = AUTHORIZATION_ERROR_CODE, message = AUTHORIZATION_ERROR_MESSAGE),
+ @ApiResponse(code = SERVER_ERROR_CODE, message = SERVER_ERROR_MESSAGE)
+ }
+ )
+ // @formatter:on
+ public ResponseEntity<InstantiationResponse> issueAutomationCompositionCommand(
+ @RequestHeader(name = REQUEST_ID_NAME, required = false) @ApiParam(REQUEST_ID_PARAM_DESCRIPTION) UUID requestId,
+ @ApiParam(
+ value = "Entity Body of automation composition command",
+ required = true) @RequestBody InstantiationCommand command)
+ throws AutomationCompositionException, PfModelException {
+
+ return ResponseEntity.accepted().body(provider.issueAutomationCompositionCommand(command));
+ }
+
+ /**
+ * Queries details of all automation compositions.
+ *
+ * @param requestId request ID used in ONAP logging
+ * @param name the name of the automation composition to get, null for all automation compositions
+ * @param version the version of the automation composition to get, null for all automation compositions
+ * @return the automation compositions
+ * @throws PfModelException on errors getting commissioning of automation composition
+ */
+ // @formatter:off
+ @GetMapping(value = "/instantiationState",
+ produces = {MediaType.APPLICATION_JSON_VALUE, APPLICATION_YAML})
+ @ApiOperation(value = "Query details of the requested automation compositions",
+ notes = "Queries details of requested automation compositions, returning all automation composition details",
+ response = AutomationCompositions.class,
+ tags = {TAGS},
+ authorizations = @Authorization(value = AUTHORIZATION_TYPE),
+ responseHeaders = {
+ @ResponseHeader(
+ name = VERSION_MINOR_NAME, description = VERSION_MINOR_DESCRIPTION,
+ response = String.class),
+ @ResponseHeader(name = VERSION_PATCH_NAME, description = VERSION_PATCH_DESCRIPTION,
+ response = String.class),
+ @ResponseHeader(name = VERSION_LATEST_NAME, description = VERSION_LATEST_DESCRIPTION,
+ response = String.class),
+ @ResponseHeader(name = REQUEST_ID_NAME, description = REQUEST_ID_HDR_DESCRIPTION,
+ response = UUID.class)},
+ extensions = {
+ @Extension
+ (
+ name = EXTENSION_NAME,
+ properties = {
+ @ExtensionProperty(name = API_VERSION_NAME, value = API_VERSION),
+ @ExtensionProperty(name = LAST_MOD_NAME, value = LAST_MOD_RELEASE)
+ }
+ )
+ }
+ )
+ @ApiResponses(
+ value = {
+ @ApiResponse(code = AUTHENTICATION_ERROR_CODE, message = AUTHENTICATION_ERROR_MESSAGE),
+ @ApiResponse(code = AUTHORIZATION_ERROR_CODE, message = AUTHORIZATION_ERROR_MESSAGE),
+ @ApiResponse(code = SERVER_ERROR_CODE, message = SERVER_ERROR_MESSAGE)
+ }
+ )
+ // @formatter:on
+ public ResponseEntity<AutomationCompositionOrderStateResponse> getInstantiationOrderState(
+ @RequestHeader(name = REQUEST_ID_NAME, required = false) @ApiParam(REQUEST_ID_PARAM_DESCRIPTION) UUID requestId,
+ @ApiParam(value = "Automation composition name", required = false) @RequestParam(
+ value = "name",
+ required = false) String name,
+ @ApiParam(value = "Automation composition version", required = false) @RequestParam(
+ value = "version",
+ required = false) String version)
+ throws PfModelException {
+
+ return ResponseEntity.ok().body(provider.getInstantiationOrderState(name, version));
+ }
+
+ /**
+ * Queries Primed/De-Primed status of a automation composition.
+ *
+ * @param requestId request ID used in ONAP logging
+ * @param name the name of the automation composition to get, null for all automation compositions
+ * @param version the version of the automation composition to get, null for all automation compositions
+ * @return the automation compositions
+ * @throws PfModelException on errors getting priming of automation composition
+ */
+ // @formatter:off
+ @GetMapping(value = "/automationCompositionPriming",
+ produces = {MediaType.APPLICATION_JSON_VALUE, APPLICATION_YAML})
+ @ApiOperation(value = "Query priming details of the requested automation compositions",
+ notes = "Queries priming details of requested automation compositions, returning primed/deprimed compositions",
+ response = AutomationCompositionPrimedResponse.class,
+ tags = {TAGS},
+ authorizations = @Authorization(value = AUTHORIZATION_TYPE),
+ responseHeaders = {
+ @ResponseHeader(
+ name = VERSION_MINOR_NAME, description = VERSION_MINOR_DESCRIPTION,
+ response = String.class),
+ @ResponseHeader(name = VERSION_PATCH_NAME, description = VERSION_PATCH_DESCRIPTION,
+ response = String.class),
+ @ResponseHeader(name = VERSION_LATEST_NAME, description = VERSION_LATEST_DESCRIPTION,
+ response = String.class),
+ @ResponseHeader(name = REQUEST_ID_NAME, description = REQUEST_ID_HDR_DESCRIPTION,
+ response = UUID.class)},
+ extensions = {
+ @Extension
+ (
+ name = EXTENSION_NAME,
+ properties = {
+ @ExtensionProperty(name = API_VERSION_NAME, value = API_VERSION),
+ @ExtensionProperty(name = LAST_MOD_NAME, value = LAST_MOD_RELEASE)
+ }
+ )
+ }
+ )
+ @ApiResponses(
+ value = {
+ @ApiResponse(code = AUTHENTICATION_ERROR_CODE, message = AUTHENTICATION_ERROR_MESSAGE),
+ @ApiResponse(code = AUTHORIZATION_ERROR_CODE, message = AUTHORIZATION_ERROR_MESSAGE),
+ @ApiResponse(code = SERVER_ERROR_CODE, message = SERVER_ERROR_MESSAGE)
+ }
+ )
+ // @formatter:on
+ public ResponseEntity<AutomationCompositionPrimedResponse> getAutomationCompositionPriming(
+ @RequestHeader(name = REQUEST_ID_NAME, required = false) @ApiParam(REQUEST_ID_PARAM_DESCRIPTION) UUID requestId,
+ @ApiParam(value = "Automation composition definition name", required = false) @RequestParam(
+ value = "name",
+ required = false) String name,
+ @ApiParam(value = "Automation composition definition version", required = false) @RequestParam(
+ value = "version",
+ required = false) String version)
+ throws PfModelException {
+
+ return ResponseEntity.ok().body(provider.getAutomationCompositionPriming(name, version));
+ }
+}
diff --git a/runtime-acm/src/main/java/org/onap/policy/clamp/acm/runtime/main/rest/MonitoringQueryController.java b/runtime-acm/src/main/java/org/onap/policy/clamp/acm/runtime/main/rest/MonitoringQueryController.java
new file mode 100644
index 000000000..30c1d5dc9
--- /dev/null
+++ b/runtime-acm/src/main/java/org/onap/policy/clamp/acm/runtime/main/rest/MonitoringQueryController.java
@@ -0,0 +1,334 @@
+/*-
+ * ============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.acm.runtime.main.rest;
+
+import io.swagger.annotations.ApiOperation;
+import io.swagger.annotations.ApiParam;
+import io.swagger.annotations.ApiResponse;
+import io.swagger.annotations.ApiResponses;
+import io.swagger.annotations.Authorization;
+import io.swagger.annotations.Extension;
+import io.swagger.annotations.ExtensionProperty;
+import io.swagger.annotations.ResponseHeader;
+import java.time.Instant;
+import java.util.UUID;
+import lombok.RequiredArgsConstructor;
+import org.onap.policy.clamp.acm.runtime.main.web.AbstractRestController;
+import org.onap.policy.clamp.acm.runtime.monitoring.MonitoringProvider;
+import org.onap.policy.clamp.models.acm.concepts.AcElementStatisticsList;
+import org.onap.policy.clamp.models.acm.concepts.ParticipantStatisticsList;
+import org.onap.policy.models.base.PfModelException;
+import org.springframework.http.MediaType;
+import org.springframework.http.ResponseEntity;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RequestHeader;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.bind.annotation.RestController;
+
+/**
+ * This class handles REST endpoints for ACM Statistics monitoring.
+ */
+@RestController
+@RequiredArgsConstructor
+public class MonitoringQueryController extends AbstractRestController {
+
+ private static final String TAGS = "Clamp Automation Composition Monitoring API";
+ private final MonitoringProvider provider;
+
+ /**
+ * Queries details of automation composition participants statistics.
+ *
+ * @param requestId request ID used in ONAP logging
+ * @param name the name of the participant to get, null for all participants statistics
+ * @param version the version of the participant to get, null for all participants with the given name
+ * @param recordCount the record count to be fetched
+ * @param startTime the time from which to get statistics
+ * @param endTime the time to which to get statistics
+ * @return the participant statistics
+ */
+ // @formatter:off
+ @GetMapping(value = "/monitoring/participant",
+ produces = {MediaType.APPLICATION_JSON_VALUE, APPLICATION_YAML})
+ @ApiOperation(value = "Query details of the requested participant stats",
+ notes = "Queries details of the requested participant stats, returning all participant stats",
+ response = ParticipantStatisticsList.class,
+ tags = {TAGS},
+ authorizations = @Authorization(value = AUTHORIZATION_TYPE),
+ responseHeaders = {
+ @ResponseHeader(
+ name = VERSION_MINOR_NAME, description = VERSION_MINOR_DESCRIPTION,
+ response = String.class),
+ @ResponseHeader(name = VERSION_PATCH_NAME, description = VERSION_PATCH_DESCRIPTION,
+ response = String.class),
+ @ResponseHeader(name = VERSION_LATEST_NAME, description = VERSION_LATEST_DESCRIPTION,
+ response = String.class),
+ @ResponseHeader(name = REQUEST_ID_NAME, description = REQUEST_ID_HDR_DESCRIPTION,
+ response = UUID.class)},
+ extensions = {
+ @Extension
+ (
+ name = EXTENSION_NAME,
+ properties = {
+ @ExtensionProperty(name = API_VERSION_NAME, value = API_VERSION),
+ @ExtensionProperty(name = LAST_MOD_NAME, value = LAST_MOD_RELEASE)
+ }
+ )
+ }
+ )
+ @ApiResponses(
+ value = {
+ @ApiResponse(code = AUTHENTICATION_ERROR_CODE, message = AUTHENTICATION_ERROR_MESSAGE),
+ @ApiResponse(code = AUTHORIZATION_ERROR_CODE, message = AUTHORIZATION_ERROR_MESSAGE),
+ @ApiResponse(code = SERVER_ERROR_CODE, message = SERVER_ERROR_MESSAGE)
+ }
+ )
+ // @formatter:on
+ public ResponseEntity<ParticipantStatisticsList> queryParticipantStatistics(
+ @RequestHeader(name = REQUEST_ID_NAME, required = false) @ApiParam(REQUEST_ID_PARAM_DESCRIPTION) UUID requestId,
+ @ApiParam(value = "Automation composition participant name") @RequestParam(
+ value = "name",
+ required = false) final String name,
+ @ApiParam(value = "Automation composition participant version", required = false) @RequestParam(
+ value = "version",
+ required = false) final String version,
+ @ApiParam(value = "Record count", required = false) @RequestParam(
+ value = "recordCount",
+ required = false,
+ defaultValue = "0") final int recordCount,
+ @ApiParam(value = "start time", required = false) @RequestParam(
+ value = "startTime",
+ required = false) final String startTime,
+ @ApiParam(value = "end time", required = false) @RequestParam(
+ value = "endTime",
+ required = false) final String endTime) {
+
+ Instant startTimestamp = null;
+ Instant endTimestamp = null;
+
+ if (startTime != null) {
+ startTimestamp = Instant.parse(startTime);
+ }
+ if (endTime != null) {
+ endTimestamp = Instant.parse(endTime);
+ }
+ return ResponseEntity.ok().body(
+ provider.fetchFilteredParticipantStatistics(name, version, recordCount, startTimestamp, endTimestamp));
+ }
+
+ /**
+ * Queries details of all participant statistics per automation composition.
+ *
+ * @param requestId request ID used in ONAP logging
+ * @param name the name of the automation composition
+ * @param version version of the automation composition
+ * @return the automation composition element statistics
+ */
+ // @formatter:off
+ @GetMapping(value = "/monitoring/participants/automationcomposition",
+ produces = {MediaType.APPLICATION_JSON_VALUE, APPLICATION_YAML})
+ @ApiOperation(value = "Query details of all the participant stats in a automation composition",
+ notes = "Queries details of the participant stats, returning all participant stats",
+ response = AcElementStatisticsList.class,
+ tags = {TAGS},
+ authorizations = @Authorization(value = AUTHORIZATION_TYPE),
+ responseHeaders = {
+ @ResponseHeader(
+ name = VERSION_MINOR_NAME, description = VERSION_MINOR_DESCRIPTION,
+ response = String.class),
+ @ResponseHeader(name = VERSION_PATCH_NAME, description = VERSION_PATCH_DESCRIPTION,
+ response = String.class),
+ @ResponseHeader(name = VERSION_LATEST_NAME, description = VERSION_LATEST_DESCRIPTION,
+ response = String.class),
+ @ResponseHeader(name = REQUEST_ID_NAME, description = REQUEST_ID_HDR_DESCRIPTION,
+ response = UUID.class)},
+ extensions = {
+ @Extension
+ (
+ name = EXTENSION_NAME,
+ properties = {
+ @ExtensionProperty(name = API_VERSION_NAME, value = API_VERSION),
+ @ExtensionProperty(name = LAST_MOD_NAME, value = LAST_MOD_RELEASE)
+ }
+ )
+ })
+ @ApiResponses(
+ value = {
+ @ApiResponse(code = AUTHENTICATION_ERROR_CODE, message = AUTHENTICATION_ERROR_MESSAGE),
+ @ApiResponse(code = AUTHORIZATION_ERROR_CODE, message = AUTHORIZATION_ERROR_MESSAGE),
+ @ApiResponse(code = SERVER_ERROR_CODE, message = SERVER_ERROR_MESSAGE)
+ }
+ )
+ // @formatter:on
+ public ResponseEntity<ParticipantStatisticsList> queryParticipantStatisticsPerAutomationComposition(
+ @RequestHeader(name = REQUEST_ID_NAME, required = false) @ApiParam(REQUEST_ID_PARAM_DESCRIPTION) UUID requestId,
+ @ApiParam(value = "Automation composition name", required = true) @RequestParam(
+ value = "name",
+ required = false) final String name,
+ @ApiParam(value = "Automation composition version", required = true) @RequestParam(
+ value = "version",
+ required = false) final String version) {
+
+ return ResponseEntity.ok().body(provider.fetchParticipantStatsPerAutomationComposition(name, version));
+ }
+
+ /**
+ * Queries details of all automation composition element statistics per automation composition.
+ *
+ * @param requestId request ID used in ONAP logging
+ * @param name the name of the automation composition
+ * @param version version of the automation composition
+ * @return the automation composition element statistics
+ */
+ // @formatter:off
+ @GetMapping(value = "/monitoring/acelements/automationcomposition",
+ produces = {MediaType.APPLICATION_JSON_VALUE, APPLICATION_YAML})
+ @ApiOperation(value = "Query details of the requested acElement stats in a automation composition",
+ notes = "Queries details of the requested acElement stats, returning all acElement stats",
+ response = AcElementStatisticsList.class,
+ tags = {TAGS},
+ authorizations = @Authorization(value = AUTHORIZATION_TYPE),
+ responseHeaders = {
+ @ResponseHeader(
+ name = VERSION_MINOR_NAME, description = VERSION_MINOR_DESCRIPTION,
+ response = String.class),
+ @ResponseHeader(name = VERSION_PATCH_NAME, description = VERSION_PATCH_DESCRIPTION,
+ response = String.class),
+ @ResponseHeader(name = VERSION_LATEST_NAME, description = VERSION_LATEST_DESCRIPTION,
+ response = String.class),
+ @ResponseHeader(name = REQUEST_ID_NAME, description = REQUEST_ID_HDR_DESCRIPTION,
+ response = UUID.class)},
+ extensions = {
+ @Extension
+ (
+ name = EXTENSION_NAME,
+ properties = {
+ @ExtensionProperty(name = API_VERSION_NAME, value = API_VERSION),
+ @ExtensionProperty(name = LAST_MOD_NAME, value = LAST_MOD_RELEASE)
+ }
+ )
+ })
+ @ApiResponses(
+ value = {
+ @ApiResponse(code = AUTHENTICATION_ERROR_CODE, message = AUTHENTICATION_ERROR_MESSAGE),
+ @ApiResponse(code = AUTHORIZATION_ERROR_CODE, message = AUTHORIZATION_ERROR_MESSAGE),
+ @ApiResponse(code = SERVER_ERROR_CODE, message = SERVER_ERROR_MESSAGE)
+ }
+ )
+ // @formatter:on
+ public ResponseEntity<AcElementStatisticsList> queryElementStatisticsPerAutomationComposition(
+ @RequestHeader(name = REQUEST_ID_NAME, required = false) @ApiParam(REQUEST_ID_PARAM_DESCRIPTION) UUID requestId,
+ @ApiParam(value = "Automation composition name", required = true) @RequestParam(
+ value = "name",
+ required = false) final String name,
+ @ApiParam(value = "Automation composition version", required = true) @RequestParam(
+ value = "version",
+ required = false) final String version) {
+
+ return ResponseEntity.ok().body(provider.fetchAcElementStatsPerAutomationComposition(name, version));
+ }
+
+ /**
+ * Queries details of all automation composition element statistics per automation composition.
+ *
+ * @param requestId request ID used in ONAP logging
+ * @param name the name of the automation composition
+ * @param version version of the automation composition
+ * @param id Id of the automation composition element
+ * @param recordCount the record count to be fetched
+ * @param startTime the time from which to get statistics
+ * @param endTime the time to which to get statistics
+ * @return the automation composition element statistics
+ * @throws PfModelException on errors getting details of all automation composition element statistics per
+ * automation composition
+ */
+ // @formatter:off
+ @GetMapping(value = "/monitoring/acelement",
+ produces = {MediaType.APPLICATION_JSON_VALUE, APPLICATION_YAML})
+ @ApiOperation(value = "Query details of the requested acElement stats",
+ notes = "Queries details of the requested acElement stats, returning all acElement stats",
+ response = AcElementStatisticsList.class,
+ tags = {TAGS},
+ authorizations = @Authorization(value = AUTHORIZATION_TYPE),
+ responseHeaders = {
+ @ResponseHeader(
+ name = VERSION_MINOR_NAME, description = VERSION_MINOR_DESCRIPTION,
+ response = String.class),
+ @ResponseHeader(name = VERSION_PATCH_NAME, description = VERSION_PATCH_DESCRIPTION,
+ response = String.class),
+ @ResponseHeader(name = VERSION_LATEST_NAME, description = VERSION_LATEST_DESCRIPTION,
+ response = String.class),
+ @ResponseHeader(name = REQUEST_ID_NAME, description = REQUEST_ID_HDR_DESCRIPTION,
+ response = UUID.class)},
+ extensions = {
+ @Extension
+ (
+ name = EXTENSION_NAME,
+ properties = {
+ @ExtensionProperty(name = API_VERSION_NAME, value = API_VERSION),
+ @ExtensionProperty(name = LAST_MOD_NAME, value = LAST_MOD_RELEASE)
+ }
+ )
+ })
+ @ApiResponses(
+ value = {
+ @ApiResponse(code = AUTHENTICATION_ERROR_CODE, message = AUTHENTICATION_ERROR_MESSAGE),
+ @ApiResponse(code = AUTHORIZATION_ERROR_CODE, message = AUTHORIZATION_ERROR_MESSAGE),
+ @ApiResponse(code = SERVER_ERROR_CODE, message = SERVER_ERROR_MESSAGE)
+ }
+ )
+ // @formatter:on
+ public ResponseEntity<AcElementStatisticsList> queryElementStatistics(
+ @RequestHeader(name = REQUEST_ID_NAME, required = false) @ApiParam(REQUEST_ID_PARAM_DESCRIPTION) UUID requestId,
+ @ApiParam(value = "Participant name", required = true) @RequestParam(
+ value = "name",
+ required = false) final String name,
+ @ApiParam(value = "Participant version", required = true) @RequestParam(
+ value = "version",
+ required = false) final String version,
+ @ApiParam(value = "Record count", required = false) @RequestParam(
+ value = "recordCount",
+ required = false,
+ defaultValue = "0") final int recordCount,
+ @ApiParam(value = "Automation composition element id", required = false) @RequestParam(
+ value = "id",
+ required = false) final String id,
+ @ApiParam(value = "start time", required = false) @RequestParam(
+ value = "startTime",
+ required = false) final String startTime,
+ @ApiParam(value = "end time", required = false) @RequestParam(
+ value = "endTime",
+ required = false) final String endTime)
+ throws PfModelException {
+
+ Instant startTimestamp = null;
+ Instant endTimestamp = null;
+
+ if (startTime != null) {
+ startTimestamp = Instant.parse(startTime);
+ }
+ if (endTime != null) {
+ endTimestamp = Instant.parse(endTime);
+ }
+ return ResponseEntity.ok().body(
+ provider.fetchFilteredAcElementStatistics(name, version, id, startTimestamp, endTimestamp, recordCount));
+ }
+
+}
diff --git a/runtime-acm/src/main/java/org/onap/policy/clamp/acm/runtime/main/web/AbstractRestController.java b/runtime-acm/src/main/java/org/onap/policy/clamp/acm/runtime/main/web/AbstractRestController.java
new file mode 100644
index 000000000..7907de7be
--- /dev/null
+++ b/runtime-acm/src/main/java/org/onap/policy/clamp/acm/runtime/main/web/AbstractRestController.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.acm.runtime.main.web;
+
+import io.swagger.annotations.Api;
+import io.swagger.annotations.BasicAuthDefinition;
+import io.swagger.annotations.Info;
+import io.swagger.annotations.SecurityDefinition;
+import io.swagger.annotations.SwaggerDefinition;
+import io.swagger.annotations.Tag;
+import java.net.HttpURLConnection;
+import javax.ws.rs.core.MediaType;
+import org.springframework.web.bind.annotation.RequestMapping;
+
+/**
+ * Common superclass to provide REST endpoints for the participant simulator.
+ */
+// @formatter:off
+@RequestMapping(value = "/v2", produces = {MediaType.APPLICATION_JSON, AbstractRestController.APPLICATION_YAML})
+@Api(value = "Automation Composition Commissioning API")
+@SwaggerDefinition(
+ info = @Info(description =
+ "Automation Composition Service", version = "v1.0",
+ title = "Automation Composition"),
+ consumes = {MediaType.APPLICATION_JSON, AbstractRestController.APPLICATION_YAML},
+ produces = {MediaType.APPLICATION_JSON, AbstractRestController.APPLICATION_YAML},
+ schemes = {SwaggerDefinition.Scheme.HTTP, SwaggerDefinition.Scheme.HTTPS},
+ tags = {@Tag(name = "automationcomposition", description = "Automation Composition Service")},
+ securityDefinition = @SecurityDefinition(basicAuthDefinitions = {@BasicAuthDefinition(key = "basicAuth")}))
+// @formatter:on
+public abstract class AbstractRestController {
+ public static final String APPLICATION_YAML = "application/yaml";
+
+ public static final String EXTENSION_NAME = "interface info";
+
+ public static final String API_VERSION_NAME = "api-version";
+ public static final String API_VERSION = "1.0.0";
+
+ public static final String LAST_MOD_NAME = "last-mod-release";
+ public static final String LAST_MOD_RELEASE = "Istanbul";
+
+ public static final String VERSION_MINOR_NAME = "X-MinorVersion";
+ public static final String VERSION_MINOR_DESCRIPTION =
+ "Used to request or communicate a MINOR version back from the client"
+ + " to the server, and from the server back to the client";
+
+ public static final String VERSION_PATCH_NAME = "X-PatchVersion";
+ public static final String VERSION_PATCH_DESCRIPTION = "Used only to communicate a PATCH version in a response for"
+ + " troubleshooting purposes only, and will not be provided by" + " the client on request";
+
+ public static final String VERSION_LATEST_NAME = "X-LatestVersion";
+ public static final String VERSION_LATEST_DESCRIPTION = "Used only to communicate an API's latest version";
+
+ public static final String REQUEST_ID_NAME = "X-ONAP-RequestID";
+ public static final String REQUEST_ID_HDR_DESCRIPTION = "Used to track REST transactions for logging purpose";
+ public static final String REQUEST_ID_PARAM_DESCRIPTION = "RequestID for http transaction";
+
+ public static final String AUTHORIZATION_TYPE = "basicAuth";
+
+ public static final int AUTHENTICATION_ERROR_CODE = HttpURLConnection.HTTP_UNAUTHORIZED;
+ public static final int AUTHORIZATION_ERROR_CODE = HttpURLConnection.HTTP_FORBIDDEN;
+ public static final int SERVER_ERROR_CODE = HttpURLConnection.HTTP_INTERNAL_ERROR;
+
+ public static final String AUTHENTICATION_ERROR_MESSAGE = "Authentication Error";
+ public static final String AUTHORIZATION_ERROR_MESSAGE = "Authorization Error";
+ public static final String SERVER_ERROR_MESSAGE = "Internal Server Error";
+
+ /**
+ * Constructor.
+ */
+ protected AbstractRestController() {
+ }
+}
diff --git a/runtime-acm/src/main/java/org/onap/policy/clamp/acm/runtime/main/web/AutomationConfiguraitonAafFilter.java b/runtime-acm/src/main/java/org/onap/policy/clamp/acm/runtime/main/web/AutomationConfiguraitonAafFilter.java
new file mode 100644
index 000000000..ed49e3b44
--- /dev/null
+++ b/runtime-acm/src/main/java/org/onap/policy/clamp/acm/runtime/main/web/AutomationConfiguraitonAafFilter.java
@@ -0,0 +1,38 @@
+/*-
+ * ============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.acm.runtime.main.web;
+
+import org.onap.policy.common.endpoints.http.server.aaf.AafGranularAuthFilter;
+import org.onap.policy.common.utils.resources.MessageConstants;
+
+/**
+ * Class to manage AAF filters for the automation composition runtime component.
+ */
+public class AutomationConfiguraitonAafFilter extends AafGranularAuthFilter {
+
+ public static final String AAF_NODETYPE = MessageConstants.POLICY_CLAMP;
+ public static final String AAF_ROOT_PERMISSION = DEFAULT_NAMESPACE + "." + AAF_NODETYPE;
+
+ @Override
+ public String getPermissionTypeRoot() {
+ return AAF_ROOT_PERMISSION;
+ }
+}
diff --git a/runtime-acm/src/main/java/org/onap/policy/clamp/acm/runtime/main/web/GlobalControllerExceptionHandler.java b/runtime-acm/src/main/java/org/onap/policy/clamp/acm/runtime/main/web/GlobalControllerExceptionHandler.java
new file mode 100644
index 000000000..fef358bb1
--- /dev/null
+++ b/runtime-acm/src/main/java/org/onap/policy/clamp/acm/runtime/main/web/GlobalControllerExceptionHandler.java
@@ -0,0 +1,67 @@
+/*-
+ * ============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.acm.runtime.main.web;
+
+import org.onap.policy.clamp.common.acm.exception.AutomationCompositionException;
+import org.onap.policy.clamp.models.acm.messages.rest.SimpleResponse;
+import org.onap.policy.clamp.models.acm.rest.RestUtils;
+import org.onap.policy.models.base.PfModelException;
+import org.onap.policy.models.base.PfModelRuntimeException;
+import org.springframework.http.ResponseEntity;
+import org.springframework.web.bind.annotation.ExceptionHandler;
+import org.springframework.web.bind.annotation.RestControllerAdvice;
+
+@RestControllerAdvice
+public class GlobalControllerExceptionHandler {
+
+ /**
+ * Handle AutomationCompositionException.
+ *
+ * @param ex AutomationCompositionException
+ * @return ResponseEntity
+ */
+ @ExceptionHandler(AutomationCompositionException.class)
+ public ResponseEntity<SimpleResponse> handleBadRequest(AutomationCompositionException ex) {
+ return RestUtils.toSimpleResponse(ex);
+ }
+
+ /**
+ * Handle PfModelRuntimeException.
+ *
+ * @param ex PfModelRuntimeException
+ * @return ResponseEntity
+ */
+ @ExceptionHandler(PfModelRuntimeException.class)
+ public ResponseEntity<SimpleResponse> handleBadRequest(PfModelRuntimeException ex) {
+ return RestUtils.toSimpleResponse(ex);
+ }
+
+ /**
+ * Handle PfModelException.
+ *
+ * @param ex PfModelException
+ * @return ResponseEntity
+ */
+ @ExceptionHandler(PfModelException.class)
+ public ResponseEntity<SimpleResponse> handleBadRequest(PfModelException ex) {
+ return RestUtils.toSimpleResponse(ex);
+ }
+}
diff --git a/runtime-acm/src/main/java/org/onap/policy/clamp/acm/runtime/main/web/RuntimeErrorController.java b/runtime-acm/src/main/java/org/onap/policy/clamp/acm/runtime/main/web/RuntimeErrorController.java
new file mode 100644
index 000000000..5eecb92dd
--- /dev/null
+++ b/runtime-acm/src/main/java/org/onap/policy/clamp/acm/runtime/main/web/RuntimeErrorController.java
@@ -0,0 +1,104 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * Copyright (C) 2021 Nordix Foundation.
+ * ================================================================================
+ * Modifications Copyright (C) 2021 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * 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.acm.runtime.main.web;
+
+import io.swagger.v3.oas.annotations.Hidden;
+import java.util.Map;
+import javax.servlet.RequestDispatcher;
+import javax.servlet.http.HttpServletRequest;
+import org.onap.policy.clamp.models.acm.messages.rest.SimpleResponse;
+import org.onap.policy.clamp.models.acm.messages.rest.TypedSimpleResponse;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.boot.web.error.ErrorAttributeOptions;
+import org.springframework.boot.web.servlet.error.ErrorAttributes;
+import org.springframework.boot.web.servlet.error.ErrorController;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.MediaType;
+import org.springframework.http.ResponseEntity;
+import org.springframework.stereotype.Controller;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.context.request.ServletWebRequest;
+
+@Controller
+@Hidden
+public class RuntimeErrorController implements ErrorController {
+
+ private static final Logger LOGGER = LoggerFactory.getLogger(RuntimeErrorController.class);
+
+ private final ErrorAttributes errorAttributes;
+
+ @Value("${server.error.path}")
+ private String path;
+
+ /**
+ * Constructor.
+ *
+ * @param errorAttributes ErrorAttributes
+ */
+ public RuntimeErrorController(ErrorAttributes errorAttributes) {
+ this.errorAttributes = errorAttributes;
+ }
+
+ protected HttpStatus getStatus(HttpServletRequest request) {
+ Integer statusCode = (Integer) request.getAttribute(RequestDispatcher.ERROR_STATUS_CODE);
+ if (statusCode == null) {
+ return HttpStatus.INTERNAL_SERVER_ERROR;
+ }
+ try {
+ return HttpStatus.valueOf(statusCode);
+ } catch (Exception ex) {
+ LOGGER.error("statusCode {} Not Valid", statusCode, ex);
+ return HttpStatus.INTERNAL_SERVER_ERROR;
+ }
+ }
+
+ /**
+ * Handle Errors not handled to GlobalControllerExceptionHandler.
+ *
+ * @param request HttpServletRequest
+ * @return ResponseEntity
+ */
+ @RequestMapping(value = "${server.error.path}", produces = MediaType.APPLICATION_JSON_VALUE)
+ public ResponseEntity<TypedSimpleResponse<SimpleResponse>> handleError(HttpServletRequest request) {
+ Map<String, Object> map = this.errorAttributes.getErrorAttributes(new ServletWebRequest(request),
+ ErrorAttributeOptions.defaults());
+
+ var sb = new StringBuilder();
+ final Object error = map.get("error");
+ if (error != null) {
+ sb.append(error.toString()).append(" ");
+ }
+ final Object message = map.get("message");
+ if (message != null) {
+ sb.append(message.toString());
+ }
+
+ TypedSimpleResponse<SimpleResponse> resp = new TypedSimpleResponse<>();
+ resp.setErrorDetails(sb.toString());
+
+ return ResponseEntity.status(getStatus(request)).body(resp);
+
+ }
+}
diff --git a/runtime-acm/src/main/java/org/onap/policy/clamp/acm/runtime/monitoring/MonitoringProvider.java b/runtime-acm/src/main/java/org/onap/policy/clamp/acm/runtime/monitoring/MonitoringProvider.java
new file mode 100644
index 000000000..2950ad9da
--- /dev/null
+++ b/runtime-acm/src/main/java/org/onap/policy/clamp/acm/runtime/monitoring/MonitoringProvider.java
@@ -0,0 +1,247 @@
+/*-
+ * ============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.acm.runtime.monitoring;
+
+import java.time.Instant;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import lombok.AllArgsConstructor;
+import lombok.NonNull;
+import org.onap.policy.clamp.models.acm.concepts.AcElementStatistics;
+import org.onap.policy.clamp.models.acm.concepts.AcElementStatisticsList;
+import org.onap.policy.clamp.models.acm.concepts.AutomationCompositionElement;
+import org.onap.policy.clamp.models.acm.concepts.ParticipantStatistics;
+import org.onap.policy.clamp.models.acm.concepts.ParticipantStatisticsList;
+import org.onap.policy.clamp.models.acm.persistence.provider.AcElementStatisticsProvider;
+import org.onap.policy.clamp.models.acm.persistence.provider.AutomationCompositionProvider;
+import org.onap.policy.clamp.models.acm.persistence.provider.ParticipantStatisticsProvider;
+import org.onap.policy.models.base.PfModelException;
+import org.onap.policy.models.base.PfModelRuntimeException;
+import org.onap.policy.models.tosca.authorative.concepts.ToscaConceptIdentifier;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+/**
+ * This class provides information about statistics data of Automation Composition elements and Participants in database
+ * to callers.
+ */
+@Service
+@Transactional
+@AllArgsConstructor
+public class MonitoringProvider {
+
+ private static final String DESC_ORDER = "DESC";
+ private final ParticipantStatisticsProvider participantStatisticsProvider;
+ private final AcElementStatisticsProvider acElementStatisticsProvider;
+ private final AutomationCompositionProvider automationCompositionProvider;
+
+ /**
+ * Create participant statistics.
+ *
+ * @param participantStatistics the participant statistics
+ * @return the result of create operation
+ * @throws PfModelException on creation errors
+ */
+ public ParticipantStatisticsList createParticipantStatistics(List<ParticipantStatistics> participantStatistics)
+ throws PfModelException {
+ var participantStatisticsList = new ParticipantStatisticsList();
+ participantStatisticsList
+ .setStatisticsList(participantStatisticsProvider.createParticipantStatistics(participantStatistics));
+
+ return participantStatisticsList;
+ }
+
+ /**
+ * Create AcElement statistics.
+ *
+ * @param acElementStatisticsList the AcElement statistics
+ * @return the result of create operation
+ * @throws PfModelException on creation errors
+ */
+ public AcElementStatisticsList createAcElementStatistics(List<AcElementStatistics> acElementStatisticsList)
+ throws PfModelException {
+ var elementStatisticsList = new AcElementStatisticsList();
+ elementStatisticsList
+ .setAcElementStatistics(acElementStatisticsProvider.createAcElementStatistics(acElementStatisticsList));
+
+ return elementStatisticsList;
+ }
+
+ /**
+ * Get participant statistics based on specific filters.
+ *
+ * @param name the name of the participant statistics to get, null to get all statistics
+ * @param version the version of the participant statistics to get, null to get all statistics
+ * @param recordCount number of records to be fetched.
+ * @param startTime start of the timestamp, from statistics to be filtered
+ * @param endTime end of the timestamp up to which statistics to be filtered
+ * @return the participant found
+ */
+ @Transactional(readOnly = true)
+ public ParticipantStatisticsList fetchFilteredParticipantStatistics(@NonNull final String name,
+ final String version, int recordCount, Instant startTime, Instant endTime) {
+ var participantStatisticsList = new ParticipantStatisticsList();
+
+ // Additional parameters can be added in filterMap for filtering data.
+ Map<String, Object> filterMap = null;
+ participantStatisticsList.setStatisticsList(participantStatisticsProvider.getFilteredParticipantStatistics(name,
+ version, startTime, endTime, filterMap, DESC_ORDER, recordCount));
+
+ return participantStatisticsList;
+ }
+
+ /**
+ * Get all participant statistics records found for a specific automation composition.
+ *
+ * @param automationCompositionName name of the automation composition
+ * @param automationCompositionVersion version of the automation composition
+ * @return All the participant statistics found
+ * @throws PfModelRuntimeException on errors getting participant statistics
+ */
+ @Transactional(readOnly = true)
+ public ParticipantStatisticsList fetchParticipantStatsPerAutomationComposition(
+ @NonNull final String automationCompositionName, @NonNull final String automationCompositionVersion) {
+ var statisticsList = new ParticipantStatisticsList();
+ List<ParticipantStatistics> participantStatistics = new ArrayList<>();
+ try {
+ // Fetch all participantIds for a specific automation composition
+ List<ToscaConceptIdentifier> participantIds =
+ getAllParticipantIdsPerAutomationComposition(automationCompositionName, automationCompositionVersion);
+ for (ToscaConceptIdentifier id : participantIds) {
+ participantStatistics.addAll(participantStatisticsProvider
+ .getFilteredParticipantStatistics(id.getName(), id.getVersion(), null, null, null, DESC_ORDER, 0));
+ }
+ statisticsList.setStatisticsList(participantStatistics);
+ } catch (PfModelException e) {
+ throw new PfModelRuntimeException(e);
+ }
+ return statisticsList;
+ }
+
+ /**
+ * Get AcElement statistics based on specific filters.
+ *
+ * @param name the name of the AcElement statistics to get, null to get all statistics
+ * @param version the version of the AcElement statistics to get, null to get all statistics
+ * @param id UUID of the automation composition element
+ * @param startTime start of the timestamp, from statistics to be filtered
+ * @param endTime end of the timestamp up to which statistics to be filtered
+ * @param recordCount number of records to be fetched.
+ * @return the participant found
+ * @throws PfModelException on errors getting automation composition statistics
+ */
+ @Transactional(readOnly = true)
+ public AcElementStatisticsList fetchFilteredAcElementStatistics(@NonNull final String name, final String version,
+ final String id, Instant startTime, Instant endTime, int recordCount) throws PfModelException {
+ var acElementStatisticsList = new AcElementStatisticsList();
+ Map<String, Object> filterMap = new HashMap<>();
+ // Adding UUID in filter if present
+ if (id != null) {
+ filterMap.put("localName", id);
+ }
+ acElementStatisticsList.setAcElementStatistics(acElementStatisticsProvider.getFilteredAcElementStatistics(name,
+ version, startTime, endTime, filterMap, DESC_ORDER, recordCount));
+
+ return acElementStatisticsList;
+ }
+
+ /**
+ * Get AcElement statistics per automation composition.
+ *
+ * @param name the name of the automation composition
+ * @param version the version of the automation composition
+ * @return the AcElement statistics found
+ * @throws PfModelRuntimeException on errors getting automation composition statistics
+ */
+ @Transactional(readOnly = true)
+ public AcElementStatisticsList fetchAcElementStatsPerAutomationComposition(@NonNull final String name,
+ @NonNull final String version) {
+ var acElementStatisticsList = new AcElementStatisticsList();
+ List<AcElementStatistics> acElementStats = new ArrayList<>();
+ try {
+ List<AutomationCompositionElement> acElements = new ArrayList<>();
+ // Fetch all automation composition elements for the automation composition
+ var automationCompositionOpt =
+ automationCompositionProvider.findAutomationComposition(new ToscaConceptIdentifier(name, version));
+ if (automationCompositionOpt.isPresent()) {
+ acElements.addAll(automationCompositionOpt.get().getElements().values());
+ // Collect automation composition element statistics for each acElement.
+ for (AutomationCompositionElement acElement : acElements) {
+ acElementStats.addAll(fetchFilteredAcElementStatistics(acElement.getParticipantId().getName(),
+ acElement.getParticipantId().getVersion(), acElement.getId().toString(), null, null, 0)
+ .getAcElementStatistics());
+ }
+ }
+ acElementStatisticsList.setAcElementStatistics(acElementStats);
+ } catch (PfModelException e) {
+ throw new PfModelRuntimeException(e);
+ }
+ return acElementStatisticsList;
+ }
+
+ /**
+ * If required, REST end point can be defined for this method to fetch associated participant Ids
+ * for a automation composition.
+ *
+ * @param name the name of the automation composition
+ * @param version the version of the automation composition
+ * @return List of participant Id
+ * @throws PfModelException on errors
+ */
+ @Transactional(readOnly = true)
+ public List<ToscaConceptIdentifier> getAllParticipantIdsPerAutomationComposition(String name, String version)
+ throws PfModelException {
+ List<ToscaConceptIdentifier> participantIds = new ArrayList<>();
+ var automationCompositionOpt =
+ automationCompositionProvider.findAutomationComposition(new ToscaConceptIdentifier(name, version));
+ if (automationCompositionOpt.isPresent()) {
+ for (AutomationCompositionElement acElement : automationCompositionOpt.get().getElements().values()) {
+ participantIds.add(acElement.getParticipantId());
+ }
+ }
+ return participantIds;
+ }
+
+ /**
+ * If required, REST end point can be defined for this method to fetch associated automation composition element Ids
+ * for a automation composition.
+ *
+ * @param name the name of the automation composition
+ * @param version the version of the automation composition
+ * @return Map of automation composition Id and participant details
+ * @throws PfModelException on errors
+ */
+ @Transactional(readOnly = true)
+ public Map<String, ToscaConceptIdentifier> getAllAcElementsIdPerAutomationComposition(String name, String version)
+ throws PfModelException {
+ Map<String, ToscaConceptIdentifier> acElementId = new HashMap<>();
+ var automationCompositionOpt =
+ automationCompositionProvider.findAutomationComposition(new ToscaConceptIdentifier(name, version));
+ if (automationCompositionOpt.isPresent()) {
+ for (AutomationCompositionElement acElement : automationCompositionOpt.get().getElements().values()) {
+ acElementId.put(acElement.getId().toString(), acElement.getParticipantId());
+ }
+ }
+ return acElementId;
+ }
+}
diff --git a/runtime-acm/src/main/java/org/onap/policy/clamp/acm/runtime/supervision/HandleCounter.java b/runtime-acm/src/main/java/org/onap/policy/clamp/acm/runtime/supervision/HandleCounter.java
new file mode 100644
index 000000000..9949f3c89
--- /dev/null
+++ b/runtime-acm/src/main/java/org/onap/policy/clamp/acm/runtime/supervision/HandleCounter.java
@@ -0,0 +1,106 @@
+/*-
+ * ============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.acm.runtime.supervision;
+
+import java.time.Instant;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+import lombok.Getter;
+import lombok.Setter;
+
+public class HandleCounter<K> {
+ @Getter
+ @Setter
+ private long maxWaitMs;
+
+ @Getter
+ @Setter
+ private int maxRetryCount;
+
+ private Map<K, Integer> mapCounter = new HashMap<>();
+ private Set<K> mapFault = new HashSet<>();
+ private Map<K, Long> mapTimer = new HashMap<>();
+
+ public long getDuration(K id) {
+ mapTimer.putIfAbsent(id, getEpochMilli());
+ return getEpochMilli() - mapTimer.get(id);
+ }
+
+ /**
+ * Reset timer and clear counter and fault by id.
+ *
+ * @param id the id
+ */
+ public void clear(K id) {
+ mapFault.remove(id);
+ mapCounter.put(id, 0);
+ mapTimer.put(id, getEpochMilli());
+ }
+
+ /**
+ * Remove counter, timer and fault by id.
+ *
+ * @param id the id
+ */
+ public void remove(K id) {
+ mapFault.remove(id);
+ mapCounter.remove(id);
+ mapTimer.remove(id);
+ }
+
+ public void setFault(K id) {
+ mapCounter.put(id, 0);
+ mapFault.add(id);
+ }
+
+ /**
+ * Increment RetryCount by id e return true if minor or equal of maxRetryCount.
+ *
+ * @param id the identifier
+ * @return false if count is major of maxRetryCount
+ */
+ public boolean count(K id) {
+ int counter = mapCounter.getOrDefault(id, 0) + 1;
+ if (counter <= maxRetryCount) {
+ mapCounter.put(id, counter);
+ return true;
+ }
+ return false;
+ }
+
+ public boolean isFault(K id) {
+ return mapFault.contains(id);
+ }
+
+ public int getCounter(K id) {
+ return mapCounter.getOrDefault(id, 0);
+ }
+
+ protected long getEpochMilli() {
+ return Instant.now().toEpochMilli();
+ }
+
+ public Set<K> keySet() {
+ return mapCounter.keySet();
+ }
+}
diff --git a/runtime-acm/src/main/java/org/onap/policy/clamp/acm/runtime/supervision/MessageIntercept.java b/runtime-acm/src/main/java/org/onap/policy/clamp/acm/runtime/supervision/MessageIntercept.java
new file mode 100644
index 000000000..5b861ce96
--- /dev/null
+++ b/runtime-acm/src/main/java/org/onap/policy/clamp/acm/runtime/supervision/MessageIntercept.java
@@ -0,0 +1,32 @@
+/*-
+ * ============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.acm.runtime.supervision;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+@Retention(RetentionPolicy.RUNTIME)
+@Target(ElementType.METHOD)
+public @interface MessageIntercept {
+
+}
diff --git a/runtime-acm/src/main/java/org/onap/policy/clamp/acm/runtime/supervision/SupervisionAspect.java b/runtime-acm/src/main/java/org/onap/policy/clamp/acm/runtime/supervision/SupervisionAspect.java
new file mode 100644
index 000000000..ea851da81
--- /dev/null
+++ b/runtime-acm/src/main/java/org/onap/policy/clamp/acm/runtime/supervision/SupervisionAspect.java
@@ -0,0 +1,105 @@
+/*-
+ * ============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.acm.runtime.supervision;
+
+import java.io.Closeable;
+import java.io.IOException;
+import java.util.concurrent.LinkedBlockingQueue;
+import java.util.concurrent.ThreadPoolExecutor;
+import java.util.concurrent.TimeUnit;
+import lombok.RequiredArgsConstructor;
+import org.apache.commons.lang3.tuple.ImmutablePair;
+import org.aspectj.lang.annotation.After;
+import org.aspectj.lang.annotation.AfterReturning;
+import org.aspectj.lang.annotation.Aspect;
+import org.aspectj.lang.annotation.Before;
+import org.onap.policy.clamp.models.acm.messages.dmaap.participant.ParticipantRegister;
+import org.onap.policy.clamp.models.acm.messages.dmaap.participant.ParticipantStatus;
+import org.onap.policy.clamp.models.acm.messages.dmaap.participant.ParticipantUpdateAck;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.scheduling.annotation.Scheduled;
+import org.springframework.stereotype.Component;
+
+@Aspect
+@Component
+@RequiredArgsConstructor
+public class SupervisionAspect implements Closeable {
+
+ private static final Logger LOGGER = LoggerFactory.getLogger(SupervisionAspect.class);
+
+ private final SupervisionScanner supervisionScanner;
+
+ private ThreadPoolExecutor executor =
+ new ThreadPoolExecutor(1, 1, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<>());
+
+ @Scheduled(
+ fixedRateString = "${runtime.participantParameters.heartBeatMs}",
+ initialDelayString = "${runtime.participantParameters.heartBeatMs}")
+ public void schedule() {
+ LOGGER.info("Add scheduled scanning");
+ executor.execute(() -> supervisionScanner.run(true));
+ }
+
+ /**
+ * Intercept Messages from participant and run Supervision Scan.
+ */
+ @After("@annotation(MessageIntercept)")
+ public void doCheck() {
+ if (executor.getQueue().size() < 2) {
+ LOGGER.debug("Add scanning Message");
+ executor.execute(() -> supervisionScanner.run(false));
+ }
+ }
+
+ @Before("@annotation(MessageIntercept) && args(participantStatusMessage,..)")
+ public void handleParticipantStatus(ParticipantStatus participantStatusMessage) {
+ executor.execute(() -> supervisionScanner.handleParticipantStatus(participantStatusMessage.getParticipantId()));
+ }
+
+ /**
+ * Intercepts participant Register Message
+ * if there is a Commissioning starts an execution of handleParticipantRegister.
+ *
+ * @param participantRegisterMessage the ParticipantRegister message
+ * @param isCommissioning is Commissioning
+ */
+ @AfterReturning(
+ value = "@annotation(MessageIntercept) && args(participantRegisterMessage,..)",
+ returning = "isCommissioning")
+ public void handleParticipantRegister(ParticipantRegister participantRegisterMessage, boolean isCommissioning) {
+ if (isCommissioning) {
+ executor.execute(() -> supervisionScanner.handleParticipantRegister(new ImmutablePair<>(
+ participantRegisterMessage.getParticipantId(), participantRegisterMessage.getParticipantType())));
+ }
+ }
+
+ @Before("@annotation(MessageIntercept) && args(participantUpdateAckMessage,..)")
+ public void handleParticipantUpdateAck(ParticipantUpdateAck participantUpdateAckMessage) {
+ executor.execute(() -> supervisionScanner.handleParticipantUpdateAck(new ImmutablePair<>(
+ participantUpdateAckMessage.getParticipantId(), participantUpdateAckMessage.getParticipantType())));
+ }
+
+ @Override
+ public void close() throws IOException {
+ executor.shutdown();
+ }
+}
diff --git a/runtime-acm/src/main/java/org/onap/policy/clamp/acm/runtime/supervision/SupervisionHandler.java b/runtime-acm/src/main/java/org/onap/policy/clamp/acm/runtime/supervision/SupervisionHandler.java
new file mode 100644
index 000000000..055acb28f
--- /dev/null
+++ b/runtime-acm/src/main/java/org/onap/policy/clamp/acm/runtime/supervision/SupervisionHandler.java
@@ -0,0 +1,518 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * Copyright (C) 2021 Nordix Foundation.
+ * Modifications Copyright (C) 2021 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * 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.acm.runtime.supervision;
+
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.UUID;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.Response.Status;
+import lombok.AllArgsConstructor;
+import org.apache.commons.collections4.CollectionUtils;
+import org.onap.policy.clamp.acm.runtime.monitoring.MonitoringProvider;
+import org.onap.policy.clamp.acm.runtime.supervision.comm.AutomationCompositionStateChangePublisher;
+import org.onap.policy.clamp.acm.runtime.supervision.comm.AutomationCompositionUpdatePublisher;
+import org.onap.policy.clamp.acm.runtime.supervision.comm.ParticipantDeregisterAckPublisher;
+import org.onap.policy.clamp.acm.runtime.supervision.comm.ParticipantRegisterAckPublisher;
+import org.onap.policy.clamp.acm.runtime.supervision.comm.ParticipantUpdatePublisher;
+import org.onap.policy.clamp.common.acm.exception.AutomationCompositionException;
+import org.onap.policy.clamp.models.acm.concepts.AutomationComposition;
+import org.onap.policy.clamp.models.acm.concepts.AutomationCompositionElementAck;
+import org.onap.policy.clamp.models.acm.concepts.AutomationCompositionInfo;
+import org.onap.policy.clamp.models.acm.concepts.AutomationCompositionState;
+import org.onap.policy.clamp.models.acm.concepts.Participant;
+import org.onap.policy.clamp.models.acm.concepts.ParticipantHealthStatus;
+import org.onap.policy.clamp.models.acm.concepts.ParticipantState;
+import org.onap.policy.clamp.models.acm.concepts.ParticipantUtils;
+import org.onap.policy.clamp.models.acm.messages.dmaap.participant.AutomationCompositionAck;
+import org.onap.policy.clamp.models.acm.messages.dmaap.participant.ParticipantDeregister;
+import org.onap.policy.clamp.models.acm.messages.dmaap.participant.ParticipantMessage;
+import org.onap.policy.clamp.models.acm.messages.dmaap.participant.ParticipantRegister;
+import org.onap.policy.clamp.models.acm.messages.dmaap.participant.ParticipantStatus;
+import org.onap.policy.clamp.models.acm.messages.dmaap.participant.ParticipantUpdateAck;
+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.persistence.provider.ServiceTemplateProvider;
+import org.onap.policy.models.base.PfModelException;
+import org.onap.policy.models.base.PfModelRuntimeException;
+import org.onap.policy.models.tosca.authorative.concepts.ToscaConceptIdentifier;
+import org.onap.policy.models.tosca.authorative.concepts.ToscaServiceTemplate;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.stereotype.Component;
+
+/**
+ * This class handles supervision of automation composition instances, so only one object of this type should be built
+ * at a time.
+ *
+ * <p/>
+ * It is effectively a singleton that is started at system start.
+ */
+@Component
+@AllArgsConstructor
+public class SupervisionHandler {
+ private static final Logger LOGGER = LoggerFactory.getLogger(SupervisionHandler.class);
+
+ private static final String AUTOMATION_COMPOSITION_CANNOT_TRANSITION_FROM_STATE =
+ "Automation composition can't transition from state ";
+ private static final String AUTOMATION_COMPOSITION_IS_ALREADY_IN_STATE =
+ "Automation composition is already in state ";
+ private static final String TO_STATE = " to state ";
+ private static final String AND_TRANSITIONING_TO_STATE = " and transitioning to state ";
+
+ private final AutomationCompositionProvider automationCompositionProvider;
+ private final ParticipantProvider participantProvider;
+ private final MonitoringProvider monitoringProvider;
+ private final ServiceTemplateProvider serviceTemplateProvider;
+
+ // Publishers for participant communication
+ private final AutomationCompositionUpdatePublisher automationCompositionUpdatePublisher;
+ private final AutomationCompositionStateChangePublisher automationCompositionStateChangePublisher;
+ private final ParticipantRegisterAckPublisher participantRegisterAckPublisher;
+ private final ParticipantDeregisterAckPublisher participantDeregisterAckPublisher;
+ private final ParticipantUpdatePublisher participantUpdatePublisher;
+
+ /**
+ * Supervision trigger called when a command is issued on automation compositions.
+ *
+ * <p/>
+ * Causes supervision to start or continue supervision on the automation compositions in question.
+ *
+ * @param automationCompositionIdentifierList the automation compositions for which the supervision command has been
+ * issued
+ * @throws AutomationCompositionException on supervision triggering exceptions
+ */
+ public void triggerAutomationCompositionSupervision(
+ List<ToscaConceptIdentifier> automationCompositionIdentifierList) throws AutomationCompositionException {
+
+ LOGGER.debug("triggering automation composition supervision on automation compositions {}",
+ automationCompositionIdentifierList);
+
+ if (CollectionUtils.isEmpty(automationCompositionIdentifierList)) {
+ // This is just to force throwing of the exception in certain circumstances.
+ exceptionOccured(Response.Status.NOT_ACCEPTABLE,
+ "The list of automation compositions for supervision is empty");
+ }
+
+ for (ToscaConceptIdentifier automationCompositionId : automationCompositionIdentifierList) {
+ try {
+ var automationComposition =
+ automationCompositionProvider.getAutomationComposition(automationCompositionId);
+
+ superviseAutomationComposition(automationComposition);
+
+ automationCompositionProvider.saveAutomationComposition(automationComposition);
+ } catch (PfModelException pfme) {
+ throw new AutomationCompositionException(pfme.getErrorResponse().getResponseCode(), pfme.getMessage(),
+ pfme);
+ }
+ }
+ }
+
+ /**
+ * Handle a ParticipantStatus message from a participant.
+ *
+ * @param participantStatusMessage the ParticipantStatus message received from a participant
+ */
+ @MessageIntercept
+ public void handleParticipantMessage(ParticipantStatus participantStatusMessage) {
+ LOGGER.debug("Participant Status received {}", participantStatusMessage);
+ try {
+ superviseParticipant(participantStatusMessage);
+ } catch (PfModelException | AutomationCompositionException svExc) {
+ LOGGER.warn("error supervising participant {}", participantStatusMessage.getParticipantId(), svExc);
+ return;
+ }
+
+ try {
+ superviseAutomationCompositions(participantStatusMessage);
+ } catch (PfModelException | AutomationCompositionException svExc) {
+ LOGGER.warn("error supervising participant {}", participantStatusMessage.getParticipantId(), svExc);
+ }
+ }
+
+ /**
+ * Handle a ParticipantRegister message from a participant.
+ *
+ * @param participantRegisterMessage the ParticipantRegister message received from a participant
+ */
+ @MessageIntercept
+ public boolean handleParticipantMessage(ParticipantRegister participantRegisterMessage) {
+ LOGGER.debug("Participant Register received {}", participantRegisterMessage);
+ try {
+ checkParticipant(participantRegisterMessage, ParticipantState.UNKNOWN, ParticipantHealthStatus.UNKNOWN);
+ } catch (PfModelException | AutomationCompositionException svExc) {
+ LOGGER.warn("error saving participant {}", participantRegisterMessage.getParticipantId(), svExc);
+ }
+
+ var isCommissioning = participantUpdatePublisher.sendCommissioning(null, null,
+ participantRegisterMessage.getParticipantId(), participantRegisterMessage.getParticipantType());
+
+ participantRegisterAckPublisher.send(participantRegisterMessage.getMessageId(),
+ participantRegisterMessage.getParticipantId(), participantRegisterMessage.getParticipantType());
+ return isCommissioning;
+ }
+
+ /**
+ * Handle a ParticipantDeregister message from a participant.
+ *
+ * @param participantDeregisterMessage the ParticipantDeregister message received from a participant
+ */
+ @MessageIntercept
+ public void handleParticipantMessage(ParticipantDeregister participantDeregisterMessage) {
+ LOGGER.debug("Participant Deregister received {}", participantDeregisterMessage);
+ try {
+ var participantOpt =
+ participantProvider.findParticipant(participantDeregisterMessage.getParticipantId().getName(),
+ participantDeregisterMessage.getParticipantId().getVersion());
+
+ if (participantOpt.isPresent()) {
+ var participant = participantOpt.get();
+ participant.setParticipantState(ParticipantState.TERMINATED);
+ participant.setHealthStatus(ParticipantHealthStatus.OFF_LINE);
+ participantProvider.saveParticipant(participant);
+ }
+ } catch (PfModelException pfme) {
+ LOGGER.warn("Model exception occured with participant id {}",
+ participantDeregisterMessage.getParticipantId());
+ }
+
+ participantDeregisterAckPublisher.send(participantDeregisterMessage.getMessageId());
+ }
+
+ /**
+ * Handle a ParticipantUpdateAck message from a participant.
+ *
+ * @param participantUpdateAckMessage the ParticipantUpdateAck message received from a participant
+ */
+ @MessageIntercept
+ public void handleParticipantMessage(ParticipantUpdateAck participantUpdateAckMessage) {
+ LOGGER.debug("Participant Update Ack received {}", participantUpdateAckMessage);
+ try {
+ var participantOpt =
+ participantProvider.findParticipant(participantUpdateAckMessage.getParticipantId().getName(),
+ participantUpdateAckMessage.getParticipantId().getVersion());
+
+ if (participantOpt.isPresent()) {
+ var participant = participantOpt.get();
+ participant.setParticipantState(participantUpdateAckMessage.getState());
+ participantProvider.saveParticipant(participant);
+ } else {
+ LOGGER.warn("Participant not found in database {}", participantUpdateAckMessage.getParticipantId());
+ }
+ } catch (PfModelException pfme) {
+ LOGGER.warn("Model exception occured with participant id {}",
+ participantUpdateAckMessage.getParticipantId());
+ }
+ }
+
+ /**
+ * Send commissioning update message to dmaap.
+ *
+ * @param name the ToscaServiceTemplate name
+ * @param version the ToscaServiceTemplate version
+ */
+ public void handleSendCommissionMessage(String name, String version) {
+ LOGGER.debug("Participant update message with serviveTemplate {} {} being sent to all participants", name,
+ version);
+ participantUpdatePublisher.sendComissioningBroadcast(name, version);
+ }
+
+ /**
+ * Send decommissioning update message to dmaap.
+ *
+ */
+ public void handleSendDeCommissionMessage() {
+ LOGGER.debug("Participant update message being sent");
+ participantUpdatePublisher.sendDecomisioning();
+ }
+
+ /**
+ * Handle a AutomationComposition update acknowledge message from a participant.
+ *
+ * @param automationCompositionAckMessage the AutomationCompositionAck message received from a participant
+ */
+ @MessageIntercept
+ public void handleAutomationCompositionUpdateAckMessage(AutomationCompositionAck automationCompositionAckMessage) {
+ LOGGER.debug("AutomationComposition Update Ack message received {}", automationCompositionAckMessage);
+ setAcElementStateInDb(automationCompositionAckMessage);
+ }
+
+ /**
+ * Handle a AutomationComposition statechange acknowledge message from a participant.
+ *
+ * @param automationCompositionAckMessage the AutomationCompositionAck message received from a participant
+ */
+ @MessageIntercept
+ public void handleAutomationCompositionStateChangeAckMessage(
+ AutomationCompositionAck automationCompositionAckMessage) {
+ LOGGER.debug("AutomationComposition StateChange Ack message received {}", automationCompositionAckMessage);
+ setAcElementStateInDb(automationCompositionAckMessage);
+ }
+
+ private void setAcElementStateInDb(AutomationCompositionAck automationCompositionAckMessage) {
+ if (automationCompositionAckMessage.getAutomationCompositionResultMap() != null) {
+ try {
+ var automationComposition = automationCompositionProvider
+ .getAutomationComposition(automationCompositionAckMessage.getAutomationCompositionId());
+ if (automationComposition != null) {
+ var updated = updateState(automationComposition,
+ automationCompositionAckMessage.getAutomationCompositionResultMap().entrySet());
+ updated |= setPrimed(automationComposition);
+ if (updated) {
+ automationCompositionProvider.saveAutomationComposition(automationComposition);
+ }
+ } else {
+ LOGGER.warn("AutomationComposition not found in database {}",
+ automationCompositionAckMessage.getAutomationCompositionId());
+ }
+ } catch (PfModelException pfme) {
+ LOGGER.warn("Model exception occured with AutomationComposition Id {}",
+ automationCompositionAckMessage.getAutomationCompositionId());
+ }
+ }
+ }
+
+ private boolean updateState(AutomationComposition automationComposition,
+ Set<Map.Entry<UUID, AutomationCompositionElementAck>> automationCompositionResultSet) {
+ var updated = false;
+ for (var acElementAck : automationCompositionResultSet) {
+ var element = automationComposition.getElements().get(acElementAck.getKey());
+ if (element != null) {
+ element.setState(acElementAck.getValue().getState());
+ updated = true;
+ }
+ }
+ return updated;
+ }
+
+ private boolean setPrimed(AutomationComposition automationComposition) {
+ var acElements = automationComposition.getElements().values();
+ if (acElements != null) {
+ Boolean primedFlag = true;
+ var checkOpt = automationComposition.getElements().values().stream()
+ .filter(acElement -> (!acElement.getState().equals(AutomationCompositionState.PASSIVE)
+ || !acElement.getState().equals(AutomationCompositionState.RUNNING)))
+ .findAny();
+ if (checkOpt.isEmpty()) {
+ primedFlag = false;
+ }
+ automationComposition.setPrimed(primedFlag);
+ return true;
+ }
+
+ return false;
+ }
+
+ /**
+ * Supervise a automation composition, performing whatever actions need to be performed on the automation
+ * composition.
+ *
+ * @param automationComposition the automation composition to supervises
+ * @throws AutomationCompositionException on supervision errors
+ */
+ private void superviseAutomationComposition(AutomationComposition automationComposition)
+ throws AutomationCompositionException {
+ switch (automationComposition.getOrderedState()) {
+ case UNINITIALISED:
+ superviseAutomationCompositionUninitialization(automationComposition);
+ break;
+
+ case PASSIVE:
+ superviseAutomationCompositionPassivation(automationComposition);
+ break;
+
+ case RUNNING:
+ superviseAutomationCompositionActivation(automationComposition);
+ break;
+
+ default:
+ exceptionOccured(Response.Status.NOT_ACCEPTABLE,
+ "A automation composition cannot be commanded to go into state "
+ + automationComposition.getOrderedState().name());
+ }
+ }
+
+ /**
+ * Supervise a automation composition uninitialisation, performing whatever actions need to be performed on the
+ * automation composition,
+ * automation composition ordered state is UNINITIALIZED.
+ *
+ * @param automationComposition the automation composition to supervises
+ * @throws AutomationCompositionException on supervision errors
+ */
+ private void superviseAutomationCompositionUninitialization(AutomationComposition automationComposition)
+ throws AutomationCompositionException {
+ switch (automationComposition.getState()) {
+ case UNINITIALISED:
+ exceptionOccured(Response.Status.NOT_ACCEPTABLE,
+ AUTOMATION_COMPOSITION_IS_ALREADY_IN_STATE + automationComposition.getState().name());
+ break;
+
+ case UNINITIALISED2PASSIVE:
+ case PASSIVE:
+ automationComposition.setState(AutomationCompositionState.PASSIVE2UNINITIALISED);
+ automationCompositionStateChangePublisher.send(automationComposition,
+ getFirstStartPhase(automationComposition));
+ break;
+
+ case PASSIVE2UNINITIALISED:
+ exceptionOccured(Response.Status.NOT_ACCEPTABLE,
+ AUTOMATION_COMPOSITION_IS_ALREADY_IN_STATE + automationComposition.getState().name()
+ + AND_TRANSITIONING_TO_STATE + automationComposition.getOrderedState());
+ break;
+
+ default:
+ exceptionOccured(Response.Status.NOT_ACCEPTABLE, AUTOMATION_COMPOSITION_CANNOT_TRANSITION_FROM_STATE
+ + automationComposition.getState().name() + TO_STATE + automationComposition.getOrderedState());
+ break;
+ }
+ }
+
+ private void superviseAutomationCompositionPassivation(AutomationComposition automationComposition)
+ throws AutomationCompositionException {
+ switch (automationComposition.getState()) {
+ case PASSIVE:
+ exceptionOccured(Response.Status.NOT_ACCEPTABLE,
+ AUTOMATION_COMPOSITION_IS_ALREADY_IN_STATE + automationComposition.getState().name());
+ break;
+ case UNINITIALISED:
+ automationComposition.setState(AutomationCompositionState.UNINITIALISED2PASSIVE);
+ automationCompositionUpdatePublisher.send(automationComposition);
+ break;
+
+ case UNINITIALISED2PASSIVE:
+ case RUNNING2PASSIVE:
+ exceptionOccured(Response.Status.NOT_ACCEPTABLE,
+ AUTOMATION_COMPOSITION_IS_ALREADY_IN_STATE + automationComposition.getState().name()
+ + AND_TRANSITIONING_TO_STATE + automationComposition.getOrderedState());
+ break;
+
+ case RUNNING:
+ automationComposition.setState(AutomationCompositionState.RUNNING2PASSIVE);
+ automationCompositionStateChangePublisher.send(automationComposition,
+ getFirstStartPhase(automationComposition));
+ break;
+
+ default:
+ exceptionOccured(Response.Status.NOT_ACCEPTABLE, AUTOMATION_COMPOSITION_CANNOT_TRANSITION_FROM_STATE
+ + automationComposition.getState().name() + TO_STATE + automationComposition.getOrderedState());
+ break;
+ }
+ }
+
+ private void superviseAutomationCompositionActivation(AutomationComposition automationComposition)
+ throws AutomationCompositionException {
+ switch (automationComposition.getState()) {
+ case RUNNING:
+ exceptionOccured(Response.Status.NOT_ACCEPTABLE,
+ AUTOMATION_COMPOSITION_IS_ALREADY_IN_STATE + automationComposition.getState().name());
+ break;
+
+ case PASSIVE2RUNNING:
+ exceptionOccured(Response.Status.NOT_ACCEPTABLE,
+ AUTOMATION_COMPOSITION_IS_ALREADY_IN_STATE + automationComposition.getState().name()
+ + AND_TRANSITIONING_TO_STATE + automationComposition.getOrderedState());
+ break;
+
+ case PASSIVE:
+ automationComposition.setState(AutomationCompositionState.PASSIVE2RUNNING);
+ automationCompositionStateChangePublisher.send(automationComposition,
+ getFirstStartPhase(automationComposition));
+ break;
+
+ default:
+ exceptionOccured(Response.Status.NOT_ACCEPTABLE, AUTOMATION_COMPOSITION_CANNOT_TRANSITION_FROM_STATE
+ + automationComposition.getState().name() + TO_STATE + automationComposition.getOrderedState());
+ break;
+ }
+ }
+
+ private int getFirstStartPhase(AutomationComposition automationComposition) {
+ ToscaServiceTemplate toscaServiceTemplate = null;
+ try {
+ toscaServiceTemplate = serviceTemplateProvider.getAllServiceTemplates().get(0);
+ } catch (PfModelException e) {
+ throw new PfModelRuntimeException(Status.BAD_REQUEST, "Canont load ToscaServiceTemplate from DB", e);
+ }
+ return ParticipantUtils.getFirstStartPhase(automationComposition, toscaServiceTemplate);
+ }
+
+ private void checkParticipant(ParticipantMessage participantMessage, ParticipantState participantState,
+ ParticipantHealthStatus healthStatus) throws AutomationCompositionException, PfModelException {
+ if (participantMessage.getParticipantId() == null) {
+ exceptionOccured(Response.Status.NOT_FOUND, "Participant ID on PARTICIPANT_STATUS message is null");
+ }
+ var participantOpt = participantProvider.findParticipant(participantMessage.getParticipantId().getName(),
+ participantMessage.getParticipantId().getVersion());
+
+ if (participantOpt.isEmpty()) {
+ var participant = new Participant();
+ participant.setName(participantMessage.getParticipantId().getName());
+ participant.setVersion(participantMessage.getParticipantId().getVersion());
+ participant.setDefinition(participantMessage.getParticipantId());
+ participant.setParticipantType(participantMessage.getParticipantType());
+ participant.setParticipantState(participantState);
+ participant.setHealthStatus(healthStatus);
+
+ participantProvider.saveParticipant(participant);
+ } else {
+ var participant = participantOpt.get();
+ participant.setParticipantState(participantState);
+ participant.setHealthStatus(healthStatus);
+
+ participantProvider.saveParticipant(participant);
+ }
+ }
+
+ private void superviseParticipant(ParticipantStatus participantStatusMessage)
+ throws PfModelException, AutomationCompositionException {
+
+ checkParticipant(participantStatusMessage, participantStatusMessage.getState(),
+ participantStatusMessage.getHealthStatus());
+
+ monitoringProvider.createParticipantStatistics(List.of(participantStatusMessage.getParticipantStatistics()));
+ }
+
+ private void superviseAutomationCompositions(ParticipantStatus participantStatusMessage)
+ throws PfModelException, AutomationCompositionException {
+ if (participantStatusMessage.getAutomationCompositionInfoList() != null) {
+ for (AutomationCompositionInfo acEntry : participantStatusMessage.getAutomationCompositionInfoList()) {
+ var dbAutomationComposition = automationCompositionProvider
+ .getAutomationComposition(new ToscaConceptIdentifier(acEntry.getAutomationCompositionId()));
+ if (dbAutomationComposition == null) {
+ exceptionOccured(Response.Status.NOT_FOUND,
+ "PARTICIPANT_STATUS automation composition not found in database: "
+ + acEntry.getAutomationCompositionId());
+ }
+ dbAutomationComposition.setState(acEntry.getState());
+ monitoringProvider.createAcElementStatistics(
+ acEntry.getAutomationCompositionStatistics().getAcElementStatisticsList().getAcElementStatistics());
+ }
+ }
+ }
+
+ private void exceptionOccured(Response.Status status, String reason) throws AutomationCompositionException {
+ throw new AutomationCompositionException(status, reason);
+ }
+}
diff --git a/runtime-acm/src/main/java/org/onap/policy/clamp/acm/runtime/supervision/SupervisionScanner.java b/runtime-acm/src/main/java/org/onap/policy/clamp/acm/runtime/supervision/SupervisionScanner.java
new file mode 100644
index 000000000..ce7195d93
--- /dev/null
+++ b/runtime-acm/src/main/java/org/onap/policy/clamp/acm/runtime/supervision/SupervisionScanner.java
@@ -0,0 +1,307 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * Copyright (C) 2021 Nordix Foundation.
+ * ================================================================================
+ * Modifications Copyright (C) 2021 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * 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.acm.runtime.supervision;
+
+import java.util.HashMap;
+import java.util.Map;
+import org.apache.commons.lang3.tuple.Pair;
+import org.onap.policy.clamp.acm.runtime.main.parameters.AcRuntimeParameterGroup;
+import org.onap.policy.clamp.acm.runtime.supervision.comm.AutomationCompositionStateChangePublisher;
+import org.onap.policy.clamp.acm.runtime.supervision.comm.AutomationCompositionUpdatePublisher;
+import org.onap.policy.clamp.acm.runtime.supervision.comm.ParticipantStatusReqPublisher;
+import org.onap.policy.clamp.acm.runtime.supervision.comm.ParticipantUpdatePublisher;
+import org.onap.policy.clamp.models.acm.concepts.AutomationComposition;
+import org.onap.policy.clamp.models.acm.concepts.AutomationCompositionElement;
+import org.onap.policy.clamp.models.acm.concepts.AutomationCompositionState;
+import org.onap.policy.clamp.models.acm.concepts.Participant;
+import org.onap.policy.clamp.models.acm.concepts.ParticipantHealthStatus;
+import org.onap.policy.clamp.models.acm.concepts.ParticipantUtils;
+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.persistence.provider.ServiceTemplateProvider;
+import org.onap.policy.models.base.PfModelException;
+import org.onap.policy.models.tosca.authorative.concepts.ToscaConceptIdentifier;
+import org.onap.policy.models.tosca.authorative.concepts.ToscaNodeTemplate;
+import org.onap.policy.models.tosca.authorative.concepts.ToscaServiceTemplate;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.stereotype.Component;
+
+/**
+ * This class is used to scan the automation compositions in the database and check if they are in the correct state.
+ */
+@Component
+public class SupervisionScanner {
+ private static final Logger LOGGER = LoggerFactory.getLogger(SupervisionScanner.class);
+
+ private final HandleCounter<ToscaConceptIdentifier> automationCompositionCounter = new HandleCounter<>();
+ private final HandleCounter<ToscaConceptIdentifier> participantStatusCounter = new HandleCounter<>();
+ private final HandleCounter<Pair<ToscaConceptIdentifier, ToscaConceptIdentifier>> participantUpdateCounter =
+ new HandleCounter<>();
+
+ private final Map<ToscaConceptIdentifier, Integer> phaseMap = new HashMap<>();
+
+ private final AutomationCompositionProvider automationCompositionProvider;
+ private final ServiceTemplateProvider serviceTemplateProvider;
+ private final AutomationCompositionStateChangePublisher automationCompositionStateChangePublisher;
+ private final AutomationCompositionUpdatePublisher automationCompositionUpdatePublisher;
+ private final ParticipantProvider participantProvider;
+ private final ParticipantStatusReqPublisher participantStatusReqPublisher;
+ private final ParticipantUpdatePublisher participantUpdatePublisher;
+
+ /**
+ * Constructor for instantiating SupervisionScanner.
+ *
+ * @param automationCompositionProvider the provider to use to read automation compositions from the database
+ * @param serviceTemplateProvider the Policy Models Provider
+ * @param automationCompositionStateChangePublisher the AutomationComposition StateChange Publisher
+ * @param automationCompositionUpdatePublisher the AutomationCompositionUpdate Publisher
+ * @param participantProvider the Participant Provider
+ * @param participantStatusReqPublisher the Participant StatusReq Publisher
+ * @param participantUpdatePublisher the Participant Update Publisher
+ * @param acRuntimeParameterGroup the parameters for the automation composition runtime
+ */
+ public SupervisionScanner(final AutomationCompositionProvider automationCompositionProvider,
+ ServiceTemplateProvider serviceTemplateProvider,
+ final AutomationCompositionStateChangePublisher automationCompositionStateChangePublisher,
+ AutomationCompositionUpdatePublisher automationCompositionUpdatePublisher,
+ ParticipantProvider participantProvider, ParticipantStatusReqPublisher participantStatusReqPublisher,
+ ParticipantUpdatePublisher participantUpdatePublisher, final AcRuntimeParameterGroup acRuntimeParameterGroup) {
+ this.automationCompositionProvider = automationCompositionProvider;
+ this.serviceTemplateProvider = serviceTemplateProvider;
+ this.automationCompositionStateChangePublisher = automationCompositionStateChangePublisher;
+ this.automationCompositionUpdatePublisher = automationCompositionUpdatePublisher;
+ this.participantProvider = participantProvider;
+ this.participantStatusReqPublisher = participantStatusReqPublisher;
+ this.participantUpdatePublisher = participantUpdatePublisher;
+
+ automationCompositionCounter.setMaxRetryCount(
+ acRuntimeParameterGroup.getParticipantParameters().getUpdateParameters().getMaxRetryCount());
+ automationCompositionCounter
+ .setMaxWaitMs(acRuntimeParameterGroup.getParticipantParameters().getMaxStatusWaitMs());
+
+ participantUpdateCounter.setMaxRetryCount(
+ acRuntimeParameterGroup.getParticipantParameters().getUpdateParameters().getMaxRetryCount());
+ participantUpdateCounter
+ .setMaxWaitMs(acRuntimeParameterGroup.getParticipantParameters().getUpdateParameters().getMaxWaitMs());
+
+ participantStatusCounter.setMaxRetryCount(
+ acRuntimeParameterGroup.getParticipantParameters().getUpdateParameters().getMaxRetryCount());
+ participantStatusCounter.setMaxWaitMs(acRuntimeParameterGroup.getParticipantParameters().getMaxStatusWaitMs());
+ }
+
+ /**
+ * Run Scanning.
+ *
+ * @param counterCheck if true activate counter and retry
+ */
+ public void run(boolean counterCheck) {
+ LOGGER.debug("Scanning automation compositions in the database . . .");
+
+ if (counterCheck) {
+ try {
+ for (var participant : participantProvider.getParticipants()) {
+ scanParticipantStatus(participant);
+ }
+ } catch (PfModelException pfme) {
+ LOGGER.warn("error reading participant from database", pfme);
+ return;
+ }
+ }
+
+ try {
+ var list = serviceTemplateProvider.getAllServiceTemplates();
+ if (list != null && !list.isEmpty()) {
+ ToscaServiceTemplate toscaServiceTemplate = list.get(0);
+
+ for (AutomationComposition automationComposition : automationCompositionProvider
+ .getAutomationCompositions()) {
+ scanAutomationComposition(automationComposition, toscaServiceTemplate, counterCheck);
+ }
+ }
+ } catch (PfModelException pfme) {
+ LOGGER.warn("error reading automation compositions from database", pfme);
+ }
+
+ if (counterCheck) {
+ scanParticipantUpdate();
+ }
+
+ LOGGER.debug("Automation composition scan complete . . .");
+ }
+
+ private void scanParticipantUpdate() {
+ LOGGER.debug("Scanning participants to update . . .");
+
+ for (var id : participantUpdateCounter.keySet()) {
+ if (participantUpdateCounter.isFault(id)) {
+ LOGGER.debug("report Participant Update fault");
+
+ } else if (participantUpdateCounter.getDuration(id) > participantUpdateCounter.getMaxWaitMs()) {
+
+ if (participantUpdateCounter.count(id)) {
+ LOGGER.debug("retry message ParticipantUpdate");
+ participantUpdatePublisher.sendCommissioning(null, null, id.getLeft(), id.getRight());
+ } else {
+ LOGGER.debug("report Participant Update fault");
+ participantUpdateCounter.setFault(id);
+ }
+ }
+ }
+
+ LOGGER.debug("Participants to update scan complete . . .");
+ }
+
+ private void scanParticipantStatus(Participant participant) throws PfModelException {
+ ToscaConceptIdentifier id = participant.getKey().asIdentifier();
+ if (participantStatusCounter.isFault(id)) {
+ LOGGER.debug("report Participant fault");
+ return;
+ }
+ if (participantStatusCounter.getDuration(id) > participantStatusCounter.getMaxWaitMs()) {
+ if (participantStatusCounter.count(id)) {
+ LOGGER.debug("retry message ParticipantStatusReq");
+ participantStatusReqPublisher.send(id);
+ participant.setHealthStatus(ParticipantHealthStatus.NOT_HEALTHY);
+ } else {
+ LOGGER.debug("report Participant fault");
+ participantStatusCounter.setFault(id);
+ participant.setHealthStatus(ParticipantHealthStatus.OFF_LINE);
+ }
+ participantProvider.saveParticipant(participant);
+ }
+ }
+
+ /**
+ * handle participant Status message.
+ */
+ public void handleParticipantStatus(ToscaConceptIdentifier id) {
+ participantStatusCounter.clear(id);
+ }
+
+ public void handleParticipantRegister(Pair<ToscaConceptIdentifier, ToscaConceptIdentifier> id) {
+ participantUpdateCounter.clear(id);
+ }
+
+ public void handleParticipantUpdateAck(Pair<ToscaConceptIdentifier, ToscaConceptIdentifier> id) {
+ participantUpdateCounter.remove(id);
+ }
+
+ private void scanAutomationComposition(final AutomationComposition automationComposition,
+ ToscaServiceTemplate toscaServiceTemplate, boolean counterCheck) throws PfModelException {
+ LOGGER.debug("scanning automation composition {} . . .", automationComposition.getKey().asIdentifier());
+
+ if (automationComposition.getState().equals(automationComposition.getOrderedState().asState())) {
+ LOGGER.debug("automation composition {} scanned, OK", automationComposition.getKey().asIdentifier());
+
+ // Clear missed report counter on automation composition
+ clearFaultAndCounter(automationComposition);
+ return;
+ }
+
+ var completed = true;
+ var minSpNotCompleted = 1000; // min startPhase not completed
+ var maxSpNotCompleted = 0; // max startPhase not completed
+ var defaultMin = 1000; // min startPhase
+ var defaultMax = 0; // max startPhase
+ for (AutomationCompositionElement element : automationComposition.getElements().values()) {
+ ToscaNodeTemplate toscaNodeTemplate = toscaServiceTemplate.getToscaTopologyTemplate().getNodeTemplates()
+ .get(element.getDefinition().getName());
+ int startPhase = ParticipantUtils.findStartPhase(toscaNodeTemplate.getProperties());
+ defaultMin = Math.min(defaultMin, startPhase);
+ defaultMax = Math.max(defaultMax, startPhase);
+ if (!element.getState().equals(element.getOrderedState().asState())) {
+ completed = false;
+ minSpNotCompleted = Math.min(minSpNotCompleted, startPhase);
+ maxSpNotCompleted = Math.max(maxSpNotCompleted, startPhase);
+ }
+ }
+
+ if (completed) {
+ LOGGER.debug("automation composition scan: transition from state {} to {} completed",
+ automationComposition.getState(), automationComposition.getOrderedState());
+
+ automationComposition.setState(automationComposition.getOrderedState().asState());
+ automationCompositionProvider.saveAutomationComposition(automationComposition);
+
+ // Clear missed report counter on automation composition
+ clearFaultAndCounter(automationComposition);
+ } else {
+ LOGGER.debug("automation composition scan: transition from state {} to {} not completed",
+ automationComposition.getState(), automationComposition.getOrderedState());
+
+ var nextSpNotCompleted =
+ AutomationCompositionState.UNINITIALISED2PASSIVE.equals(automationComposition.getState())
+ || AutomationCompositionState.PASSIVE2RUNNING.equals(automationComposition.getState())
+ ? minSpNotCompleted
+ : maxSpNotCompleted;
+
+ var firstStartPhase =
+ AutomationCompositionState.UNINITIALISED2PASSIVE.equals(automationComposition.getState())
+ || AutomationCompositionState.PASSIVE2RUNNING.equals(automationComposition.getState()) ? defaultMin
+ : defaultMax;
+
+ if (nextSpNotCompleted != phaseMap.getOrDefault(automationComposition.getKey().asIdentifier(),
+ firstStartPhase)) {
+ phaseMap.put(automationComposition.getKey().asIdentifier(), nextSpNotCompleted);
+ sendAutomationCompositionMsg(automationComposition, nextSpNotCompleted);
+ } else if (counterCheck) {
+ phaseMap.put(automationComposition.getKey().asIdentifier(), nextSpNotCompleted);
+ handleCounter(automationComposition, nextSpNotCompleted);
+ }
+ }
+ }
+
+ private void clearFaultAndCounter(AutomationComposition automationComposition) {
+ automationCompositionCounter.clear(automationComposition.getKey().asIdentifier());
+ phaseMap.clear();
+ }
+
+ private void handleCounter(AutomationComposition automationComposition, int startPhase) {
+ ToscaConceptIdentifier id = automationComposition.getKey().asIdentifier();
+ if (automationCompositionCounter.isFault(id)) {
+ LOGGER.debug("report AutomationComposition fault");
+ return;
+ }
+
+ if (automationCompositionCounter.getDuration(id) > automationCompositionCounter.getMaxWaitMs()) {
+ if (automationCompositionCounter.count(id)) {
+ phaseMap.put(id, startPhase);
+ sendAutomationCompositionMsg(automationComposition, startPhase);
+ } else {
+ LOGGER.debug("report AutomationComposition fault");
+ automationCompositionCounter.setFault(id);
+ }
+ }
+ }
+
+ private void sendAutomationCompositionMsg(AutomationComposition automationComposition, int startPhase) {
+ if (AutomationCompositionState.UNINITIALISED2PASSIVE.equals(automationComposition.getState())) {
+ LOGGER.debug("retry message AutomationCompositionUpdate");
+ automationCompositionUpdatePublisher.send(automationComposition, startPhase);
+ } else {
+ LOGGER.debug("retry message AutomationCompositionStateChange");
+ automationCompositionStateChangePublisher.send(automationComposition, startPhase);
+ }
+ }
+}
diff --git a/runtime-acm/src/main/java/org/onap/policy/clamp/acm/runtime/supervision/comm/AbstractParticipantAckPublisher.java b/runtime-acm/src/main/java/org/onap/policy/clamp/acm/runtime/supervision/comm/AbstractParticipantAckPublisher.java
new file mode 100644
index 000000000..22284a4eb
--- /dev/null
+++ b/runtime-acm/src/main/java/org/onap/policy/clamp/acm/runtime/supervision/comm/AbstractParticipantAckPublisher.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.acm.runtime.supervision.comm;
+
+import java.util.List;
+import javax.ws.rs.core.Response.Status;
+import org.onap.policy.clamp.acm.runtime.config.messaging.Publisher;
+import org.onap.policy.clamp.common.acm.exception.AutomationCompositionRuntimeException;
+import org.onap.policy.clamp.models.acm.messages.dmaap.participant.ParticipantAckMessage;
+import org.onap.policy.common.endpoints.event.comm.TopicSink;
+import org.onap.policy.common.endpoints.event.comm.client.TopicSinkClient;
+
+public abstract class AbstractParticipantAckPublisher<E extends ParticipantAckMessage> implements Publisher {
+
+ private TopicSinkClient topicSinkClient;
+ private boolean active = false;
+
+ /**
+ * Method to send Participant message to participants on demand.
+ *
+ * @param participantMessage the Participant message
+ */
+ public void send(final E participantMessage) {
+ if (!active) {
+ throw new AutomationCompositionRuntimeException(Status.NOT_ACCEPTABLE, "Not Active!");
+ }
+ topicSinkClient.send(participantMessage);
+ }
+
+
+ @Override
+ public void active(List<TopicSink> topicSinks) {
+ if (topicSinks.size() != 1) {
+ throw new IllegalArgumentException("Topic Sink must be one");
+ }
+ this.topicSinkClient = new TopicSinkClient(topicSinks.get(0));
+ active = true;
+ }
+
+ @Override
+ public void stop() {
+ active = false;
+ }
+}
diff --git a/runtime-acm/src/main/java/org/onap/policy/clamp/acm/runtime/supervision/comm/AbstractParticipantPublisher.java b/runtime-acm/src/main/java/org/onap/policy/clamp/acm/runtime/supervision/comm/AbstractParticipantPublisher.java
new file mode 100644
index 000000000..054eaf7b5
--- /dev/null
+++ b/runtime-acm/src/main/java/org/onap/policy/clamp/acm/runtime/supervision/comm/AbstractParticipantPublisher.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.acm.runtime.supervision.comm;
+
+import java.util.List;
+import javax.ws.rs.core.Response.Status;
+import org.onap.policy.clamp.acm.runtime.config.messaging.Publisher;
+import org.onap.policy.clamp.common.acm.exception.AutomationCompositionRuntimeException;
+import org.onap.policy.clamp.models.acm.messages.dmaap.participant.ParticipantMessage;
+import org.onap.policy.common.endpoints.event.comm.TopicSink;
+import org.onap.policy.common.endpoints.event.comm.client.TopicSinkClient;
+
+public abstract class AbstractParticipantPublisher<E extends ParticipantMessage> implements Publisher {
+
+ private TopicSinkClient topicSinkClient;
+ private boolean active = false;
+
+ /**
+ * Method to send Participant message to participants on demand.
+ *
+ * @param participantMessage the Participant message
+ */
+ public void send(final E participantMessage) {
+ if (!active) {
+ throw new AutomationCompositionRuntimeException(Status.NOT_ACCEPTABLE, "Not Active!");
+ }
+ topicSinkClient.send(participantMessage);
+ }
+
+
+ @Override
+ public void active(List<TopicSink> topicSinks) {
+ if (topicSinks.size() != 1) {
+ throw new IllegalArgumentException("Topic Sink must be one");
+ }
+ this.topicSinkClient = new TopicSinkClient(topicSinks.get(0));
+ active = true;
+ }
+
+ @Override
+ public void stop() {
+ active = false;
+ }
+}
diff --git a/runtime-acm/src/main/java/org/onap/policy/clamp/acm/runtime/supervision/comm/AutomationCompositionStateChangeAckListener.java b/runtime-acm/src/main/java/org/onap/policy/clamp/acm/runtime/supervision/comm/AutomationCompositionStateChangeAckListener.java
new file mode 100644
index 000000000..dd07be680
--- /dev/null
+++ b/runtime-acm/src/main/java/org/onap/policy/clamp/acm/runtime/supervision/comm/AutomationCompositionStateChangeAckListener.java
@@ -0,0 +1,70 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * Copyright (C) 2021 Nordix Foundation.
+ * Modifications Copyright (C) 2021 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * 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.acm.runtime.supervision.comm;
+
+import org.onap.policy.clamp.acm.runtime.config.messaging.Listener;
+import org.onap.policy.clamp.acm.runtime.supervision.SupervisionHandler;
+import org.onap.policy.clamp.models.acm.messages.dmaap.participant.AutomationCompositionAck;
+import org.onap.policy.clamp.models.acm.messages.dmaap.participant.ParticipantMessageType;
+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;
+import org.springframework.stereotype.Component;
+
+/**
+ * Listener for AutomationCompositionStateChangeAck messages sent by participants.
+ */
+@Component
+public class AutomationCompositionStateChangeAckListener extends ScoListener<AutomationCompositionAck>
+ implements Listener<AutomationCompositionAck> {
+ private static final Logger LOGGER = LoggerFactory.getLogger(AutomationCompositionStateChangeAckListener.class);
+
+ private final SupervisionHandler supervisionHandler;
+
+ /**
+ * Constructs the object.
+ */
+ public AutomationCompositionStateChangeAckListener(SupervisionHandler supervisionHandler) {
+ super(AutomationCompositionAck.class);
+ this.supervisionHandler = supervisionHandler;
+ }
+
+ @Override
+ public void onTopicEvent(final CommInfrastructure infra, final String topic, final StandardCoderObject sco,
+ final AutomationCompositionAck automationCompositionStateChangeAckMessage) {
+ LOGGER.debug("AutomationCompositionStateChangeAck received from participant - {}",
+ automationCompositionStateChangeAckMessage);
+ supervisionHandler.handleAutomationCompositionStateChangeAckMessage(automationCompositionStateChangeAckMessage);
+ }
+
+ @Override
+ public ScoListener<AutomationCompositionAck> getScoListener() {
+ return this;
+ }
+
+ @Override
+ public String getType() {
+ return ParticipantMessageType.AUTOMATION_COMPOSITION_STATECHANGE_ACK.name();
+ }
+}
diff --git a/runtime-acm/src/main/java/org/onap/policy/clamp/acm/runtime/supervision/comm/AutomationCompositionStateChangePublisher.java b/runtime-acm/src/main/java/org/onap/policy/clamp/acm/runtime/supervision/comm/AutomationCompositionStateChangePublisher.java
new file mode 100644
index 000000000..4e0d12bf6
--- /dev/null
+++ b/runtime-acm/src/main/java/org/onap/policy/clamp/acm/runtime/supervision/comm/AutomationCompositionStateChangePublisher.java
@@ -0,0 +1,50 @@
+/*-
+ * ============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.acm.runtime.supervision.comm;
+
+import java.util.UUID;
+import org.onap.policy.clamp.models.acm.concepts.AutomationComposition;
+import org.onap.policy.clamp.models.acm.messages.dmaap.participant.AutomationCompositionStateChange;
+import org.springframework.stereotype.Component;
+
+/**
+ * This class is used to send AutomationCompositionStateChangePublisher messages to participants on DMaaP.
+ */
+@Component
+public class AutomationCompositionStateChangePublisher
+ extends AbstractParticipantPublisher<AutomationCompositionStateChange> {
+
+ /**
+ * Send AutomationCompositionStateChange to Participant.
+ *
+ * @param automationComposition the AutomationComposition
+ * @param startPhase the startPhase
+ */
+ public void send(AutomationComposition automationComposition, int startPhase) {
+ var acsc = new AutomationCompositionStateChange();
+ acsc.setAutomationCompositionId(automationComposition.getKey().asIdentifier());
+ acsc.setMessageId(UUID.randomUUID());
+ acsc.setOrderedState(automationComposition.getOrderedState());
+ acsc.setStartPhase(startPhase);
+
+ super.send(acsc);
+ }
+}
diff --git a/runtime-acm/src/main/java/org/onap/policy/clamp/acm/runtime/supervision/comm/AutomationCompositionUpdateAckListener.java b/runtime-acm/src/main/java/org/onap/policy/clamp/acm/runtime/supervision/comm/AutomationCompositionUpdateAckListener.java
new file mode 100644
index 000000000..7a1d5294c
--- /dev/null
+++ b/runtime-acm/src/main/java/org/onap/policy/clamp/acm/runtime/supervision/comm/AutomationCompositionUpdateAckListener.java
@@ -0,0 +1,70 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * Copyright (C) 2021 Nordix Foundation.
+ * Modifications Copyright (C) 2021 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * 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.acm.runtime.supervision.comm;
+
+import org.onap.policy.clamp.acm.runtime.config.messaging.Listener;
+import org.onap.policy.clamp.acm.runtime.supervision.SupervisionHandler;
+import org.onap.policy.clamp.models.acm.messages.dmaap.participant.AutomationCompositionAck;
+import org.onap.policy.clamp.models.acm.messages.dmaap.participant.ParticipantMessageType;
+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;
+import org.springframework.stereotype.Component;
+
+/**
+ * Listener for AutomationCompositionUpdateAck messages sent by participants.
+ */
+@Component
+public class AutomationCompositionUpdateAckListener extends ScoListener<AutomationCompositionAck>
+ implements Listener<AutomationCompositionAck> {
+ private static final Logger LOGGER = LoggerFactory.getLogger(AutomationCompositionUpdateAckListener.class);
+
+ private final SupervisionHandler supervisionHandler;
+
+ /**
+ * Constructs the object.
+ */
+ public AutomationCompositionUpdateAckListener(SupervisionHandler supervisionHandler) {
+ super(AutomationCompositionAck.class);
+ this.supervisionHandler = supervisionHandler;
+ }
+
+ @Override
+ public void onTopicEvent(final CommInfrastructure infra, final String topic, final StandardCoderObject sco,
+ final AutomationCompositionAck automationCompositionUpdateAckMessage) {
+ LOGGER.debug("AutomationCompositionUpdateAck message received from participant - {}",
+ automationCompositionUpdateAckMessage);
+ supervisionHandler.handleAutomationCompositionUpdateAckMessage(automationCompositionUpdateAckMessage);
+ }
+
+ @Override
+ public ScoListener<AutomationCompositionAck> getScoListener() {
+ return this;
+ }
+
+ @Override
+ public String getType() {
+ return ParticipantMessageType.AUTOMATION_COMPOSITION_UPDATE_ACK.name();
+ }
+}
diff --git a/runtime-acm/src/main/java/org/onap/policy/clamp/acm/runtime/supervision/comm/AutomationCompositionUpdatePublisher.java b/runtime-acm/src/main/java/org/onap/policy/clamp/acm/runtime/supervision/comm/AutomationCompositionUpdatePublisher.java
new file mode 100644
index 000000000..ac5a998b4
--- /dev/null
+++ b/runtime-acm/src/main/java/org/onap/policy/clamp/acm/runtime/supervision/comm/AutomationCompositionUpdatePublisher.java
@@ -0,0 +1,91 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * Copyright (C) 2021 Nordix Foundation.
+ * ================================================================================
+ * Modifications Copyright (C) 2021 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * 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.acm.runtime.supervision.comm;
+
+import java.time.Instant;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.UUID;
+import lombok.AllArgsConstructor;
+import org.onap.policy.clamp.models.acm.concepts.AutomationComposition;
+import org.onap.policy.clamp.models.acm.concepts.AutomationCompositionElement;
+import org.onap.policy.clamp.models.acm.concepts.ParticipantUpdates;
+import org.onap.policy.clamp.models.acm.messages.dmaap.participant.AutomationCompositionUpdate;
+import org.onap.policy.clamp.models.acm.persistence.provider.ServiceTemplateProvider;
+import org.onap.policy.clamp.models.acm.utils.AcmUtils;
+import org.onap.policy.models.base.PfModelException;
+import org.onap.policy.models.tosca.authorative.concepts.ToscaServiceTemplate;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.stereotype.Component;
+
+/**
+ * This class is used to send AutomationCompositionUpdate messages to participants on DMaaP.
+ */
+@Component
+@AllArgsConstructor
+public class AutomationCompositionUpdatePublisher extends AbstractParticipantPublisher<AutomationCompositionUpdate> {
+
+ private static final Logger LOGGER = LoggerFactory.getLogger(AutomationCompositionUpdatePublisher.class);
+ private final ServiceTemplateProvider serviceTemplateProvider;
+
+ /**
+ * Send AutomationCompositionUpdate to Participant.
+ *
+ * @param automationComposition the AutomationComposition
+ */
+ public void send(AutomationComposition automationComposition) {
+ send(automationComposition, 0);
+ }
+
+ /**
+ * Send AutomationCompositionUpdate to Participant.
+ *
+ * @param automationComposition the AutomationComposition
+ * @param startPhase the Start Phase
+ */
+ public void send(AutomationComposition automationComposition, int startPhase) {
+ var automationCompositionUpdateMsg = new AutomationCompositionUpdate();
+ automationCompositionUpdateMsg.setStartPhase(startPhase);
+ automationCompositionUpdateMsg.setAutomationCompositionId(automationComposition.getKey().asIdentifier());
+ automationCompositionUpdateMsg.setMessageId(UUID.randomUUID());
+ automationCompositionUpdateMsg.setTimestamp(Instant.now());
+ ToscaServiceTemplate toscaServiceTemplate;
+ try {
+ toscaServiceTemplate = serviceTemplateProvider.getAllServiceTemplates().get(0);
+ } catch (PfModelException pfme) {
+ LOGGER.warn("Get of tosca service template failed, cannot send participantupdate", pfme);
+ return;
+ }
+
+ List<ParticipantUpdates> participantUpdates = new ArrayList<>();
+ for (AutomationCompositionElement element : automationComposition.getElements().values()) {
+ AcmUtils.setServiceTemplatePolicyInfo(element, toscaServiceTemplate);
+ AcmUtils.prepareParticipantUpdate(element, participantUpdates);
+ }
+ automationCompositionUpdateMsg.setParticipantUpdatesList(participantUpdates);
+
+ LOGGER.debug("AutomationCompositionUpdate message sent {}", automationCompositionUpdateMsg);
+ super.send(automationCompositionUpdateMsg);
+ }
+}
diff --git a/runtime-acm/src/main/java/org/onap/policy/clamp/acm/runtime/supervision/comm/ParticipantDeregisterAckPublisher.java b/runtime-acm/src/main/java/org/onap/policy/clamp/acm/runtime/supervision/comm/ParticipantDeregisterAckPublisher.java
new file mode 100644
index 000000000..34881b557
--- /dev/null
+++ b/runtime-acm/src/main/java/org/onap/policy/clamp/acm/runtime/supervision/comm/ParticipantDeregisterAckPublisher.java
@@ -0,0 +1,45 @@
+/*-
+ * ============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.acm.runtime.supervision.comm;
+
+import java.util.UUID;
+import org.onap.policy.clamp.models.acm.messages.dmaap.participant.ParticipantDeregisterAck;
+import org.springframework.stereotype.Component;
+
+/**
+ * This class is used to send ParticipantDeregisterAck messages to participants on DMaaP.
+ */
+@Component
+public class ParticipantDeregisterAckPublisher extends AbstractParticipantAckPublisher<ParticipantDeregisterAck> {
+
+ /**
+ * Sent ParticipantDeregisterAck to Participant.
+ *
+ * @param responseTo the original request id in the request.
+ */
+ public void send(UUID responseTo) {
+ var message = new ParticipantDeregisterAck();
+ message.setResponseTo(responseTo);
+ message.setMessage("Participant Deregister Ack");
+ message.setResult(true);
+ super.send(message);
+ }
+}
diff --git a/runtime-acm/src/main/java/org/onap/policy/clamp/acm/runtime/supervision/comm/ParticipantDeregisterListener.java b/runtime-acm/src/main/java/org/onap/policy/clamp/acm/runtime/supervision/comm/ParticipantDeregisterListener.java
new file mode 100644
index 000000000..eec21235f
--- /dev/null
+++ b/runtime-acm/src/main/java/org/onap/policy/clamp/acm/runtime/supervision/comm/ParticipantDeregisterListener.java
@@ -0,0 +1,69 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * Copyright (C) 2021 Nordix Foundation.
+ * Modifications Copyright (C) 2021 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * 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.acm.runtime.supervision.comm;
+
+import org.onap.policy.clamp.acm.runtime.config.messaging.Listener;
+import org.onap.policy.clamp.acm.runtime.supervision.SupervisionHandler;
+import org.onap.policy.clamp.models.acm.messages.dmaap.participant.ParticipantDeregister;
+import org.onap.policy.clamp.models.acm.messages.dmaap.participant.ParticipantMessageType;
+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;
+import org.springframework.stereotype.Component;
+
+/**
+ * Listener for ParticipantDeregister messages sent by participants.
+ */
+@Component
+public class ParticipantDeregisterListener extends ScoListener<ParticipantDeregister>
+ implements Listener<ParticipantDeregister> {
+ private static final Logger LOGGER = LoggerFactory.getLogger(ParticipantDeregisterListener.class);
+
+ private final SupervisionHandler supervisionHandler;
+
+ /**
+ * Constructs the object.
+ */
+ public ParticipantDeregisterListener(SupervisionHandler supervisionHandler) {
+ super(ParticipantDeregister.class);
+ this.supervisionHandler = supervisionHandler;
+ }
+
+ @Override
+ public void onTopicEvent(final CommInfrastructure infra, final String topic, final StandardCoderObject sco,
+ final ParticipantDeregister participantDeregisterMessage) {
+ LOGGER.debug("ParticipantDeregister message received from participant - {}", participantDeregisterMessage);
+ supervisionHandler.handleParticipantMessage(participantDeregisterMessage);
+ }
+
+ @Override
+ public String getType() {
+ return ParticipantMessageType.PARTICIPANT_DEREGISTER.name();
+ }
+
+ @Override
+ public ScoListener<ParticipantDeregister> getScoListener() {
+ return this;
+ }
+}
diff --git a/runtime-acm/src/main/java/org/onap/policy/clamp/acm/runtime/supervision/comm/ParticipantRegisterAckPublisher.java b/runtime-acm/src/main/java/org/onap/policy/clamp/acm/runtime/supervision/comm/ParticipantRegisterAckPublisher.java
new file mode 100644
index 000000000..8344837c1
--- /dev/null
+++ b/runtime-acm/src/main/java/org/onap/policy/clamp/acm/runtime/supervision/comm/ParticipantRegisterAckPublisher.java
@@ -0,0 +1,50 @@
+/*-
+ * ============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.acm.runtime.supervision.comm;
+
+import java.util.UUID;
+import org.onap.policy.clamp.models.acm.messages.dmaap.participant.ParticipantRegisterAck;
+import org.onap.policy.models.tosca.authorative.concepts.ToscaConceptIdentifier;
+import org.springframework.stereotype.Component;
+
+/**
+ * This class is used to send ParticipantRegisterAck messages to participants on DMaaP.
+ */
+@Component
+public class ParticipantRegisterAckPublisher extends AbstractParticipantAckPublisher<ParticipantRegisterAck> {
+
+ /**
+ * Send ParticipantRegisterAck to Participant.
+ *
+ * @param responseTo the original request id in the request.
+ * @param participantId the participant Id
+ * @param participantType the participant Type
+ */
+ public void send(UUID responseTo, ToscaConceptIdentifier participantId, ToscaConceptIdentifier participantType) {
+ var message = new ParticipantRegisterAck();
+ message.setParticipantId(participantId);
+ message.setParticipantType(participantType);
+ message.setResponseTo(responseTo);
+ message.setMessage("Participant Register Ack");
+ message.setResult(true);
+ super.send(message);
+ }
+}
diff --git a/runtime-acm/src/main/java/org/onap/policy/clamp/acm/runtime/supervision/comm/ParticipantRegisterListener.java b/runtime-acm/src/main/java/org/onap/policy/clamp/acm/runtime/supervision/comm/ParticipantRegisterListener.java
new file mode 100644
index 000000000..852340000
--- /dev/null
+++ b/runtime-acm/src/main/java/org/onap/policy/clamp/acm/runtime/supervision/comm/ParticipantRegisterListener.java
@@ -0,0 +1,69 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * Copyright (C) 2021 Nordix Foundation.
+ * Modifications Copyright (C) 2021 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * 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.acm.runtime.supervision.comm;
+
+import org.onap.policy.clamp.acm.runtime.config.messaging.Listener;
+import org.onap.policy.clamp.acm.runtime.supervision.SupervisionHandler;
+import org.onap.policy.clamp.models.acm.messages.dmaap.participant.ParticipantMessageType;
+import org.onap.policy.clamp.models.acm.messages.dmaap.participant.ParticipantRegister;
+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;
+import org.springframework.stereotype.Component;
+
+/**
+ * Listener for ParticipantRegister messages sent by participants.
+ */
+@Component
+public class ParticipantRegisterListener extends ScoListener<ParticipantRegister>
+ implements Listener<ParticipantRegister> {
+ private static final Logger LOGGER = LoggerFactory.getLogger(ParticipantRegisterListener.class);
+
+ private final SupervisionHandler supervisionHandler;
+
+ /**
+ * Constructs the object.
+ */
+ public ParticipantRegisterListener(SupervisionHandler supervisionHandler) {
+ super(ParticipantRegister.class);
+ this.supervisionHandler = supervisionHandler;
+ }
+
+ @Override
+ public void onTopicEvent(final CommInfrastructure infra, final String topic, final StandardCoderObject sco,
+ final ParticipantRegister participantRegisterMessage) {
+ LOGGER.debug("ParticipantRegister message received from participant - {}", participantRegisterMessage);
+ supervisionHandler.handleParticipantMessage(participantRegisterMessage);
+ }
+
+ @Override
+ public String getType() {
+ return ParticipantMessageType.PARTICIPANT_REGISTER.name();
+ }
+
+ @Override
+ public ScoListener<ParticipantRegister> getScoListener() {
+ return this;
+ }
+}
diff --git a/runtime-acm/src/main/java/org/onap/policy/clamp/acm/runtime/supervision/comm/ParticipantStatusListener.java b/runtime-acm/src/main/java/org/onap/policy/clamp/acm/runtime/supervision/comm/ParticipantStatusListener.java
new file mode 100644
index 000000000..4ae1a1a2d
--- /dev/null
+++ b/runtime-acm/src/main/java/org/onap/policy/clamp/acm/runtime/supervision/comm/ParticipantStatusListener.java
@@ -0,0 +1,68 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * Copyright (C) 2021 Nordix Foundation.
+ * Modifications Copyright (C) 2021 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * 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.acm.runtime.supervision.comm;
+
+import org.onap.policy.clamp.acm.runtime.config.messaging.Listener;
+import org.onap.policy.clamp.acm.runtime.supervision.SupervisionHandler;
+import org.onap.policy.clamp.models.acm.messages.dmaap.participant.ParticipantMessageType;
+import org.onap.policy.clamp.models.acm.messages.dmaap.participant.ParticipantStatus;
+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;
+import org.springframework.stereotype.Component;
+
+/**
+ * Listener for ParticipantStatus messages sent by participants.
+ */
+@Component
+public class ParticipantStatusListener extends ScoListener<ParticipantStatus> implements Listener<ParticipantStatus> {
+ private static final Logger LOGGER = LoggerFactory.getLogger(ParticipantStatusListener.class);
+
+ private final SupervisionHandler supervisionHandler;
+
+ /**
+ * Constructs the object.
+ */
+ public ParticipantStatusListener(SupervisionHandler supervisionHandler) {
+ super(ParticipantStatus.class);
+ this.supervisionHandler = supervisionHandler;
+ }
+
+ @Override
+ public void onTopicEvent(final CommInfrastructure infra, final String topic, final StandardCoderObject sco,
+ final ParticipantStatus participantStatusMessage) {
+ LOGGER.debug("ParticipantStatus message received from participant - {}", participantStatusMessage);
+ supervisionHandler.handleParticipantMessage(participantStatusMessage);
+ }
+
+ @Override
+ public String getType() {
+ return ParticipantMessageType.PARTICIPANT_STATUS.name();
+ }
+
+ @Override
+ public ScoListener<ParticipantStatus> getScoListener() {
+ return this;
+ }
+}
diff --git a/runtime-acm/src/main/java/org/onap/policy/clamp/acm/runtime/supervision/comm/ParticipantStatusReqPublisher.java b/runtime-acm/src/main/java/org/onap/policy/clamp/acm/runtime/supervision/comm/ParticipantStatusReqPublisher.java
new file mode 100644
index 000000000..0de8ff063
--- /dev/null
+++ b/runtime-acm/src/main/java/org/onap/policy/clamp/acm/runtime/supervision/comm/ParticipantStatusReqPublisher.java
@@ -0,0 +1,48 @@
+/*-
+ * ============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.acm.runtime.supervision.comm;
+
+import java.time.Instant;
+import org.onap.policy.clamp.models.acm.messages.dmaap.participant.ParticipantStatusReq;
+import org.onap.policy.models.tosca.authorative.concepts.ToscaConceptIdentifier;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.stereotype.Component;
+
+@Component
+public class ParticipantStatusReqPublisher extends AbstractParticipantPublisher<ParticipantStatusReq> {
+
+ private static final Logger LOGGER = LoggerFactory.getLogger(ParticipantStatusReqPublisher.class);
+
+ /**
+ * Send ParticipantStatusReq to Participant.
+ *
+ * @param participantId the participant Id
+ */
+ public void send(ToscaConceptIdentifier participantId) {
+ ParticipantStatusReq message = new ParticipantStatusReq();
+ message.setParticipantId(participantId);
+ message.setTimestamp(Instant.now());
+
+ LOGGER.debug("Participant StatusReq sent {}", message);
+ super.send(message);
+ }
+}
diff --git a/runtime-acm/src/main/java/org/onap/policy/clamp/acm/runtime/supervision/comm/ParticipantUpdateAckListener.java b/runtime-acm/src/main/java/org/onap/policy/clamp/acm/runtime/supervision/comm/ParticipantUpdateAckListener.java
new file mode 100644
index 000000000..d75de775b
--- /dev/null
+++ b/runtime-acm/src/main/java/org/onap/policy/clamp/acm/runtime/supervision/comm/ParticipantUpdateAckListener.java
@@ -0,0 +1,69 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * Copyright (C) 2021 Nordix Foundation.
+ * Modifications Copyright (C) 2021 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * 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.acm.runtime.supervision.comm;
+
+import org.onap.policy.clamp.acm.runtime.config.messaging.Listener;
+import org.onap.policy.clamp.acm.runtime.supervision.SupervisionHandler;
+import org.onap.policy.clamp.models.acm.messages.dmaap.participant.ParticipantMessageType;
+import org.onap.policy.clamp.models.acm.messages.dmaap.participant.ParticipantUpdateAck;
+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;
+import org.springframework.stereotype.Component;
+
+/**
+ * Listener for ParticipantUpdateAck messages sent by participants.
+ */
+@Component
+public class ParticipantUpdateAckListener extends ScoListener<ParticipantUpdateAck>
+ implements Listener<ParticipantUpdateAck> {
+ private static final Logger LOGGER = LoggerFactory.getLogger(ParticipantUpdateAckListener.class);
+
+ private final SupervisionHandler supervisionHandler;
+
+ /**
+ * Constructs the object.
+ */
+ public ParticipantUpdateAckListener(SupervisionHandler supervisionHandler) {
+ super(ParticipantUpdateAck.class);
+ this.supervisionHandler = supervisionHandler;
+ }
+
+ @Override
+ public void onTopicEvent(final CommInfrastructure infra, final String topic, final StandardCoderObject sco,
+ final ParticipantUpdateAck participantUpdateAckMessage) {
+ LOGGER.debug("ParticipantUpdateAck message received from participant - {}", participantUpdateAckMessage);
+ supervisionHandler.handleParticipantMessage(participantUpdateAckMessage);
+ }
+
+ @Override
+ public String getType() {
+ return ParticipantMessageType.PARTICIPANT_UPDATE_ACK.name();
+ }
+
+ @Override
+ public ScoListener<ParticipantUpdateAck> getScoListener() {
+ return this;
+ }
+}
diff --git a/runtime-acm/src/main/java/org/onap/policy/clamp/acm/runtime/supervision/comm/ParticipantUpdatePublisher.java b/runtime-acm/src/main/java/org/onap/policy/clamp/acm/runtime/supervision/comm/ParticipantUpdatePublisher.java
new file mode 100644
index 000000000..47a66c10e
--- /dev/null
+++ b/runtime-acm/src/main/java/org/onap/policy/clamp/acm/runtime/supervision/comm/ParticipantUpdatePublisher.java
@@ -0,0 +1,127 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * Copyright (C) 2021 Nordix Foundation.
+ * ================================================================================
+ * Modifications Copyright (C) 2021 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * 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.acm.runtime.supervision.comm;
+
+import java.time.Instant;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import lombok.AllArgsConstructor;
+import org.onap.policy.clamp.models.acm.concepts.ParticipantDefinition;
+import org.onap.policy.clamp.models.acm.concepts.ParticipantUtils;
+import org.onap.policy.clamp.models.acm.messages.dmaap.participant.ParticipantUpdate;
+import org.onap.policy.clamp.models.acm.persistence.provider.ServiceTemplateProvider;
+import org.onap.policy.clamp.models.acm.utils.AcmUtils;
+import org.onap.policy.models.base.PfModelException;
+import org.onap.policy.models.tosca.authorative.concepts.ToscaConceptIdentifier;
+import org.onap.policy.models.tosca.authorative.concepts.ToscaNodeType;
+import org.onap.policy.models.tosca.authorative.concepts.ToscaServiceTemplate;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.stereotype.Component;
+
+/**
+ * This class is used to send ParticipantUpdate messages to participants on DMaaP.
+ */
+@Component
+@AllArgsConstructor
+public class ParticipantUpdatePublisher extends AbstractParticipantPublisher<ParticipantUpdate> {
+
+ private static final Logger LOGGER = LoggerFactory.getLogger(ParticipantUpdatePublisher.class);
+
+ private final ServiceTemplateProvider serviceTemplateProvider;
+
+ /**
+ * Send ParticipantUpdate to all Participants.
+ *
+ * @param name the ToscaServiceTemplate name
+ * @param version the ToscaServiceTemplate version
+ */
+ public void sendComissioningBroadcast(String name, String version) {
+ sendCommissioning(name, version, null, null);
+ }
+
+ /**
+ * Send ParticipantUpdate to Participant
+ * if participantType and participantId are null then message is broadcast.
+ *
+ * @param name the ToscaServiceTemplate name
+ * @param version the ToscaServiceTemplate version
+ * @param participantType the ParticipantType
+ * @param participantId the ParticipantId
+ */
+ public boolean sendCommissioning(String name, String version, ToscaConceptIdentifier participantType,
+ ToscaConceptIdentifier participantId) {
+ var message = new ParticipantUpdate();
+ message.setParticipantType(participantType);
+ message.setParticipantId(participantId);
+ message.setTimestamp(Instant.now());
+
+ ToscaServiceTemplate toscaServiceTemplate = null;
+ Map<String, ToscaNodeType> commonPropertiesMap = null;
+ try {
+ var list = serviceTemplateProvider.getServiceTemplateList(name, version);
+ if (!list.isEmpty()) {
+ toscaServiceTemplate = list.get(0);
+ commonPropertiesMap =
+ serviceTemplateProvider.getCommonOrInstancePropertiesFromNodeTypes(true, toscaServiceTemplate);
+ } else {
+ LOGGER.warn("No tosca service template found, cannot send participantupdate {} {}", name, version);
+ return false;
+ }
+ } catch (PfModelException pfme) {
+ LOGGER.warn("Get of tosca service template failed, cannot send participantupdate", pfme);
+ return false;
+ }
+
+ List<ParticipantDefinition> participantDefinitionUpdates = new ArrayList<>();
+ for (var toscaInputEntry : toscaServiceTemplate.getToscaTopologyTemplate().getNodeTemplates().entrySet()) {
+ if (ParticipantUtils.checkIfNodeTemplateIsAutomationCompositionElement(toscaInputEntry.getValue(),
+ toscaServiceTemplate)) {
+ AcmUtils.prepareParticipantDefinitionUpdate(
+ ParticipantUtils.findParticipantType(toscaInputEntry.getValue().getProperties()),
+ toscaInputEntry.getKey(), toscaInputEntry.getValue(),
+ participantDefinitionUpdates, commonPropertiesMap);
+ }
+ }
+
+ // Commission the automation composition but sending participantdefinitions to participants
+ message.setParticipantDefinitionUpdates(participantDefinitionUpdates);
+ LOGGER.debug("Participant Update sent {}", message);
+ super.send(message);
+ return true;
+ }
+
+ /**
+ * Send ParticipantUpdate to Participant after that commissioning has been removed.
+ */
+ public void sendDecomisioning() {
+ var message = new ParticipantUpdate();
+ message.setTimestamp(Instant.now());
+ // DeCommission the automation composition but deleting participantdefinitions on participants
+ message.setParticipantDefinitionUpdates(null);
+
+ LOGGER.debug("Participant Update sent {}", message);
+ super.send(message);
+ }
+}