Transfer tosca-poc onto master

This is the third if three commits, this commit makes the content of
the master branch the same as the tosca-poc branch.

This commit adds the "src" files for TOSCA control loops to the modules
in master.

Difference between this commit and the current master:
------------------------------------------------------
diff -qr clamp clamp-master |diff_filter.sh
Only in clamp/common: src
Only in clamp/models: src
Files clamp/participant/participant-impl/participant-impl-dcae/pom.xml and clamp-master/participant/participant-impl/participant-impl-dcae/pom.xml differ
Only in clamp/participant/participant-impl/participant-impl-dcae: src
Only in clamp/participant/participant-impl/participant-impl-policy: src
Only in clamp/participant/participant-impl/participant-impl-simulator: src
Files clamp/participant/participant-impl/pom.xml and clamp-master/participant/participant-impl/pom.xml differ
Only in clamp/participant/participant-intermediary: src
Files clamp/participant/pom.xml and clamp-master/participant/pom.xml differ
Files clamp/pom.xml and clamp-master/pom.xml differ
Files clamp/runtime/pom.xml and clamp-master/runtime/pom.xml differ
Only in clamp: runtime-controlloop

Difference between this commit and the current tosca-poc branch:
----------------------------------------------------------------
diff -qr clamp clamp-tp |diff_filter.sh
Files clamp/INFO.yaml and clamp-tp/INFO.yaml differ
Only in clamp/releases: 6.0.1-container.yaml
Only in clamp/releases: 6.0.1.yaml
Only in clamp/releases: 6.0.2-container.yaml
Only in clamp/releases: 6.0.2.yaml
Only in clamp/releases: 6.1.0-container.yaml
Only in clamp/releases: 6.1.0.yaml
Only in clamp/releases: 6.1.1-container.yaml
Only in clamp/releases: 6.1.1.yaml
Files clamp/runtime/src/main/resources/META-INF/resources/swagger.html and clamp-tp/runtime/src/main/resources/META-INF/resources/swagger.html differ

Issue-ID: POLICY-3215
Change-Id: Ica1aa3fe5d6110df2396ea856703102e800fa770
Signed-off-by: liamfallon <liam.fallon@est.tech>
diff --git a/runtime-controlloop/pom.xml b/runtime-controlloop/pom.xml
new file mode 100644
index 0000000..ab72deb
--- /dev/null
+++ b/runtime-controlloop/pom.xml
@@ -0,0 +1,48 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  ============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=========================================================
+-->
+
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+
+    <parent>
+        <groupId>org.onap.policy.clamp</groupId>
+        <artifactId>policy-clamp</artifactId>
+        <version>6.1.2-SNAPSHOT</version>
+    </parent>
+
+    <artifactId>policy-clamp-runtime-controlloop</artifactId>
+    <name>${project.artifactId}</name>
+
+    <dependencies>
+        <dependency>
+            <groupId>org.onap.policy.clamp</groupId>
+            <artifactId>policy-clamp-common</artifactId>
+            <version>${project.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.onap.policy.clamp</groupId>
+            <artifactId>policy-clamp-models</artifactId>
+            <version>${project.version}</version>
+        </dependency>
+    </dependencies>
+</project>
diff --git a/runtime-controlloop/src/main/java/org/onap/policy/clamp/controlloop/runtime/commissioning/CommissioningHandler.java b/runtime-controlloop/src/main/java/org/onap/policy/clamp/controlloop/runtime/commissioning/CommissioningHandler.java
new file mode 100644
index 0000000..88e8b1d
--- /dev/null
+++ b/runtime-controlloop/src/main/java/org/onap/policy/clamp/controlloop/runtime/commissioning/CommissioningHandler.java
@@ -0,0 +1,81 @@
+/*-
+ * ============LICENSE_START=======================================================
+ *  Copyright (C) 2021 Nordix Foundation.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.policy.clamp.controlloop.runtime.commissioning;
+
+import java.io.IOException;
+import java.util.List;
+import java.util.Set;
+import javax.ws.rs.core.Response;
+import lombok.Getter;
+import org.onap.policy.clamp.controlloop.common.handler.ControlLoopHandler;
+import org.onap.policy.clamp.controlloop.runtime.commissioning.rest.CommissioningController;
+import org.onap.policy.clamp.controlloop.runtime.main.parameters.ClRuntimeParameterGroup;
+import org.onap.policy.common.endpoints.event.comm.TopicSink;
+import org.onap.policy.common.endpoints.listeners.MessageTypeDispatcher;
+import org.onap.policy.common.utils.services.Registry;
+import org.onap.policy.models.base.PfModelRuntimeException;
+
+/**
+ * This class handles commissioning of control loop definitions.
+ */
+public final class CommissioningHandler extends ControlLoopHandler {
+
+    @Getter
+    private CommissioningProvider provider;
+
+    /**
+     * Gets the CommissioningHandler.
+     *
+     * @return CommissioningHandler
+     */
+    public static CommissioningHandler getInstance() {
+        return Registry.get(CommissioningHandler.class.getName());
+    }
+
+    /**
+     * Create a handler.
+     *
+     * @param controlLoopParameters the parameters for access to the database
+     */
+    public CommissioningHandler(ClRuntimeParameterGroup controlLoopParameters) {
+        super(controlLoopParameters.getDatabaseProviderParameters());
+    }
+
+    @Override
+    public Set<Class<?>> getProviderClasses() {
+        return Set.of(CommissioningController.class);
+    }
+
+    @Override
+    public void startProviders() {
+        provider = new CommissioningProvider(getDatabaseProviderParameters());
+    }
+
+    @Override
+    public void stopProviders() {
+        try {
+            provider.close();
+        } catch (IOException e) {
+            throw new PfModelRuntimeException(Response.Status.INTERNAL_SERVER_ERROR,
+                    "an error has occured while stopping commissioning providers", e);
+        }
+    }
+}
diff --git a/runtime-controlloop/src/main/java/org/onap/policy/clamp/controlloop/runtime/commissioning/CommissioningProvider.java b/runtime-controlloop/src/main/java/org/onap/policy/clamp/controlloop/runtime/commissioning/CommissioningProvider.java
new file mode 100644
index 0000000..50f6787
--- /dev/null
+++ b/runtime-controlloop/src/main/java/org/onap/policy/clamp/controlloop/runtime/commissioning/CommissioningProvider.java
@@ -0,0 +1,208 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * Copyright (C) 2021 Nordix Foundation.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.policy.clamp.controlloop.runtime.commissioning;
+
+import java.io.Closeable;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
+import org.apache.commons.collections4.CollectionUtils;
+import org.apache.commons.collections4.MapUtils;
+import org.onap.policy.clamp.controlloop.common.exception.ControlLoopRuntimeException;
+import org.onap.policy.clamp.controlloop.models.controlloop.persistence.provider.ControlLoopProvider;
+import org.onap.policy.clamp.controlloop.models.messages.rest.commissioning.CommissioningResponse;
+import org.onap.policy.models.base.PfModelException;
+import org.onap.policy.models.base.PfModelRuntimeException;
+import org.onap.policy.models.provider.PolicyModelsProvider;
+import org.onap.policy.models.provider.PolicyModelsProviderFactory;
+import org.onap.policy.models.provider.PolicyModelsProviderParameters;
+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.onap.policy.models.tosca.authorative.concepts.ToscaServiceTemplates;
+import org.onap.policy.models.tosca.authorative.concepts.ToscaTypedEntityFilter;
+
+/**
+ * This class provides the create, read and delete actions on Commissioning of Control Loop concepts in the database to
+ * the callers.
+ */
+public class CommissioningProvider implements Closeable {
+    public static final String CONTROL_LOOP_NODE_TYPE = "org.onap.policy.clamp.controlloop.ControlLoop";
+
+    private final PolicyModelsProvider modelsProvider;
+    private final ControlLoopProvider clProvider;
+
+    private static final Object lockit = new Object();
+
+    /**
+     * Create a commissioning provider.
+     *
+     * @throws ControlLoopRuntimeException on errors creating the provider
+     */
+    public CommissioningProvider(PolicyModelsProviderParameters databaseProviderParameters)
+            throws ControlLoopRuntimeException {
+        try {
+            modelsProvider = new PolicyModelsProviderFactory()
+                    .createPolicyModelsProvider(databaseProviderParameters);
+        } catch (PfModelException e) {
+            throw new PfModelRuntimeException(e);
+        }
+
+        try {
+            clProvider = new ControlLoopProvider(databaseProviderParameters);
+        } catch (PfModelException e) {
+            throw new PfModelRuntimeException(e);
+        }
+    }
+
+    @Override
+    public void close() throws IOException {
+        try {
+            modelsProvider.close();
+        } catch (PfModelException e) {
+            throw new IOException("error closing modelsProvider", e);
+        }
+    }
+
+    /**
+     * Create control loops from a service template.
+     *
+     * @param serviceTemplate the service template
+     * @return the result of the commissioning operation
+     * @throws PfModelException on creation errors
+     */
+    public CommissioningResponse createControlLoopDefinitions(ToscaServiceTemplate serviceTemplate)
+            throws PfModelException {
+        synchronized (lockit) {
+            modelsProvider.createServiceTemplate(serviceTemplate);
+        }
+
+        CommissioningResponse response = new CommissioningResponse();
+        // @formatter:off
+        response.setAffectedControlLoopDefinitions(serviceTemplate.getToscaTopologyTemplate().getNodeTemplates()
+                .values()
+                .stream()
+                .map(template -> template.getKey().asIdentifier())
+                .collect(Collectors.toList()));
+        // @formatter:on
+
+        return response;
+    }
+
+    /**
+     * Delete the control loop definition with the given name and version.
+     *
+     * @param name the name of the control loop definition to delete
+     * @param version the version of the control loop to delete
+     * @return the result of the deletion
+     * @throws PfModelException on deletion errors
+     */
+    public CommissioningResponse deleteControlLoopDefinition(String name, String version) throws PfModelException {
+        synchronized (lockit) {
+            modelsProvider.deleteServiceTemplate(name, version);
+        }
+
+        CommissioningResponse response = new CommissioningResponse();
+        response.setAffectedControlLoopDefinitions(
+                Collections.singletonList(new ToscaConceptIdentifier(name, version)));
+
+        return response;
+    }
+
+    /**
+     * Get control loop node templates.
+     *
+     * @param clName the name of the control loop, null for all
+     * @param clVersion the version of the control loop, null for all
+     * @return list of control loop node templates
+     * @throws PfModelException on errors getting control loop definitions
+     */
+    public List<ToscaNodeTemplate> getControlLoopDefinitions(String clName, String clVersion) throws PfModelException {
+
+        // @formatter:off
+        ToscaTypedEntityFilter<ToscaNodeTemplate> nodeTemplateFilter = ToscaTypedEntityFilter
+                .<ToscaNodeTemplate>builder()
+                .name(clName)
+                .version(clVersion)
+                .type(CONTROL_LOOP_NODE_TYPE)
+                .build();
+        // @formatter:on
+
+        return clProvider.getFilteredNodeTemplates(nodeTemplateFilter);
+    }
+
+    /**
+     * Get the control loop elements from a control loop node template.
+     *
+     * @param controlLoopNodeTemplate the control loop node template
+     * @return a list of the control loop element node templates in a control loop node template
+     * @throws PfModelException on errors get control loop element node templates
+     */
+    public List<ToscaNodeTemplate> getControlLoopElementDefinitions(ToscaNodeTemplate controlLoopNodeTemplate)
+            throws PfModelException {
+        if (!CONTROL_LOOP_NODE_TYPE.equals(controlLoopNodeTemplate.getType())) {
+            return Collections.emptyList();
+        }
+
+        if (MapUtils.isEmpty(controlLoopNodeTemplate.getProperties())) {
+            return Collections.emptyList();
+        }
+
+        @SuppressWarnings("unchecked")
+        List<Map<String, String>> controlLoopElements =
+                (List<Map<String, String>>) controlLoopNodeTemplate.getProperties().get("elements");
+
+        if (CollectionUtils.isEmpty(controlLoopElements)) {
+            return Collections.emptyList();
+        }
+
+        List<ToscaNodeTemplate> controlLoopElementList = new ArrayList<>();
+        // @formatter:off
+        controlLoopElementList.addAll(
+                controlLoopElements
+                        .stream()
+                        .map(elementMap -> clProvider.getNodeTemplates(elementMap.get("name"),
+                                elementMap.get("version")))
+                        .flatMap(List::stream)
+                        .collect(Collectors.toList())
+        );
+        // @formatter:on
+
+        return controlLoopElementList;
+    }
+
+    /**
+     * Get the requested control loop 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 control loop definitions
+     * @throws PfModelException on errors getting control loop definitions
+     */
+    public ToscaServiceTemplate getToscaServiceTemplate(String name, String version) throws PfModelException {
+        ToscaServiceTemplates serviceTemplates = new ToscaServiceTemplates();
+        serviceTemplates.setServiceTemplates(modelsProvider.getServiceTemplateList(name, version));
+        return serviceTemplates.getServiceTemplates().get(0);
+    }
+}
diff --git a/runtime-controlloop/src/main/java/org/onap/policy/clamp/controlloop/runtime/commissioning/rest/CommissioningController.java b/runtime-controlloop/src/main/java/org/onap/policy/clamp/controlloop/runtime/commissioning/rest/CommissioningController.java
new file mode 100644
index 0000000..18e1f77
--- /dev/null
+++ b/runtime-controlloop/src/main/java/org/onap/policy/clamp/controlloop/runtime/commissioning/rest/CommissioningController.java
@@ -0,0 +1,360 @@
+/*-
+ * ============LICENSE_START=======================================================
+ *  Copyright (C) 2021 Nordix Foundation.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.policy.clamp.controlloop.runtime.commissioning.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.UUID;
+import javax.ws.rs.DELETE;
+import javax.ws.rs.GET;
+import javax.ws.rs.HeaderParam;
+import javax.ws.rs.POST;
+import javax.ws.rs.Path;
+import javax.ws.rs.QueryParam;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.Response.Status;
+import org.onap.policy.clamp.controlloop.models.messages.rest.commissioning.CommissioningResponse;
+import org.onap.policy.clamp.controlloop.runtime.commissioning.CommissioningHandler;
+import org.onap.policy.clamp.controlloop.runtime.commissioning.CommissioningProvider;
+import org.onap.policy.clamp.controlloop.runtime.main.rest.RestController;
+import org.onap.policy.models.base.PfModelException;
+import org.onap.policy.models.base.PfModelRuntimeException;
+import org.onap.policy.models.errors.concepts.ErrorResponse;
+import org.onap.policy.models.errors.concepts.ErrorResponseInfo;
+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;
+
+/**
+ * Class to provide REST end points for creating, deleting, querying commissioned control loops.
+ */
+public class CommissioningController extends RestController {
+
+    private static final Logger LOGGER = LoggerFactory.getLogger(CommissioningController.class);
+
+    private final CommissioningProvider provider;
+
+    /**
+     * create Commissioning Controller.
+     */
+    public CommissioningController() {
+        this.provider = CommissioningHandler.getInstance().getProvider();
+    }
+
+    /**
+     * Creates a control loop definition.
+     *
+     * @param requestId request ID used in ONAP logging
+     * @param body the body of control loop following TOSCA definition
+     * @return a response
+     */
+    // @formatter:off
+    @POST
+    @Path("/commission")
+    @ApiOperation(
+            value = "Commissions control loop definitions",
+            notes = "Commissions control loop definitions, returning the commissioned control loop definition IDs",
+            response = CommissioningResponse.class,
+            tags = {
+                    "Control Loop 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 Response create(
+            @HeaderParam(REQUEST_ID_NAME) @ApiParam(REQUEST_ID_PARAM_DESCRIPTION) UUID requestId,
+            @ApiParam(value = "Entity Body of Control Loop", required = true) ToscaServiceTemplate body) {
+
+        try {
+            CommissioningResponse response = provider.createControlLoopDefinitions(body);
+            return addLoggingHeaders(addVersionControlHeaders(Response.status(Status.OK)), requestId)
+                    .entity(response).build();
+
+        } catch (PfModelRuntimeException | PfModelException e) {
+            LOGGER.warn("Commissioning of the control loops failed", e);
+            CommissioningResponse resp = new CommissioningResponse();
+            resp.setErrorDetails(e.getErrorResponse().getErrorMessage());
+            return returnResponse(e.getErrorResponse().getResponseCode(), requestId, resp);
+        }
+
+    }
+
+    /**
+     * Deletes a control loop definition.
+     *
+     * @param requestId request ID used in ONAP logging
+     * @param name the name of the control loop definition to delete
+     * @param version the version of the control loop definition to delete
+     * @return a response
+     */
+    // @formatter:off
+    @DELETE
+    @Path("/commission")
+    @ApiOperation(value = "Delete a commissioned control loop",
+            notes = "Deletes a Commissioned Control Loop, returning optional error details",
+            response = CommissioningResponse.class,
+            tags = {
+                    "Clamp Control Loop 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 Response delete(
+            @HeaderParam(REQUEST_ID_NAME) @ApiParam(REQUEST_ID_PARAM_DESCRIPTION) UUID requestId,
+            @ApiParam(value = "Control Loop definition name", required = true) @QueryParam("name") String name,
+            @ApiParam(value = "Control Loop definition version", required = true)
+            @QueryParam("version") String version) {
+
+        try {
+            CommissioningResponse response = provider.deleteControlLoopDefinition(name, version);
+            return addLoggingHeaders(addVersionControlHeaders(Response.status(Status.OK)), requestId)
+                    .entity(response).build();
+
+        } catch (PfModelRuntimeException | PfModelException e) {
+            LOGGER.warn("Decommisssioning of control loop failed", e);
+            CommissioningResponse resp = new CommissioningResponse();
+            resp.setErrorDetails(e.getErrorResponse().getErrorMessage());
+            return returnResponse(e.getErrorResponse().getResponseCode(), requestId, resp);
+        }
+
+    }
+
+    /**
+     * Queries details of all or specific control loop definitions.
+     *
+     * @param requestId request ID used in ONAP logging
+     * @param name the name of the control loop definition to get, null for all definitions
+     * @param version the version of the control loop definition to get, null for all definitions
+     * @return the control loop definitions
+     */
+    // @formatter:off
+    @GET
+    @Path("/commission")
+    @ApiOperation(value = "Query details of the requested commissioned control loop definitions",
+            notes = "Queries details of the requested commissioned control loop definitions, "
+                    + "returning all control loop details",
+            response = ToscaNodeTemplate.class,
+            tags = {
+                    "Clamp Control Loop 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 Response query(@HeaderParam(REQUEST_ID_NAME) @ApiParam(REQUEST_ID_PARAM_DESCRIPTION) UUID requestId,
+                          @ApiParam(value = "Control Loop definition name", required = true)
+                          @QueryParam("name") String name,
+                          @ApiParam(value = "Control Loop definition version", required = true)
+                          @QueryParam("version") String version) {
+
+        try {
+            List<ToscaNodeTemplate> response = provider.getControlLoopDefinitions(name, version);
+            return addLoggingHeaders(addVersionControlHeaders(Response.status(Status.OK)), requestId).entity(response)
+                    .build();
+
+        } catch (PfModelRuntimeException | PfModelException e) {
+            LOGGER.warn("Get of control loop definitions failed", e);
+            CommissioningResponse resp = new CommissioningResponse();
+            resp.setErrorDetails(e.getErrorResponse().getErrorMessage());
+            return returnResponse(e.getErrorResponse().getResponseCode(), requestId, resp);
+        }
+
+    }
+
+    /**
+     * Queries the elements of a specific control loop.
+     *
+     * @param requestId request ID used in ONAP logging
+     * @param name the name of the control loop definition to get
+     * @param version the version of the control loop definition to get
+     * @return the control loop element definitions
+     */
+    // @formatter:off
+    @GET
+    @Path("/commission/elements")
+    @ApiOperation(value = "Query details of the requested commissioned control loop element definitions",
+            notes = "Queries details of the requested commissioned control loop element definitions, "
+                    + "returning all control loop elements' details",
+            response = ToscaNodeTemplate.class,
+            tags = {
+                    "Clamp Control Loop 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 Response queryElements(@HeaderParam(REQUEST_ID_NAME) @ApiParam(REQUEST_ID_PARAM_DESCRIPTION) UUID requestId,
+                                  @ApiParam(value = "Control Loop definition name", required = true)
+                                  @QueryParam("name") String name,
+                                  @ApiParam(value = "Control Loop definition version", required = true)
+                                  @QueryParam("version") String version) throws Exception {
+
+        try {
+            List<ToscaNodeTemplate> nodeTemplate = provider.getControlLoopDefinitions(name, version);
+            //Prevent ambiguous queries with multiple returns
+            if (nodeTemplate.size() > 1) {
+                CommissioningResponse resp = new CommissioningResponse();
+                resp.setErrorDetails("Multiple ControlLoops are not supported");
+                return returnResponse(Response.Status.NOT_ACCEPTABLE, requestId, resp);
+            }
+
+            List<ToscaNodeTemplate> response = provider.getControlLoopElementDefinitions(nodeTemplate.get(0));
+            return addLoggingHeaders(addVersionControlHeaders(Response.status(Status.OK)), requestId).entity(response)
+                    .build();
+
+        } catch (PfModelRuntimeException | PfModelException e) {
+            LOGGER.warn("Get of control loop element definitions failed", e);
+            CommissioningResponse resp = new CommissioningResponse();
+            resp.setErrorDetails(e.getErrorResponse().getErrorMessage());
+            return returnResponse(e.getErrorResponse().getResponseCode(), requestId, resp);
+        }
+
+    }
+
+    private Response returnResponse(Response.Status status, UUID requestId, CommissioningResponse resp) {
+        return addLoggingHeaders(addVersionControlHeaders(Response.status(status)),
+                requestId).entity(resp).build();
+    }
+}
diff --git a/runtime-controlloop/src/main/java/org/onap/policy/clamp/controlloop/runtime/instantiation/ControlLoopInstantiationProvider.java b/runtime-controlloop/src/main/java/org/onap/policy/clamp/controlloop/runtime/instantiation/ControlLoopInstantiationProvider.java
new file mode 100644
index 0000000..eb72d92
--- /dev/null
+++ b/runtime-controlloop/src/main/java/org/onap/policy/clamp/controlloop/runtime/instantiation/ControlLoopInstantiationProvider.java
@@ -0,0 +1,276 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * Copyright (C) 2021 Nordix Foundation.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.policy.clamp.controlloop.runtime.instantiation;
+
+import java.io.Closeable;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+import java.util.function.UnaryOperator;
+import java.util.stream.Collectors;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.Response.Status;
+import org.onap.policy.clamp.controlloop.common.exception.ControlLoopException;
+import org.onap.policy.clamp.controlloop.models.controlloop.concepts.ControlLoop;
+import org.onap.policy.clamp.controlloop.models.controlloop.concepts.ControlLoopElement;
+import org.onap.policy.clamp.controlloop.models.controlloop.concepts.ControlLoopState;
+import org.onap.policy.clamp.controlloop.models.controlloop.concepts.ControlLoops;
+import org.onap.policy.clamp.controlloop.models.controlloop.persistence.provider.ControlLoopProvider;
+import org.onap.policy.clamp.controlloop.models.messages.rest.instantiation.InstantiationCommand;
+import org.onap.policy.clamp.controlloop.models.messages.rest.instantiation.InstantiationResponse;
+import org.onap.policy.clamp.controlloop.runtime.commissioning.CommissioningProvider;
+import org.onap.policy.clamp.controlloop.runtime.supervision.SupervisionHandler;
+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.base.PfModelRuntimeException;
+import org.onap.policy.models.provider.PolicyModelsProviderParameters;
+import org.onap.policy.models.tosca.authorative.concepts.ToscaConceptIdentifier;
+import org.onap.policy.models.tosca.authorative.concepts.ToscaNodeTemplate;
+
+/**
+ * This class is dedicated to the Instantiation of Commissioned control loop.
+ */
+public class ControlLoopInstantiationProvider implements Closeable {
+    private final ControlLoopProvider controlLoopProvider;
+    private final CommissioningProvider commissioningProvider;
+
+    private static final Object lockit = new Object();
+
+    /**
+     * Create a instantiation provider.
+     *
+     * @param databaseProviderParameters the parameters for database access
+     */
+    public ControlLoopInstantiationProvider(PolicyModelsProviderParameters databaseProviderParameters) {
+        try {
+            controlLoopProvider = new ControlLoopProvider(databaseProviderParameters);
+            commissioningProvider = new CommissioningProvider(databaseProviderParameters);
+        } catch (PfModelException e) {
+            throw new PfModelRuntimeException(e);
+        }
+    }
+
+    @Override
+    public void close() throws IOException {
+        controlLoopProvider.close();
+    }
+
+    /**
+     * Create control loops.
+     *
+     * @param controlLoops the control loop
+     * @return the result of the instantiation operation
+     * @throws PfModelException on creation errors
+     */
+    public InstantiationResponse createControlLoops(ControlLoops controlLoops) throws PfModelException {
+
+        synchronized (lockit) {
+            for (ControlLoop controlLoop : controlLoops.getControlLoopList()) {
+                ControlLoop checkControlLoop = controlLoopProvider.getControlLoop(controlLoop.getKey().asIdentifier());
+                if (checkControlLoop != null) {
+                    throw new PfModelException(Response.Status.BAD_REQUEST,
+                            controlLoop.getKey().asIdentifier() + " already defined");
+                }
+            }
+            BeanValidationResult validationResult = validateControlLoops(controlLoops);
+            if (!validationResult.isValid()) {
+                throw new PfModelException(Response.Status.BAD_REQUEST, validationResult.getResult());
+            }
+            controlLoopProvider.createControlLoops(controlLoops.getControlLoopList());
+        }
+
+        InstantiationResponse response = new InstantiationResponse();
+        response.setAffectedControlLoops(controlLoops.getControlLoopList().stream()
+                .map(cl -> cl.getKey().asIdentifier()).collect(Collectors.toList()));
+
+        return response;
+    }
+
+    /**
+     * Update control loops.
+     *
+     * @param controlLoops the control loop
+     * @return the result of the instantiation operation
+     * @throws PfModelException on update errors
+     */
+    public InstantiationResponse updateControlLoops(ControlLoops controlLoops) throws PfModelException {
+        synchronized (lockit) {
+            BeanValidationResult validationResult = validateControlLoops(controlLoops);
+            if (!validationResult.isValid()) {
+                throw new PfModelException(Response.Status.BAD_REQUEST, validationResult.getResult());
+            }
+            controlLoopProvider.updateControlLoops(controlLoops.getControlLoopList());
+        }
+
+        InstantiationResponse response = new InstantiationResponse();
+        response.setAffectedControlLoops(controlLoops.getControlLoopList().stream()
+                .map(cl -> cl.getKey().asIdentifier()).collect(Collectors.toList()));
+
+        return response;
+    }
+
+    /**
+     * Validate ControlLoops.
+     *
+     * @param controlLoops ControlLoops to validate
+     * @result the result of validation
+     * @throws PfModelException if controlLoops is not valid
+     */
+    private BeanValidationResult validateControlLoops(ControlLoops controlLoops) throws PfModelException {
+
+        BeanValidationResult result = new BeanValidationResult("ControlLoops", controlLoops);
+
+        for (ControlLoop controlLoop : controlLoops.getControlLoopList()) {
+            BeanValidationResult subResult = new BeanValidationResult(
+                    "entry " + controlLoop.getDefinition().getName(), controlLoop);
+
+            List<ToscaNodeTemplate> toscaNodeTemplates = commissioningProvider.getControlLoopDefinitions(
+                    controlLoop.getDefinition().getName(), controlLoop.getDefinition().getVersion());
+
+            if (toscaNodeTemplates.isEmpty()) {
+                subResult
+                        .addResult(new ObjectValidationResult("ControlLoop", controlLoop.getDefinition().getName(),
+                                ValidationStatus.INVALID, "Commissioned control loop definition not FOUND"));
+            } else if (toscaNodeTemplates.size() > 1) {
+                subResult
+                        .addResult(new ObjectValidationResult("ControlLoop", controlLoop.getDefinition().getName(),
+                                ValidationStatus.INVALID, "Commissioned control loop definition not VALID"));
+            } else {
+
+                List<ToscaNodeTemplate> clElementDefinitions =
+                        commissioningProvider.getControlLoopElementDefinitions(toscaNodeTemplates.get(0));
+
+                // @formatter:off
+                Map<String, ToscaConceptIdentifier> definitions = clElementDefinitions
+                        .stream()
+                        .map(nodeTemplate -> nodeTemplate.getKey().asIdentifier())
+                        .collect(Collectors.toMap(ToscaConceptIdentifier::getName, UnaryOperator.identity()));
+                // @formatter:on
+
+                for (ControlLoopElement element : controlLoop.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
+     * @result result the validation result
+     */
+    private ValidationResult validateDefinition(Map<String, ToscaConceptIdentifier> definitions,
+                                                ToscaConceptIdentifier definition) {
+        BeanValidationResult 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 control loop with the given name and version.
+     *
+     * @param name the name of the control loop to delete
+     * @param version the version of the control loop to delete
+     * @return the result of the deletion
+     * @throws PfModelException on deletion errors
+     */
+    public InstantiationResponse deleteControlLoop(String name, String version) throws PfModelException {
+        InstantiationResponse response = new InstantiationResponse();
+        synchronized (lockit) {
+            List<ControlLoop> controlLoops = controlLoopProvider.getControlLoops(name, version);
+            if (controlLoops.isEmpty()) {
+                throw new PfModelException(Response.Status.NOT_FOUND, "Control Loop not found");
+            }
+            for (ControlLoop controlLoop : controlLoops) {
+                if (!ControlLoopState.UNINITIALISED.equals(controlLoop.getState())) {
+                    throw new PfModelException(Response.Status.BAD_REQUEST,
+                            "Control Loop State is still " + controlLoop.getState());
+                }
+            }
+
+            response.setAffectedControlLoops(Collections
+                    .singletonList(controlLoopProvider.deleteControlLoop(name, version).getKey().asIdentifier()));
+        }
+        return response;
+    }
+
+    /**
+     * Get the requested control loops.
+     *
+     * @param name the name of the control loop to get, null for all control loops
+     * @param version the version of the control loop to get, null for all control loops
+     * @return the control loops
+     * @throws PfModelException on errors getting control loops
+     */
+    public ControlLoops getControlLoops(String name, String version) throws PfModelException {
+        ControlLoops controlLoops = new ControlLoops();
+        controlLoops.setControlLoopList(controlLoopProvider.getControlLoops(name, version));
+
+        return controlLoops;
+    }
+
+    /**
+     * Issue a command to control loops, setting their ordered state.
+     *
+     * @param command the command to issue to control loops
+     * @return the result of the initiation command
+     * @throws PfModelException on errors setting the ordered state on the control loops
+     * @throws ControlLoopException on ordered state invalid
+     */
+    public InstantiationResponse issueControlLoopCommand(InstantiationCommand command)
+            throws ControlLoopException, PfModelException {
+
+        if (command.getOrderedState() == null) {
+            throw new ControlLoopException(Status.BAD_REQUEST, "ordered state invalid or not specified on command");
+        }
+
+        synchronized (lockit) {
+            List<ControlLoop> controlLoops = new ArrayList<>(command.getControlLoopIdentifierList().size());
+            for (ToscaConceptIdentifier id : command.getControlLoopIdentifierList()) {
+                ControlLoop controlLoop = controlLoopProvider.getControlLoop(id);
+                controlLoop.setCascadedOrderedState(command.getOrderedState());
+                controlLoops.add(controlLoop);
+            }
+            controlLoopProvider.updateControlLoops(controlLoops);
+        }
+
+        SupervisionHandler supervisionHandler = SupervisionHandler.getInstance();
+        supervisionHandler.triggerControlLoopSupervision(command.getControlLoopIdentifierList());
+        InstantiationResponse response = new InstantiationResponse();
+        response.setAffectedControlLoops(command.getControlLoopIdentifierList());
+
+        return response;
+    }
+}
diff --git a/runtime-controlloop/src/main/java/org/onap/policy/clamp/controlloop/runtime/instantiation/InstantiationHandler.java b/runtime-controlloop/src/main/java/org/onap/policy/clamp/controlloop/runtime/instantiation/InstantiationHandler.java
new file mode 100644
index 0000000..d81e54c
--- /dev/null
+++ b/runtime-controlloop/src/main/java/org/onap/policy/clamp/controlloop/runtime/instantiation/InstantiationHandler.java
@@ -0,0 +1,82 @@
+/*-
+ * ============LICENSE_START=======================================================
+ *  Copyright (C) 2021 Nordix Foundation.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.policy.clamp.controlloop.runtime.instantiation;
+
+import java.io.IOException;
+import java.util.List;
+import java.util.Set;
+import javax.ws.rs.core.Response;
+import lombok.Getter;
+import org.onap.policy.clamp.controlloop.common.handler.ControlLoopHandler;
+import org.onap.policy.clamp.controlloop.runtime.instantiation.rest.InstantiationController;
+import org.onap.policy.clamp.controlloop.runtime.main.parameters.ClRuntimeParameterGroup;
+import org.onap.policy.common.endpoints.event.comm.TopicSink;
+import org.onap.policy.common.endpoints.listeners.MessageTypeDispatcher;
+import org.onap.policy.common.utils.services.Registry;
+import org.onap.policy.models.base.PfModelRuntimeException;
+
+/**
+ * This class handles instantiation of control loop instances.
+ *
+ * <p/>It is effectively a singleton that is started at system start
+ */
+public final class InstantiationHandler extends ControlLoopHandler {
+
+    @Getter
+    private ControlLoopInstantiationProvider controlLoopInstantiationProvider;
+
+    /**
+     * Gets the InstantiationHandler.
+     *
+     * @return InstantiationHandler
+     */
+    public static InstantiationHandler getInstance() {
+        return Registry.get(InstantiationHandler.class.getName());
+    }
+
+    /**
+     * Create a handler.
+     *
+     * @param controlLoopParameters the parameters for access to the database
+     */
+    public InstantiationHandler(ClRuntimeParameterGroup controlLoopParameters) {
+        super(controlLoopParameters.getDatabaseProviderParameters());
+    }
+
+    @Override
+    public Set<Class<?>> getProviderClasses() {
+        return Set.of(InstantiationController.class);
+    }
+
+    @Override
+    public void startProviders() {
+        controlLoopInstantiationProvider = new ControlLoopInstantiationProvider(getDatabaseProviderParameters());
+    }
+
+    @Override
+    public void stopProviders() {
+        try {
+            controlLoopInstantiationProvider.close();
+        } catch (IOException e) {
+            throw new PfModelRuntimeException(Response.Status.INTERNAL_SERVER_ERROR, e.getMessage());
+        }
+    }
+}
diff --git a/runtime-controlloop/src/main/java/org/onap/policy/clamp/controlloop/runtime/instantiation/rest/InstantiationController.java b/runtime-controlloop/src/main/java/org/onap/policy/clamp/controlloop/runtime/instantiation/rest/InstantiationController.java
new file mode 100644
index 0000000..7581aaf
--- /dev/null
+++ b/runtime-controlloop/src/main/java/org/onap/policy/clamp/controlloop/runtime/instantiation/rest/InstantiationController.java
@@ -0,0 +1,416 @@
+/*-
+ * ============LICENSE_START=======================================================
+ *  Copyright (C) 2021 Nordix Foundation.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.policy.clamp.controlloop.runtime.instantiation.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 javax.ws.rs.DELETE;
+import javax.ws.rs.GET;
+import javax.ws.rs.HeaderParam;
+import javax.ws.rs.POST;
+import javax.ws.rs.PUT;
+import javax.ws.rs.Path;
+import javax.ws.rs.QueryParam;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.Response.Status;
+import org.onap.policy.clamp.controlloop.common.exception.ControlLoopException;
+import org.onap.policy.clamp.controlloop.models.controlloop.concepts.ControlLoops;
+import org.onap.policy.clamp.controlloop.models.messages.rest.instantiation.InstantiationCommand;
+import org.onap.policy.clamp.controlloop.models.messages.rest.instantiation.InstantiationResponse;
+import org.onap.policy.clamp.controlloop.runtime.instantiation.ControlLoopInstantiationProvider;
+import org.onap.policy.clamp.controlloop.runtime.instantiation.InstantiationHandler;
+import org.onap.policy.clamp.controlloop.runtime.main.rest.RestController;
+import org.onap.policy.models.base.PfModelException;
+import org.onap.policy.models.base.PfModelRuntimeException;
+import org.onap.policy.models.errors.concepts.ErrorResponseInfo;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Class to provide REST end points for creating, deleting, query and commanding a control loop definition.
+ */
+public class InstantiationController extends RestController {
+
+    private static final Logger LOGGER = LoggerFactory.getLogger(InstantiationController.class);
+
+    // The CL provider for instantiation requests
+    private final ControlLoopInstantiationProvider provider;
+
+    /**
+     * create Instantiation Controller.
+     */
+    public InstantiationController() {
+        this.provider = InstantiationHandler.getInstance().getControlLoopInstantiationProvider();
+    }
+
+    /**
+     * Creates a control loop.
+     *
+     * @param requestId request ID used in ONAP logging
+     * @param controlLoops the control loops
+     * @return a response
+     */
+    // @formatter:off
+    @POST
+    @Path("/instantiation")
+    @ApiOperation(
+            value = "Commissions control loop definitions",
+            notes = "Commissions control loop definitions, returning the control loop IDs",
+            response = InstantiationResponse.class,
+            tags = {
+                "Control Loop Instantiation 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 Response create(
+            @HeaderParam(REQUEST_ID_NAME) @ApiParam(REQUEST_ID_PARAM_DESCRIPTION) UUID requestId,
+            @ApiParam(value = "Entity Body of Control Loop", required = true) ControlLoops controlLoops) {
+
+        try {
+            InstantiationResponse response = provider.createControlLoops(controlLoops);
+            return addLoggingHeaders(addVersionControlHeaders(Response.status(Status.OK)), requestId).entity(response)
+                    .build();
+
+        } catch (PfModelRuntimeException | PfModelException e) {
+            LOGGER.warn("creation of control loop failed", e);
+            return createInstantiationErrorResponse(e, requestId);
+        }
+    }
+
+    /**
+     * Queries details of all control loops.
+     *
+     * @param requestId request ID used in ONAP logging
+     * @param name the name of the control loop to get, null for all control loops
+     * @param version the version of the control loop to get, null for all control loops
+     * @return the control loops
+     */
+    // @formatter:off
+    @GET
+    @Path("/instantiation")
+    @ApiOperation(value = "Query details of the requested control loops",
+            notes = "Queries details of the requested control loops, returning all control loop details",
+            response = ControlLoops.class,
+            tags = {
+                "Clamp control loop Instantiation 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 Response query(
+            @HeaderParam(REQUEST_ID_NAME) @ApiParam(REQUEST_ID_PARAM_DESCRIPTION) UUID requestId,
+            @ApiParam(value = "Control Loop definition name", required = true) @QueryParam("name") String name,
+            @ApiParam(value = "Control Loop definition version",
+                    required = true) @QueryParam("version") String version) {
+
+        try {
+            ControlLoops response = provider.getControlLoops(name, version);
+            return addLoggingHeaders(addVersionControlHeaders(Response.status(Status.OK)), requestId).entity(response)
+                    .build();
+
+        } catch (PfModelRuntimeException | PfModelException e) {
+            LOGGER.warn("commisssioning of control loop failed", e);
+            return createInstantiationErrorResponse(e, requestId);
+        }
+
+    }
+
+    /**
+     * Updates a control loop.
+     *
+     * @param requestId request ID used in ONAP logging
+     * @param controlLoops the control loops
+     * @return a response
+     */
+    // @formatter:off
+    @PUT
+    @Path("/instantiation")
+    @ApiOperation(
+            value = "Updates control loop definitions",
+            notes = "Updates control loop definitions, returning the updated control loop definition IDs",
+            response = InstantiationResponse.class,
+            tags = {
+                "Control Loop Instantiation 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 Response update(
+            @HeaderParam(REQUEST_ID_NAME) @ApiParam(REQUEST_ID_PARAM_DESCRIPTION) UUID requestId,
+            @ApiParam(value = "Entity Body of Control Loop", required = true) ControlLoops controlLoops) {
+
+        try {
+            InstantiationResponse response = provider.updateControlLoops(controlLoops);
+            return addLoggingHeaders(addVersionControlHeaders(Response.status(Status.OK)), requestId).entity(response)
+                    .build();
+
+        } catch (PfModelRuntimeException | PfModelException e) {
+            LOGGER.warn("update of control loops failed", e);
+            return createInstantiationErrorResponse(e, requestId);
+        }
+    }
+
+    /**
+     * Deletes a control loop definition.
+     *
+     * @param requestId request ID used in ONAP logging
+     * @param name the name of the control loop to delete
+     * @param version the version of the control loop to delete
+     * @return a response
+     */
+    // @formatter:off
+    @DELETE
+    @Path("/instantiation")
+    @ApiOperation(value = "Delete a control loop",
+            notes = "Deletes a control loop, returning optional error details",
+            response = InstantiationResponse.class,
+            tags = {
+                "Clamp Control Loop Instantiation 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 Response delete(
+            @HeaderParam(REQUEST_ID_NAME) @ApiParam(REQUEST_ID_PARAM_DESCRIPTION) UUID requestId,
+            @ApiParam(value = "Control Loop definition name", required = true) @QueryParam("name") String name,
+            @ApiParam(value = "Control Loop definition version", required = true)
+                    @QueryParam("version") String version) {
+
+        try {
+            InstantiationResponse response = provider.deleteControlLoop(name, version);
+            return addLoggingHeaders(addVersionControlHeaders(Response.status(Status.OK)), requestId).entity(response)
+                    .build();
+
+        } catch (PfModelRuntimeException | PfModelException e) {
+            LOGGER.warn("delete of control loop failed", e);
+            return createInstantiationErrorResponse(e, requestId);
+        }
+    }
+
+    /**
+     * Issues control loop commands to control loops.
+     *
+     * @param requestId request ID used in ONAP logging
+     * @param command the command to issue to control loops
+     * @return the control loop definitions
+     */
+    // @formatter:off
+    @PUT
+    @Path("/instantiation/command")
+    @ApiOperation(value = "Issue a command to the requested control loops",
+            notes = "Issues a command to a control loop, ordering a state change on the control loop",
+            response = InstantiationResponse.class,
+            tags = {
+                "Clamp Control Loop Instantiation 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 Response issueControlLoopCommand(
+            @HeaderParam(REQUEST_ID_NAME) @ApiParam(REQUEST_ID_PARAM_DESCRIPTION) UUID requestId,
+            @ApiParam(value = "Entity Body of control loop command", required = true) InstantiationCommand command) {
+
+        try {
+            InstantiationResponse response = provider.issueControlLoopCommand(command);
+            return addLoggingHeaders(addVersionControlHeaders(Response.status(Status.ACCEPTED)), requestId)
+                    .entity(response).build();
+
+        } catch (PfModelRuntimeException | PfModelException | ControlLoopException e) {
+            LOGGER.warn("creation of control loop failed", e);
+            return createInstantiationErrorResponse(e, requestId);
+        }
+    }
+
+    /**
+     * create a Instantiation Response from an exception.
+     * @param e the error
+     * @param requestId request ID used in ONAP logging
+     * @return the Instantiation Response
+     */
+    private Response createInstantiationErrorResponse(ErrorResponseInfo e, UUID requestId) {
+        InstantiationResponse resp = new InstantiationResponse();
+        resp.setErrorDetails(e.getErrorResponse().getErrorMessage());
+        return addLoggingHeaders(addVersionControlHeaders(Response.status(e.getErrorResponse().getResponseCode())),
+            requestId).entity(resp).build();
+    }
+}
+
diff --git a/runtime-controlloop/src/main/java/org/onap/policy/clamp/controlloop/runtime/main/parameters/ClRuntimeParameterGroup.java b/runtime-controlloop/src/main/java/org/onap/policy/clamp/controlloop/runtime/main/parameters/ClRuntimeParameterGroup.java
new file mode 100644
index 0000000..4c99b8e
--- /dev/null
+++ b/runtime-controlloop/src/main/java/org/onap/policy/clamp/controlloop/runtime/main/parameters/ClRuntimeParameterGroup.java
@@ -0,0 +1,55 @@
+/*-
+ * ============LICENSE_START=======================================================
+ *  Copyright (C) 2021 Nordix Foundation.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.policy.clamp.controlloop.runtime.main.parameters;
+
+import java.util.List;
+import javax.validation.constraints.NotBlank;
+import lombok.Getter;
+import org.onap.policy.common.endpoints.event.comm.bus.internal.BusTopicParams;
+import org.onap.policy.common.endpoints.parameters.RestServerParameters;
+import org.onap.policy.common.endpoints.parameters.TopicParameterGroup;
+import org.onap.policy.common.parameters.ParameterGroupImpl;
+import org.onap.policy.common.parameters.annotations.NotNull;
+import org.onap.policy.models.provider.PolicyModelsProviderParameters;
+
+/**
+ * Class to hold all parameters needed for the Control Loop runtime component.
+ *
+ */
+@NotNull
+@NotBlank
+@Getter
+public class ClRuntimeParameterGroup extends ParameterGroupImpl {
+    private RestServerParameters restServerParameters;
+    private PolicyModelsProviderParameters databaseProviderParameters;
+    private ParticipantParameters participantParameters;
+    private TopicParameterGroup topicParameterGroup;
+    private List<BusTopicParams> healthCheckRestClientParameters;
+
+    /**
+     * Create the Control Loop parameter group.
+     *
+     * @param name the parameter group name
+     */
+    public ClRuntimeParameterGroup(final String name) {
+        super(name);
+    }
+}
diff --git a/runtime-controlloop/src/main/java/org/onap/policy/clamp/controlloop/runtime/main/parameters/ClRuntimeParameterHandler.java b/runtime-controlloop/src/main/java/org/onap/policy/clamp/controlloop/runtime/main/parameters/ClRuntimeParameterHandler.java
new file mode 100644
index 0000000..a463ad1
--- /dev/null
+++ b/runtime-controlloop/src/main/java/org/onap/policy/clamp/controlloop/runtime/main/parameters/ClRuntimeParameterHandler.java
@@ -0,0 +1,77 @@
+/*-
+ * ============LICENSE_START=======================================================
+ *  Copyright (C) 2021 Nordix Foundation.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.policy.clamp.controlloop.runtime.main.parameters;
+
+import java.io.File;
+import javax.ws.rs.core.Response;
+import org.onap.policy.clamp.controlloop.common.exception.ControlLoopException;
+import org.onap.policy.clamp.controlloop.runtime.main.startstop.ClRuntimeCommandLineArguments;
+import org.onap.policy.common.parameters.ValidationResult;
+import org.onap.policy.common.utils.coder.Coder;
+import org.onap.policy.common.utils.coder.CoderException;
+import org.onap.policy.common.utils.coder.StandardCoder;
+
+/**
+ * This class handles reading, parsing and validating of control loop runtime parameters from JSON files.
+ */
+public class ClRuntimeParameterHandler {
+
+    private static final Coder CODER = new StandardCoder();
+
+    /**
+     * Read the parameters from the parameter file.
+     *
+     * @param arguments the arguments passed to control loop runtime
+     * @return the parameters read from the configuration file
+     * @throws ControlLoopException on parameter exceptions
+     */
+    public ClRuntimeParameterGroup getParameters(final ClRuntimeCommandLineArguments arguments)
+            throws ControlLoopException {
+        ClRuntimeParameterGroup clRuntimeParameterGroup = null;
+
+        // Read the parameters
+        try {
+            // Read the parameters from JSON
+            File file = new File(arguments.getFullConfigurationFilePath());
+            clRuntimeParameterGroup = CODER.decode(file, ClRuntimeParameterGroup.class);
+        } catch (final CoderException e) {
+            throw new ControlLoopException(
+                    Response.Status.NOT_ACCEPTABLE, "error reading parameters from \""
+                            + arguments.getConfigurationFilePath() + "\"\n" + "(" + e.getClass().getSimpleName() + ")",
+                    e);
+        }
+
+        // The JSON processing returns null if there is an empty file
+        if (clRuntimeParameterGroup == null) {
+            throw new ControlLoopException(Response.Status.NOT_ACCEPTABLE,
+                    "no parameters found in \"" + arguments.getConfigurationFilePath() + "\"");
+        }
+
+        // validate the parameters
+        final ValidationResult validationResult = clRuntimeParameterGroup.validate();
+        if (!validationResult.isValid()) {
+            throw new ControlLoopException(Response.Status.NOT_ACCEPTABLE, "validation error(s) on parameters from \""
+                    + arguments.getConfigurationFilePath() + "\"\n" + validationResult.getResult());
+        }
+
+        return clRuntimeParameterGroup;
+    }
+}
diff --git a/runtime-controlloop/src/main/java/org/onap/policy/clamp/controlloop/runtime/main/parameters/ParticipantParameters.java b/runtime-controlloop/src/main/java/org/onap/policy/clamp/controlloop/runtime/main/parameters/ParticipantParameters.java
new file mode 100644
index 0000000..dfc1b28
--- /dev/null
+++ b/runtime-controlloop/src/main/java/org/onap/policy/clamp/controlloop/runtime/main/parameters/ParticipantParameters.java
@@ -0,0 +1,59 @@
+/*-
+ * ============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.controlloop.runtime.main.parameters;
+
+import java.util.concurrent.TimeUnit;
+import lombok.Getter;
+import org.onap.policy.common.parameters.ParameterGroupImpl;
+import org.onap.policy.common.parameters.annotations.Min;
+import org.onap.policy.common.parameters.annotations.NotBlank;
+import org.onap.policy.common.parameters.annotations.NotNull;
+
+/**
+ * Parameters for communicating with participants.
+ */
+@NotNull
+@NotBlank
+@Getter
+public class ParticipantParameters extends ParameterGroupImpl {
+
+    /**
+     * Default maximum message age, in milliseconds, that should be examined. Any message
+     * older than this is discarded.
+     */
+    public static final long DEFAULT_MAX_AGE_MS = TimeUnit.MILLISECONDS.convert(10, TimeUnit.MINUTES);
+
+
+    @Min(1)
+    private long heartBeatMs;
+
+    @Min(1)
+    private long maxMessageAgeMs =  DEFAULT_MAX_AGE_MS;
+
+    private ParticipantUpdateParameters updateParameters;
+    private ParticipantStateChangeParameters stateChangeParameters;
+
+
+    /**
+     * Constructs the object.
+     */
+    public ParticipantParameters() {
+        super(ParticipantParameters.class.getSimpleName());
+    }
+}
diff --git a/runtime-controlloop/src/main/java/org/onap/policy/clamp/controlloop/runtime/main/parameters/ParticipantStateChangeParameters.java b/runtime-controlloop/src/main/java/org/onap/policy/clamp/controlloop/runtime/main/parameters/ParticipantStateChangeParameters.java
new file mode 100644
index 0000000..2eea4ab
--- /dev/null
+++ b/runtime-controlloop/src/main/java/org/onap/policy/clamp/controlloop/runtime/main/parameters/ParticipantStateChangeParameters.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.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.policy.clamp.controlloop.runtime.main.parameters;
+
+import lombok.Getter;
+import org.onap.policy.common.parameters.ParameterGroupImpl;
+import org.onap.policy.common.parameters.annotations.Min;
+import org.onap.policy.common.parameters.annotations.NotBlank;
+import org.onap.policy.common.parameters.annotations.NotNull;
+
+/**
+ * Parameters for Participant STATE-CHANGE requests.
+ */
+@NotNull
+@NotBlank
+@Getter
+public class ParticipantStateChangeParameters extends ParameterGroupImpl {
+
+    /**
+     * Maximum number of times to re-send a request to a PDP.
+     */
+    @Min(value = 0)
+    private int maxRetryCount;
+
+    /**
+     * Maximum time to wait, in milliseconds, for a PDP response.
+     */
+    @Min(value = 0)
+    private long maxWaitMs;
+
+    /**
+     * Constructs the object.
+     */
+    public ParticipantStateChangeParameters() {
+        super(ParticipantStateChangeParameters.class.getSimpleName());
+    }
+}
diff --git a/runtime-controlloop/src/main/java/org/onap/policy/clamp/controlloop/runtime/main/parameters/ParticipantUpdateParameters.java b/runtime-controlloop/src/main/java/org/onap/policy/clamp/controlloop/runtime/main/parameters/ParticipantUpdateParameters.java
new file mode 100644
index 0000000..2af5be5
--- /dev/null
+++ b/runtime-controlloop/src/main/java/org/onap/policy/clamp/controlloop/runtime/main/parameters/ParticipantUpdateParameters.java
@@ -0,0 +1,54 @@
+/*
+ * ============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.controlloop.runtime.main.parameters;
+
+import lombok.Getter;
+import org.onap.policy.common.parameters.ParameterGroupImpl;
+import org.onap.policy.common.parameters.annotations.Min;
+import org.onap.policy.common.parameters.annotations.NotBlank;
+import org.onap.policy.common.parameters.annotations.NotNull;
+
+/**
+ * Parameters for Participant UPDATE requests.
+ */
+@NotNull
+@NotBlank
+@Getter
+public class ParticipantUpdateParameters extends ParameterGroupImpl {
+
+    /**
+     * Maximum number of times to re-send a request to a PDP.
+     */
+    @Min(value = 0)
+    private int maxRetryCount;
+
+    /**
+     * Maximum time to wait, in milliseconds, for a PDP response.
+     */
+    @Min(value = 0)
+    private long maxWaitMs;
+
+    /**
+     * Constructs the object.
+     */
+    public ParticipantUpdateParameters() {
+        super(ParticipantUpdateParameters.class.getSimpleName());
+    }
+}
+
diff --git a/runtime-controlloop/src/main/java/org/onap/policy/clamp/controlloop/runtime/main/rest/ControlLoopAafFilter.java b/runtime-controlloop/src/main/java/org/onap/policy/clamp/controlloop/runtime/main/rest/ControlLoopAafFilter.java
new file mode 100644
index 0000000..f166de5
--- /dev/null
+++ b/runtime-controlloop/src/main/java/org/onap/policy/clamp/controlloop/runtime/main/rest/ControlLoopAafFilter.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.controlloop.runtime.main.rest;
+
+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 control loop runtime component.
+ */
+public class ControlLoopAafFilter 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-controlloop/src/main/java/org/onap/policy/clamp/controlloop/runtime/main/rest/RestController.java b/runtime-controlloop/src/main/java/org/onap/policy/clamp/controlloop/runtime/main/rest/RestController.java
new file mode 100644
index 0000000..dd3fa30
--- /dev/null
+++ b/runtime-controlloop/src/main/java/org/onap/policy/clamp/controlloop/runtime/main/rest/RestController.java
@@ -0,0 +1,115 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * Copyright (C) 2021 Nordix Foundation.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.policy.clamp.controlloop.runtime.main.rest;
+
+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 java.util.UUID;
+import javax.ws.rs.Path;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response.ResponseBuilder;
+
+/**
+ * Common superclass to provide REST endpoints for the control loop service.
+ */
+// @formatter:off
+@Path("/onap/controlloop/v2")
+@Api(value = "Control Loop API")
+@Produces({MediaType.APPLICATION_JSON, RestController.APPLICATION_YAML})
+@SwaggerDefinition(
+    info = @Info(description =
+                    "Control Loop Service", version = "v1.0",
+                    title = "Control Loop"),
+    consumes = {MediaType.APPLICATION_JSON, RestController.APPLICATION_YAML},
+    produces = {MediaType.APPLICATION_JSON, RestController.APPLICATION_YAML},
+    schemes = {SwaggerDefinition.Scheme.HTTP, SwaggerDefinition.Scheme.HTTPS},
+    tags = {@Tag(name = "controlloop", description = "Control Loop Service")},
+    securityDefinition = @SecurityDefinition(basicAuthDefinitions = {@BasicAuthDefinition(key = "basicAuth")}))
+// @formatter:on
+public class RestController {
+    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 = "Dublin";
+
+    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";
+
+    /**
+     * Adds version headers to the response.
+     *
+     * @param respBuilder response builder
+     * @return the response builder, with version headers
+     */
+    public ResponseBuilder addVersionControlHeaders(ResponseBuilder respBuilder) {
+        return respBuilder.header(VERSION_MINOR_NAME, "0").header(VERSION_PATCH_NAME, "0").header(VERSION_LATEST_NAME,
+                        API_VERSION);
+    }
+
+    /**
+     * Adds logging headers to the response.
+     *
+     * @param respBuilder response builder
+     * @return the response builder, with version logging
+     */
+    public ResponseBuilder addLoggingHeaders(ResponseBuilder respBuilder, UUID requestId) {
+        if (requestId == null) {
+            // Generate a random uuid if client does not embed requestId in rest request
+            return respBuilder.header(REQUEST_ID_NAME, UUID.randomUUID());
+        }
+
+        return respBuilder.header(REQUEST_ID_NAME, requestId);
+    }
+}
diff --git a/runtime-controlloop/src/main/java/org/onap/policy/clamp/controlloop/runtime/main/startstop/ClRuntimeActivator.java b/runtime-controlloop/src/main/java/org/onap/policy/clamp/controlloop/runtime/main/startstop/ClRuntimeActivator.java
new file mode 100644
index 0000000..a4238a9
--- /dev/null
+++ b/runtime-controlloop/src/main/java/org/onap/policy/clamp/controlloop/runtime/main/startstop/ClRuntimeActivator.java
@@ -0,0 +1,186 @@
+/*-
+ * ============LICENSE_START=======================================================
+ *  Copyright (C) 2021 Nordix Foundation.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.policy.clamp.controlloop.runtime.main.startstop;
+
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+import java.util.concurrent.atomic.AtomicReference;
+import javax.ws.rs.core.Response.Status;
+import org.onap.policy.clamp.controlloop.common.exception.ControlLoopRuntimeException;
+import org.onap.policy.clamp.controlloop.common.handler.ControlLoopHandler;
+import org.onap.policy.clamp.controlloop.runtime.commissioning.CommissioningHandler;
+import org.onap.policy.clamp.controlloop.runtime.instantiation.InstantiationHandler;
+import org.onap.policy.clamp.controlloop.runtime.main.parameters.ClRuntimeParameterGroup;
+import org.onap.policy.clamp.controlloop.runtime.main.rest.ControlLoopAafFilter;
+import org.onap.policy.clamp.controlloop.runtime.monitoring.MonitoringHandler;
+import org.onap.policy.clamp.controlloop.runtime.supervision.SupervisionHandler;
+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.http.server.RestServer;
+import org.onap.policy.common.endpoints.listeners.MessageTypeDispatcher;
+import org.onap.policy.common.parameters.ParameterService;
+import org.onap.policy.common.utils.services.ServiceManagerContainer;
+
+/**
+ * This class activates the control loop runtime component as a complete service together with all its controllers,
+ * listeners & handlers.
+ */
+public class ClRuntimeActivator extends ServiceManagerContainer {
+    // Name of the message type for messages on topics
+    private static final String[] MSG_TYPE_NAMES = {"messageType"};
+
+    private final ClRuntimeParameterGroup clRuntimeParameterGroup;
+
+    // Topics from which the application receives and to which the application sends messages
+    private List<TopicSink> topicSinks;
+    private List<TopicSource> topicSources;
+
+    /**
+     * Listens for messages on the topic, decodes them into a message, and then dispatches them.
+     */
+    private final MessageTypeDispatcher msgDispatcher;
+
+    /**
+     * Instantiate the activator for the control loop runtime as a complete service.
+     *
+     * @param clRuntimeParameterGroup the parameters for the control loop runtime service
+     */
+    public ClRuntimeActivator(final ClRuntimeParameterGroup clRuntimeParameterGroup) {
+
+        if (clRuntimeParameterGroup == null || !clRuntimeParameterGroup.isValid()) {
+            throw new ControlLoopRuntimeException(Status.INTERNAL_SERVER_ERROR, "ParameterGroup not valid");
+        }
+
+        this.clRuntimeParameterGroup = clRuntimeParameterGroup;
+
+        topicSinks = TopicEndpointManager.getManager()
+                .addTopicSinks(clRuntimeParameterGroup.getTopicParameterGroup().getTopicSinks());
+
+        topicSources = TopicEndpointManager.getManager()
+                .addTopicSources(clRuntimeParameterGroup.getTopicParameterGroup().getTopicSources());
+
+        try {
+            msgDispatcher = new MessageTypeDispatcher(MSG_TYPE_NAMES);
+        } catch (final RuntimeException e) {
+            throw new ControlLoopRuntimeException(Status.INTERNAL_SERVER_ERROR,
+                    "topic message dispatcher failed to start", e);
+        }
+
+        final AtomicReference<ControlLoopHandler> commissioningHandler = new AtomicReference<>();
+        final AtomicReference<ControlLoopHandler> instantiationHandler = new AtomicReference<>();
+        final AtomicReference<ControlLoopHandler> supervisionHandler = new AtomicReference<>();
+        final AtomicReference<ControlLoopHandler> monitoringHandler = new AtomicReference<>();
+        final AtomicReference<RestServer> restServer = new AtomicReference<>();
+
+        // @formatter:off
+        addAction("Control loop runtime parameters",
+            () -> ParameterService.register(clRuntimeParameterGroup),
+            () -> ParameterService.deregister(clRuntimeParameterGroup.getName()));
+
+        addAction("Topic endpoint management",
+            () -> TopicEndpointManager.getManager().start(),
+            () -> TopicEndpointManager.getManager().shutdown());
+
+        addAction("Commissioning Handler",
+                () -> commissioningHandler.set(new CommissioningHandler(clRuntimeParameterGroup)),
+                () -> commissioningHandler.get().close());
+
+        addAction("Instantiation Handler",
+            () -> instantiationHandler.set(new InstantiationHandler(clRuntimeParameterGroup)),
+            () -> instantiationHandler.get().close());
+
+        addAction("Supervision Handler",
+            () -> supervisionHandler.set(new SupervisionHandler(clRuntimeParameterGroup)),
+            () -> supervisionHandler.get().close());
+
+        addAction("Monitoring Handler",
+            () -> monitoringHandler.set(new MonitoringHandler(clRuntimeParameterGroup)),
+            () -> monitoringHandler.get().close());
+
+        addHandlerActions("Commissioning", commissioningHandler);
+        addHandlerActions("Instantiation", instantiationHandler);
+        addHandlerActions("Supervision", supervisionHandler);
+        addHandlerActions("Monitoring", monitoringHandler);
+
+        addAction("Topic Message Dispatcher", this::registerMsgDispatcher, this::unregisterMsgDispatcher);
+
+        clRuntimeParameterGroup.getRestServerParameters().setName(clRuntimeParameterGroup.getName());
+
+        addAction("REST server",
+            () -> {
+                Set<Class<?>> providerClasses = new HashSet<>();
+                providerClasses.addAll(commissioningHandler.get().getProviderClasses());
+                providerClasses.addAll(instantiationHandler.get().getProviderClasses());
+                providerClasses.addAll(supervisionHandler.get().getProviderClasses());
+                providerClasses.addAll(monitoringHandler.get().getProviderClasses());
+
+                RestServer server = new RestServer(clRuntimeParameterGroup.getRestServerParameters(),
+                        ControlLoopAafFilter.class,
+                        providerClasses.toArray(new Class<?>[providerClasses.size()]));
+
+                restServer.set(server);
+                restServer.get().start();
+            },
+            () -> restServer.get().stop());
+        // @formatter:on
+    }
+
+    private void addHandlerActions(final String name, final AtomicReference<ControlLoopHandler> handler) {
+        addAction(name + " Providers",
+            () -> handler.get().startProviders(),
+            () -> handler.get().stopProviders());
+        addAction(name + " Listeners",
+            () -> handler.get().startAndRegisterListeners(msgDispatcher),
+            () -> handler.get().stopAndUnregisterListeners(msgDispatcher));
+        addAction(name + " Publishers",
+            () -> handler.get().startAndRegisterPublishers(topicSinks),
+            () -> handler.get().stopAndUnregisterPublishers());
+    }
+
+    /**
+     * 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);
+        }
+    }
+
+    /**
+     * Get the parameters used by the activator.
+     *
+     * @return the parameters of the activator
+     */
+    public ClRuntimeParameterGroup getParameterGroup() {
+        return clRuntimeParameterGroup;
+    }
+}
diff --git a/runtime-controlloop/src/main/java/org/onap/policy/clamp/controlloop/runtime/main/startstop/ClRuntimeCommandLineArguments.java b/runtime-controlloop/src/main/java/org/onap/policy/clamp/controlloop/runtime/main/startstop/ClRuntimeCommandLineArguments.java
new file mode 100644
index 0000000..f36bb85
--- /dev/null
+++ b/runtime-controlloop/src/main/java/org/onap/policy/clamp/controlloop/runtime/main/startstop/ClRuntimeCommandLineArguments.java
@@ -0,0 +1,151 @@
+/*-
+ * ============LICENSE_START=======================================================
+ *  Copyright (C) 2021 Nordix Foundation.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.policy.clamp.controlloop.runtime.main.startstop;
+
+import java.io.File;
+import java.io.PrintWriter;
+import java.io.StringWriter;
+import java.net.URL;
+import java.util.Arrays;
+import javax.ws.rs.core.Response;
+import lombok.Getter;
+import lombok.Setter;
+import org.apache.commons.cli.CommandLine;
+import org.apache.commons.cli.DefaultParser;
+import org.apache.commons.cli.HelpFormatter;
+import org.apache.commons.cli.Option;
+import org.apache.commons.cli.Options;
+import org.apache.commons.cli.ParseException;
+import org.apache.commons.lang3.StringUtils;
+import org.onap.policy.clamp.controlloop.common.exception.ControlLoopException;
+import org.onap.policy.clamp.controlloop.common.exception.ControlLoopRuntimeException;
+import org.onap.policy.clamp.controlloop.common.startstop.CommonCommandLineArguments;
+import org.onap.policy.common.utils.resources.ResourceUtils;
+
+/**
+ * This class reads and handles command line parameters for the control loop runtime service.
+ */
+public class ClRuntimeCommandLineArguments {
+    private static final String FILE_MESSAGE_PREAMBLE = " file \"";
+    private static final int HELP_LINE_LENGTH = 120;
+
+    private final Options options;
+    private final CommonCommandLineArguments commonCommandLineArguments;
+
+    @Getter()
+    @Setter()
+    private String configurationFilePath = null;
+
+    /**
+     * Construct the options for the control loop runtime component.
+     */
+    public ClRuntimeCommandLineArguments() {
+        options = new Options();
+        commonCommandLineArguments = new CommonCommandLineArguments(options);
+    }
+
+    /**
+     * Construct the options for the CLI editor and parse in the given arguments.
+     *
+     * @param args The command line arguments
+     */
+    public ClRuntimeCommandLineArguments(final String[] args) {
+        // Set up the options with the default constructor
+        this();
+
+        // Parse the arguments
+        try {
+            parse(args);
+        } catch (final ControlLoopException e) {
+            throw new ControlLoopRuntimeException(Response.Status.NOT_ACCEPTABLE,
+                    "parse error on control loop runtime parameters", e);
+        }
+    }
+
+    /**
+     * Parse the command line options.
+     *
+     * @param args The command line arguments
+     * @return a string with a message for help and version, or null if there is no message
+     * @throws ControlLoopException on command argument errors
+     */
+    public String parse(final String[] args) throws ControlLoopException {
+        // Clear all our arguments
+        setConfigurationFilePath(null);
+        CommandLine commandLine = null;
+        try {
+            commandLine = new DefaultParser().parse(options, args);
+        } catch (final ParseException e) {
+            throw new ControlLoopException(Response.Status.NOT_ACCEPTABLE,
+                    "invalid command line arguments specified : " + e.getMessage());
+        }
+
+        // Arguments left over after Commons CLI does its stuff
+        final String[] remainingArgs = commandLine.getArgs();
+
+        if (remainingArgs.length > 0) {
+            throw new ControlLoopException(Response.Status.NOT_ACCEPTABLE,
+                    "too many command line arguments specified : " + Arrays.toString(args));
+        }
+
+        if (commandLine.hasOption('h')) {
+            return commonCommandLineArguments.help(Main.class.getName(), options);
+        }
+
+        if (commandLine.hasOption('v')) {
+            return commonCommandLineArguments.version();
+        }
+
+        if (commandLine.hasOption('c')) {
+            setConfigurationFilePath(commandLine.getOptionValue('c'));
+        }
+
+        return null;
+    }
+
+    /**
+     * Validate the command line options.
+     *
+     * @throws ControlLoopException on command argument validation errors
+     */
+    public void validate() throws ControlLoopException {
+        commonCommandLineArguments.validate(configurationFilePath);
+    }
+
+    /**
+     * Gets the full expanded configuration file path.
+     *
+     * @return the configuration file path
+     */
+    public String getFullConfigurationFilePath() {
+        return ResourceUtils.getFilePath4Resource(getConfigurationFilePath());
+    }
+
+    /**
+     * Sets the configuration file path.
+     *
+     * @param configurationFilePath the configuration file path
+     */
+    public void setConfigurationFilePath(final String configurationFilePath) {
+        this.configurationFilePath = configurationFilePath;
+
+    }
+}
diff --git a/runtime-controlloop/src/main/java/org/onap/policy/clamp/controlloop/runtime/main/startstop/Main.java b/runtime-controlloop/src/main/java/org/onap/policy/clamp/controlloop/runtime/main/startstop/Main.java
new file mode 100644
index 0000000..8e60d68
--- /dev/null
+++ b/runtime-controlloop/src/main/java/org/onap/policy/clamp/controlloop/runtime/main/startstop/Main.java
@@ -0,0 +1,156 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * Copyright (C) 2021 Nordix Foundation.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.policy.clamp.controlloop.runtime.main.startstop;
+
+import java.util.Arrays;
+import javax.ws.rs.core.Response;
+import org.onap.policy.clamp.controlloop.common.ControlLoopConstants;
+import org.onap.policy.clamp.controlloop.common.exception.ControlLoopException;
+import org.onap.policy.clamp.controlloop.common.exception.ControlLoopRuntimeException;
+import org.onap.policy.clamp.controlloop.runtime.main.parameters.ClRuntimeParameterGroup;
+import org.onap.policy.clamp.controlloop.runtime.main.parameters.ClRuntimeParameterHandler;
+import org.onap.policy.common.utils.resources.MessageConstants;
+import org.onap.policy.common.utils.services.Registry;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * This class initiates ONAP Policy Framework Control Loop runtime component.
+ */
+public class Main {
+
+    private static final Logger LOGGER = LoggerFactory.getLogger(Main.class);
+
+    private ClRuntimeActivator activator;
+    private ClRuntimeParameterGroup parameterGroup;
+
+    /**
+     * Instantiates the control loop runtime service.
+     *
+     * @param args the command line arguments
+     */
+    public Main(final String[] args) {
+        final String argumentString = Arrays.toString(args);
+        LOGGER.info("Starting the control loop runtime service with arguments - {}", argumentString);
+
+        // Check the arguments
+        final ClRuntimeCommandLineArguments arguments = new ClRuntimeCommandLineArguments();
+        try {
+            // The arguments return a string if there is a message to print and we should exit
+            final String argumentMessage = arguments.parse(args);
+            if (argumentMessage != null) {
+                LOGGER.info(argumentMessage);
+                return;
+            }
+            // Validate that the arguments are sane
+            arguments.validate();
+
+            // Read the parameters
+            parameterGroup = new ClRuntimeParameterHandler().getParameters(arguments);
+
+            // Now, create the activator for the service
+            activator = new ClRuntimeActivator(parameterGroup);
+            Registry.register(ControlLoopConstants.REG_CLRUNTIME_ACTIVATOR, activator);
+
+            // Start the activator
+            activator.start();
+        } catch (Exception exp) {
+            if (null != activator) {
+                Registry.unregister(ControlLoopConstants.REG_CLRUNTIME_ACTIVATOR);
+            }
+            throw new ControlLoopRuntimeException(Response.Status.BAD_REQUEST,
+                String.format(MessageConstants.START_FAILURE_MSG, MessageConstants.POLICY_CLAMP), exp);
+        }
+
+        // Add a shutdown hook to shut everything down in an orderly manner
+        Runtime.getRuntime().addShutdownHook(new ClRuntimeShutdownHookClass());
+        String successMsg = String.format(MessageConstants.START_SUCCESS_MSG, MessageConstants.POLICY_CLAMP);
+        LOGGER.info(successMsg);
+    }
+
+    /**
+     * Check if main is running.
+     */
+    public boolean isRunning() {
+        return activator != null && activator.isAlive();
+    }
+
+    /**
+     * Get the parameters specified in JSON.
+     *
+     * @return the parameters
+     */
+    public ClRuntimeParameterGroup getParameters() {
+        return parameterGroup;
+    }
+
+    /**
+     * Shut down Execution.
+     *
+     * @throws ControlLoopException on shutdown errors
+     */
+    public void shutdown() throws ControlLoopException {
+        // clear the parameterGroup variable
+        parameterGroup = null;
+
+        // clear the cl runtime activator
+        if (activator != null) {
+            activator.stop();
+        }
+    }
+
+    /**
+     * The Class ClRuntimeShutdownHookClass terminates the control loop runtime service when its run method is called.
+     */
+    private class ClRuntimeShutdownHookClass extends Thread {
+        /*
+         * (non-Javadoc)
+         *
+         * @see java.lang.Runnable#run()
+         */
+        @Override
+        public void run() {
+            if (!activator.isAlive()) {
+                return;
+            }
+
+            try {
+                // Shutdown the control loop runtime service and wait for everything to stop
+                activator.stop();
+            } catch (final RuntimeException e) {
+                LOGGER.warn("error occured during shut down of the control loop runtime service", e);
+            }
+        }
+    }
+
+    /**
+     * The main method.
+     *
+     * @param args the arguments
+     */
+    public static void main(final String[] args) {      // NOSONAR
+        /*
+         * NOTE: arguments are validated by the constructor, thus sonar is disabled.
+         */
+
+        new Main(args);
+    }
+}
diff --git a/runtime-controlloop/src/main/java/org/onap/policy/clamp/controlloop/runtime/monitoring/MonitoringHandler.java b/runtime-controlloop/src/main/java/org/onap/policy/clamp/controlloop/runtime/monitoring/MonitoringHandler.java
new file mode 100644
index 0000000..a7ad918
--- /dev/null
+++ b/runtime-controlloop/src/main/java/org/onap/policy/clamp/controlloop/runtime/monitoring/MonitoringHandler.java
@@ -0,0 +1,84 @@
+/*-
+ * ============LICENSE_START=======================================================
+ *  Copyright (C) 2021 Nordix Foundation.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.policy.clamp.controlloop.runtime.monitoring;
+
+import java.io.IOException;
+import java.util.List;
+import java.util.Set;
+import javax.ws.rs.core.Response;
+import lombok.Getter;
+import org.onap.policy.clamp.controlloop.common.handler.ControlLoopHandler;
+import org.onap.policy.clamp.controlloop.runtime.main.parameters.ClRuntimeParameterGroup;
+import org.onap.policy.clamp.controlloop.runtime.monitoring.rest.MonitoringQueryController;
+import org.onap.policy.common.endpoints.event.comm.TopicSink;
+import org.onap.policy.common.endpoints.listeners.MessageTypeDispatcher;
+import org.onap.policy.common.utils.services.Registry;
+import org.onap.policy.models.base.PfModelRuntimeException;
+
+/**
+ * This class handles monitoring of control loop definitions,
+ * 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.
+ */
+public class MonitoringHandler extends ControlLoopHandler {
+
+    @Getter
+    private MonitoringProvider monitoringProvider;
+
+    /**
+     * Gets the Monitoring Handler.
+     *
+     * @return MonitoringHandler
+     */
+    public static MonitoringHandler getInstance() {
+        return Registry.get(MonitoringHandler.class.getName());
+    }
+
+    /**
+     * Create a handler.
+     *
+     * @param controlLoopParameters the parameters for access to the database
+     */
+    public MonitoringHandler(ClRuntimeParameterGroup controlLoopParameters) {
+        super(controlLoopParameters.getDatabaseProviderParameters());
+    }
+
+    @Override
+    public Set<Class<?>> getProviderClasses() {
+        return Set.of(MonitoringQueryController.class);
+    }
+
+    @Override
+    public void startProviders() {
+        monitoringProvider = new MonitoringProvider(getDatabaseProviderParameters());
+    }
+
+    @Override
+    public void stopProviders() {
+        try {
+            monitoringProvider.close();
+        } catch (IOException e) {
+            throw new PfModelRuntimeException(Response.Status.INTERNAL_SERVER_ERROR, "Cannot stop provider", e);
+        }
+    }
+}
diff --git a/runtime-controlloop/src/main/java/org/onap/policy/clamp/controlloop/runtime/monitoring/MonitoringProvider.java b/runtime-controlloop/src/main/java/org/onap/policy/clamp/controlloop/runtime/monitoring/MonitoringProvider.java
new file mode 100644
index 0000000..193f8d5
--- /dev/null
+++ b/runtime-controlloop/src/main/java/org/onap/policy/clamp/controlloop/runtime/monitoring/MonitoringProvider.java
@@ -0,0 +1,273 @@
+/*-
+ * ============LICENSE_START=======================================================
+ *  Copyright (C) 2021 Nordix Foundation.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.policy.clamp.controlloop.runtime.monitoring;
+
+import java.io.Closeable;
+import java.io.IOException;
+import java.time.Instant;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import lombok.NonNull;
+import org.onap.policy.clamp.controlloop.models.controlloop.concepts.ClElementStatistics;
+import org.onap.policy.clamp.controlloop.models.controlloop.concepts.ClElementStatisticsList;
+import org.onap.policy.clamp.controlloop.models.controlloop.concepts.ControlLoop;
+import org.onap.policy.clamp.controlloop.models.controlloop.concepts.ControlLoopElement;
+import org.onap.policy.clamp.controlloop.models.controlloop.concepts.ParticipantStatistics;
+import org.onap.policy.clamp.controlloop.models.controlloop.concepts.ParticipantStatisticsList;
+import org.onap.policy.clamp.controlloop.models.controlloop.persistence.provider.ClElementStatisticsProvider;
+import org.onap.policy.clamp.controlloop.models.controlloop.persistence.provider.ControlLoopProvider;
+import org.onap.policy.clamp.controlloop.models.controlloop.persistence.provider.ParticipantStatisticsProvider;
+import org.onap.policy.models.base.PfModelException;
+import org.onap.policy.models.base.PfModelRuntimeException;
+import org.onap.policy.models.provider.PolicyModelsProviderParameters;
+import org.onap.policy.models.tosca.authorative.concepts.ToscaConceptIdentifier;
+
+/**
+ * This class provides information about statistics data of CL elements and CL Participants in database to callers.
+ */
+public class MonitoringProvider implements Closeable {
+
+    private static final String DESC_ORDER = "DESC";
+    private final ParticipantStatisticsProvider participantStatisticsProvider;
+    private final ClElementStatisticsProvider clElementStatisticsProvider;
+    private final ControlLoopProvider controlLoopProvider;
+
+    /**
+     * Create a Monitoring provider.
+     *
+     */
+    public MonitoringProvider(PolicyModelsProviderParameters parameters) {
+
+        try {
+            participantStatisticsProvider = new ParticipantStatisticsProvider(parameters);
+            clElementStatisticsProvider = new ClElementStatisticsProvider(parameters);
+            controlLoopProvider = new ControlLoopProvider(parameters);
+        } catch (PfModelException e) {
+            throw new PfModelRuntimeException(e);
+        }
+    }
+
+    @Override
+    public void close() throws IOException {
+        controlLoopProvider.close();
+        clElementStatisticsProvider.close();
+        participantStatisticsProvider.close();
+    }
+
+    /**
+     * 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 {
+        ParticipantStatisticsList participantStatisticsList = new ParticipantStatisticsList();
+        participantStatisticsList.setStatisticsList(participantStatisticsProvider
+            .createParticipantStatistics(participantStatistics));
+
+        return participantStatisticsList;
+    }
+
+    /**
+     * Create clElement statistics.
+     *
+     * @param clElementStatisticsList the clElement statistics
+     * @return the result of create operation
+     * @throws PfModelException on creation errors
+     */
+    public ClElementStatisticsList createClElementStatistics(List<ClElementStatistics> clElementStatisticsList)
+        throws PfModelException {
+        ClElementStatisticsList elementStatisticsList = new ClElementStatisticsList();
+        elementStatisticsList.setClElementStatistics(clElementStatisticsProvider
+            .createClElementStatistics(clElementStatisticsList));
+
+        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
+     */
+    public ParticipantStatisticsList fetchFilteredParticipantStatistics(@NonNull final String name,
+                                                                        final String version, int recordCount,
+                                                                        Instant startTime, Instant endTime)  {
+        ParticipantStatisticsList 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 control loop.     *
+     *
+     * @param controlLoopName name of the control loop
+     * @param controlLoopVersion version of the control loop
+     * @return All the participant statistics found
+     * @throws PfModelException on errors getting participant statistics
+     */
+    public ParticipantStatisticsList fetchParticipantStatsPerControlLoop(@NonNull final String controlLoopName,
+                                                                         @NonNull final String controlLoopVersion)
+        throws PfModelException {
+        ParticipantStatisticsList statisticsList = new ParticipantStatisticsList();
+        List<ParticipantStatistics> participantStatistics = new ArrayList<>();
+        try {
+            //Fetch all participantIds for a specific control loop
+            List<ToscaConceptIdentifier> participantIds = getAllParticipantIdsPerControlLoop(controlLoopName,
+                controlLoopVersion);
+            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 clElement statistics based on specific filters.
+     *
+     * @param name the name of the clElement statistics to get, null to get all statistics
+     * @param version the version of the clElement statistics to get, null to get all statistics
+     * @param id UUID of the control loop 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 control loop statistics
+     */
+    public ClElementStatisticsList fetchFilteredClElementStatistics(@NonNull final String name, final String version,
+                                                                    final String id, Instant startTime, Instant endTime,
+                                                                    int recordCount) throws PfModelException {
+        ClElementStatisticsList clElementStatisticsList = new ClElementStatisticsList();
+        Map<String, Object> filterMap = new HashMap<>();
+        //Adding UUID in filter if present
+        if (id != null) {
+            filterMap.put("localName", id);
+        }
+        clElementStatisticsList.setClElementStatistics(clElementStatisticsProvider.getFilteredClElementStatistics(
+            name, version, startTime, endTime, filterMap, DESC_ORDER, recordCount));
+
+        return clElementStatisticsList;
+    }
+
+
+    /**
+     * Get clElement statistics per control loop.
+     *
+     * @param name the name of the control loop
+     * @param version the version of the control loop
+     * @return the clElement statistics found
+     * @throws PfModelException on errors getting control loop statistics
+     */
+    public ClElementStatisticsList fetchClElementStatsPerControlLoop(@NonNull final String name,
+                                                                     @NonNull final String version)
+        throws PfModelException {
+        ClElementStatisticsList clElementStatisticsList = new ClElementStatisticsList();
+        List<ClElementStatistics> clElementStats = new ArrayList<>();
+        try {
+            List<ControlLoopElement> clElements = new ArrayList<>();
+            //Fetch all control loop elements for the control loop
+            ControlLoop controlLoop = controlLoopProvider.getControlLoop(new ToscaConceptIdentifier(name,
+                version));
+            if (controlLoop != null) {
+                clElements.addAll(controlLoop.getElements().values());
+                //Collect control loop element statistics for each cl element.
+                for (ControlLoopElement clElement : clElements) {
+                    clElementStats.addAll(fetchFilteredClElementStatistics(clElement.getParticipantId().getName(),
+                        clElement.getParticipantId().getVersion(), clElement.getId().toString(), null,
+                        null, 0).getClElementStatistics());
+                }
+            }
+            clElementStatisticsList.setClElementStatistics(clElementStats);
+        } catch (PfModelException e) {
+            throw new PfModelRuntimeException(e);
+        }
+        return clElementStatisticsList;
+    }
+
+    /**
+     * If required, REST end point can be defined for this method to fetch associated participant Ids
+     * for a control loop.
+     *
+     * @param name the name of the control loop
+     * @param version the version of the control loop
+     * @return List of participant Id
+     * @throws PfModelException on errors
+     */
+    public List<ToscaConceptIdentifier> getAllParticipantIdsPerControlLoop(String name, String version)
+        throws PfModelException {
+        List<ToscaConceptIdentifier> participantIds = new ArrayList<>();
+        ControlLoop controlLoop = controlLoopProvider.getControlLoop(new ToscaConceptIdentifier(name, version));
+        if (controlLoop != null) {
+            for (ControlLoopElement clElement : controlLoop.getElements().values()) {
+                participantIds.add(clElement.getParticipantId());
+            }
+        }
+        return participantIds;
+    }
+
+    /**
+     * If required, REST end point can be defined for this method to fetch associated control loop element Ids
+     * for a control loop.
+     *
+     * @param name the name of the control loop
+     * @param version the version of the control loop
+     * @return Map of control loop Id and participant details
+     * @throws PfModelException on errors
+     */
+    public Map<String, ToscaConceptIdentifier> getAllClElementsIdPerControlLoop(String name, String version)
+        throws PfModelException {
+        Map<String, ToscaConceptIdentifier> clElementId = new HashMap<>();
+        ControlLoop controlLoop = controlLoopProvider.getControlLoop(new ToscaConceptIdentifier(name, version));
+        if (controlLoop != null) {
+            for (ControlLoopElement clElement : controlLoop.getElements().values()) {
+                clElementId.put(clElement.getId().toString(), clElement.getParticipantId());
+            }
+        }
+        return clElementId;
+    }
+
+    public void updateClElementStatistics(List<ClElementStatistics> clElementStatistics) {
+        // TODO Auto-generated method stub
+    }
+
+    public void updateParticipantStatistics(List<ParticipantStatistics> statisticsList) {
+        // TODO Auto-generated method stub
+    }
+}
diff --git a/runtime-controlloop/src/main/java/org/onap/policy/clamp/controlloop/runtime/monitoring/rest/MonitoringQueryController.java b/runtime-controlloop/src/main/java/org/onap/policy/clamp/controlloop/runtime/monitoring/rest/MonitoringQueryController.java
new file mode 100644
index 0000000..2e19ffe
--- /dev/null
+++ b/runtime-controlloop/src/main/java/org/onap/policy/clamp/controlloop/runtime/monitoring/rest/MonitoringQueryController.java
@@ -0,0 +1,371 @@
+/*-
+ * ============LICENSE_START=======================================================
+ *  Copyright (C) 2021 Nordix Foundation.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.policy.clamp.controlloop.runtime.monitoring.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 javax.ws.rs.DefaultValue;
+import javax.ws.rs.GET;
+import javax.ws.rs.HeaderParam;
+import javax.ws.rs.Path;
+import javax.ws.rs.QueryParam;
+import javax.ws.rs.core.Response;
+import org.onap.policy.clamp.controlloop.models.controlloop.concepts.ClElementStatisticsList;
+import org.onap.policy.clamp.controlloop.models.controlloop.concepts.ParticipantStatisticsList;
+import org.onap.policy.clamp.controlloop.runtime.main.rest.RestController;
+import org.onap.policy.clamp.controlloop.runtime.monitoring.MonitoringHandler;
+import org.onap.policy.clamp.controlloop.runtime.monitoring.MonitoringProvider;
+import org.onap.policy.models.base.PfModelException;
+import org.onap.policy.models.base.PfModelRuntimeException;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * This class handles REST endpoints for CL Statistics monitoring.
+ */
+public class MonitoringQueryController extends RestController {
+
+    private static final Logger LOGGER = LoggerFactory.getLogger(MonitoringQueryController.class);
+    private final MonitoringProvider provider;
+
+    /**
+     * Create Monitoring Controller.
+     */
+    public MonitoringQueryController() {
+        this.provider = MonitoringHandler.getInstance().getMonitoringProvider();
+    }
+
+
+    /**
+     * Queries details of control loop 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 recordCount the record count to be fetched
+     * @return the participant statistics
+     */
+    // @formatter:off
+    @GET
+    @Path("/monitoring/participant")
+    @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 = {
+            "Clamp control loop Monitoring 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 Response queryParticipantStatistics(@HeaderParam(REQUEST_ID_NAME)
+                                               @ApiParam(REQUEST_ID_PARAM_DESCRIPTION) UUID requestId,
+                                               @ApiParam(value = "Control Loop participant name", required = true)
+                                               @QueryParam("name") final String name,
+                                               @ApiParam(value = "Control Loop participant version", required = true)
+                                               @QueryParam("version") final String version,
+                                               @ApiParam(value = "Record count", required = false) @DefaultValue("0")
+                                               @QueryParam("recordCount") final int recordCount,
+                                               @ApiParam(value = "start time", required = false)
+                                               @QueryParam("startTime") final String startTime,
+                                               @ApiParam(value = "end time", required = false)
+                                               @QueryParam("endTime") final String endTime) {
+
+        try {
+            Instant startTimestamp = null;
+            Instant endTimestamp = null;
+
+            if (startTime != null) {
+                startTimestamp = Instant.parse(startTime);
+            }
+            if (endTime != null) {
+                endTimestamp = Instant.parse(endTime);
+            }
+            ParticipantStatisticsList response = provider.fetchFilteredParticipantStatistics(name, version, recordCount,
+                startTimestamp, endTimestamp);
+            return addLoggingHeaders(addVersionControlHeaders(Response.status(Response.Status.OK)), requestId)
+                .entity(response)
+                .build();
+
+        } catch (PfModelRuntimeException e) {
+            LOGGER.warn("Monitoring of participants statistics failed", e);
+            return addLoggingHeaders(addVersionControlHeaders(Response.status(e.getErrorResponse().getResponseCode())),
+                requestId).build();
+        }
+
+    }
+
+    /**
+     * Queries details of all participant statistics per control loop.
+     *
+     * @param requestId request ID used in ONAP logging
+     * @param name the name of the control loop
+     * @param version version of the control loop
+     * @return the control loop element statistics
+     */
+    // @formatter:off
+    @GET
+    @Path("/monitoring/participants/controlloop")
+    @ApiOperation(value = "Query details of all the participant stats in a control loop",
+        notes = "Queries details of the participant stats, returning all participant stats",
+        response = ClElementStatisticsList.class,
+        tags = {
+            "Clamp control loop Monitoring 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 Response queryParticipantStatisticsPerControlLoop(@HeaderParam(REQUEST_ID_NAME)
+                                                             @ApiParam(REQUEST_ID_PARAM_DESCRIPTION) UUID requestId,
+                                                             @ApiParam(value = "Control Loop name", required = true)
+                                                             @QueryParam("name") final String name,
+                                                             @ApiParam(value = "Control Loop version", required = true)
+                                                             @QueryParam("version") final String version) {
+
+        try {
+            ParticipantStatisticsList response = provider.fetchParticipantStatsPerControlLoop(name, version);
+            return addLoggingHeaders(addVersionControlHeaders(Response.status(Response.Status.OK)), requestId)
+                .entity(response)
+                .build();
+
+        } catch (PfModelRuntimeException | PfModelException e) {
+            LOGGER.warn("Monitoring of Cl participant statistics failed", e);
+            return addLoggingHeaders(addVersionControlHeaders(Response.status(e.getErrorResponse().getResponseCode())),
+                requestId).build();
+        }
+
+    }
+
+
+
+    /**
+     * Queries details of all control loop element statistics per control loop.
+     *
+     * @param requestId request ID used in ONAP logging
+     * @param name the name of the control loop
+     * @param version version of the control loop
+     * @return the control loop element statistics
+     */
+    // @formatter:off
+    @GET
+    @Path("/monitoring/clelements/controlloop")
+    @ApiOperation(value = "Query details of the requested cl element stats in a control loop",
+        notes = "Queries details of the requested cl element stats, returning all clElement stats",
+        response = ClElementStatisticsList.class,
+        tags = {
+            "Clamp control loop Monitoring 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 Response queryElementStatisticsPerControlLoop(@HeaderParam(REQUEST_ID_NAME)
+                                                         @ApiParam(REQUEST_ID_PARAM_DESCRIPTION) UUID requestId,
+                                                         @ApiParam(value = "Control Loop name", required = true)
+                                                         @QueryParam("name") final String name,
+                                                         @ApiParam(value = "Control Loop version", required = true)
+                                                         @QueryParam("version") final String version) {
+
+        try {
+            ClElementStatisticsList response = provider.fetchClElementStatsPerControlLoop(name, version);
+            return addLoggingHeaders(addVersionControlHeaders(Response.status(Response.Status.OK)), requestId)
+                .entity(response)
+                .build();
+
+        } catch (PfModelRuntimeException | PfModelException e) {
+            LOGGER.warn("Monitoring of Cl Element statistics failed", e);
+            return addLoggingHeaders(addVersionControlHeaders(Response.status(e.getErrorResponse().getResponseCode())),
+                requestId).build();
+        }
+
+    }
+
+
+
+
+    /**
+     * Queries details of all control loop element statistics per control loop.
+     *
+     * @param requestId request ID used in ONAP logging
+     * @param name the name of the control loop
+     * @param version version of the control loop
+     * @param id Id of the control loop element
+     * @param recordCount the record count to be fetched
+     * @return the control loop element statistics
+     */
+    // @formatter:off
+    @GET
+    @Path("/monitoring/clelement")
+    @ApiOperation(value = "Query details of the requested cl element stats",
+        notes = "Queries details of the requested cl element stats, returning all clElement stats",
+        response = ClElementStatisticsList.class,
+        tags = {
+            "Clamp control loop Monitoring 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 Response queryElementStatistics(@HeaderParam(REQUEST_ID_NAME)
+                                           @ApiParam(REQUEST_ID_PARAM_DESCRIPTION) UUID requestId,
+                                           @ApiParam(value = "Participant name", required = true)
+                                           @QueryParam("name") final String name,
+                                           @ApiParam(value = "Participant version", required = true)
+                                           @QueryParam("version") final String version,
+                                           @ApiParam(value = "Record count", required = false)
+                                           @DefaultValue("0") @QueryParam("recordCount") final int recordCount,
+                                           @ApiParam(value = "Control Loop element id", required = false)
+                                           @QueryParam("id") final String id,
+                                           @ApiParam(value = "start time", required = false)
+                                           @QueryParam("startTime") final String startTime,
+                                           @ApiParam(value = "end time", required = false)
+                                           @QueryParam("endTime") final String endTime) {
+
+        try {
+            Instant startTimestamp = null;
+            Instant endTimestamp = null;
+
+            if (startTime != null) {
+                startTimestamp = Instant.parse(startTime);
+            }
+            if (endTime != null) {
+                endTimestamp = Instant.parse(endTime);
+            }
+            ClElementStatisticsList response = provider.fetchFilteredClElementStatistics(name, version, id,
+                startTimestamp, endTimestamp, recordCount);
+            return addLoggingHeaders(addVersionControlHeaders(Response.status(Response.Status.OK)), requestId)
+                .entity(response)
+                .build();
+
+        } catch (PfModelRuntimeException | PfModelException e) {
+            LOGGER.warn("Monitoring of Cl Element statistics failed", e);
+            return addLoggingHeaders(addVersionControlHeaders(Response.status(e.getErrorResponse().getResponseCode())),
+                requestId).build();
+        }
+
+    }
+
+}
diff --git a/runtime-controlloop/src/main/java/org/onap/policy/clamp/controlloop/runtime/supervision/SupervisionHandler.java b/runtime-controlloop/src/main/java/org/onap/policy/clamp/controlloop/runtime/supervision/SupervisionHandler.java
new file mode 100644
index 0000000..63bff00
--- /dev/null
+++ b/runtime-controlloop/src/main/java/org/onap/policy/clamp/controlloop/runtime/supervision/SupervisionHandler.java
@@ -0,0 +1,450 @@
+/*-
+ * ============LICENSE_START=======================================================
+ *  Copyright (C) 2021 Nordix Foundation.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.policy.clamp.controlloop.runtime.supervision;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.UUID;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.Response.Status;
+import org.apache.commons.collections4.CollectionUtils;
+import org.onap.policy.clamp.controlloop.common.exception.ControlLoopException;
+import org.onap.policy.clamp.controlloop.common.exception.ControlLoopRuntimeException;
+import org.onap.policy.clamp.controlloop.common.handler.ControlLoopHandler;
+import org.onap.policy.clamp.controlloop.models.controlloop.concepts.ControlLoop;
+import org.onap.policy.clamp.controlloop.models.controlloop.concepts.ControlLoopElement;
+import org.onap.policy.clamp.controlloop.models.controlloop.concepts.ControlLoopState;
+import org.onap.policy.clamp.controlloop.models.controlloop.concepts.Participant;
+import org.onap.policy.clamp.controlloop.models.controlloop.persistence.provider.ControlLoopProvider;
+import org.onap.policy.clamp.controlloop.models.controlloop.persistence.provider.ParticipantProvider;
+import org.onap.policy.clamp.controlloop.models.messages.dmaap.participant.ParticipantControlLoopStateChange;
+import org.onap.policy.clamp.controlloop.models.messages.dmaap.participant.ParticipantControlLoopUpdate;
+import org.onap.policy.clamp.controlloop.models.messages.dmaap.participant.ParticipantMessageType;
+import org.onap.policy.clamp.controlloop.models.messages.dmaap.participant.ParticipantStatus;
+import org.onap.policy.clamp.controlloop.runtime.commissioning.CommissioningHandler;
+import org.onap.policy.clamp.controlloop.runtime.commissioning.CommissioningProvider;
+import org.onap.policy.clamp.controlloop.runtime.main.parameters.ClRuntimeParameterGroup;
+import org.onap.policy.clamp.controlloop.runtime.monitoring.MonitoringHandler;
+import org.onap.policy.clamp.controlloop.runtime.monitoring.MonitoringProvider;
+import org.onap.policy.clamp.controlloop.runtime.supervision.comm.ParticipantControlLoopStateChangePublisher;
+import org.onap.policy.clamp.controlloop.runtime.supervision.comm.ParticipantControlLoopUpdatePublisher;
+import org.onap.policy.clamp.controlloop.runtime.supervision.comm.ParticipantStateChangePublisher;
+import org.onap.policy.clamp.controlloop.runtime.supervision.comm.ParticipantStatusListener;
+import org.onap.policy.common.endpoints.event.comm.TopicSink;
+import org.onap.policy.common.endpoints.listeners.MessageTypeDispatcher;
+import org.onap.policy.common.utils.services.Registry;
+import org.onap.policy.common.utils.services.ServiceManager;
+import org.onap.policy.common.utils.services.ServiceManagerException;
+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.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * This class handles supervision of control loop 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.
+ */
+public class SupervisionHandler extends ControlLoopHandler {
+    private static final Logger LOGGER = LoggerFactory.getLogger(SupervisionHandler.class);
+
+    private static final String CONTROL_LOOP_CANNOT_TRANSITION_FROM_STATE = "Control loop can't transition from state ";
+    private static final String CONTROL_LOOP_IS_ALREADY_IN_STATE = "Control loop 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 ControlLoopProvider controlLoopProvider;
+    private ParticipantProvider participantProvider;
+    private CommissioningProvider commissioningProvider;
+    private MonitoringProvider monitoringProvider;
+
+    // Publishers for participant communication
+    private ParticipantStateChangePublisher stateChangePublisher;
+    private ParticipantControlLoopUpdatePublisher controlLoopUpdatePublisher;
+    private ParticipantControlLoopStateChangePublisher controlLoopStateChangePublisher;
+
+    // Database scanner
+    private SupervisionScanner scanner;
+
+    /**
+     * Used to manage the services.
+     */
+    private ServiceManager manager;
+    private ServiceManager publisherManager;
+
+    /**
+     * Gets the SupervisionHandler.
+     *
+     * @return SupervisionHandler
+     */
+    public static SupervisionHandler getInstance() {
+        return Registry.get(SupervisionHandler.class.getName());
+    }
+
+    /**
+     * Create a handler.
+     *
+     * @param clRuntimeParameterGroup the parameters for the control loop runtime
+     */
+    public SupervisionHandler(ClRuntimeParameterGroup clRuntimeParameterGroup) {
+        super(clRuntimeParameterGroup.getDatabaseProviderParameters());
+        // @formatter:off
+        this.manager = new ServiceManager()
+                        .addAction("ControlLoop Provider",
+                            () -> controlLoopProvider = new ControlLoopProvider(getDatabaseProviderParameters()),
+                            () -> controlLoopProvider = null)
+                        .addAction("Participant Provider",
+                            () -> participantProvider = new ParticipantProvider(getDatabaseProviderParameters()),
+                            () -> participantProvider = null);
+        // @formatter:on
+    }
+
+    /**
+     * Supervision trigger called when a command is issued on control loops.
+     *
+     * </p> Causes supervision to start or continue supervision on the control loops in question.
+     *
+     * @param controlLoopIdentifierList the control loops for which the supervision command has been issued
+     * @throws ControlLoopException on supervision triggering exceptions
+     */
+    public void triggerControlLoopSupervision(List<ToscaConceptIdentifier> controlLoopIdentifierList)
+            throws ControlLoopException {
+
+        LOGGER.debug("triggering control loop supervision on control loops {}", controlLoopIdentifierList);
+
+        if (CollectionUtils.isEmpty(controlLoopIdentifierList)) {
+            // This is just to force throwing of the exception in certain circumstances.
+            exceptionOccured(Response.Status.NOT_ACCEPTABLE,
+                    "The list of control loops for supervision is empty");
+        }
+
+        for (ToscaConceptIdentifier controlLoopId : controlLoopIdentifierList) {
+            try {
+                ControlLoop controlLoop = controlLoopProvider.getControlLoop(controlLoopId);
+
+                superviseControlLoop(controlLoop);
+
+                controlLoopProvider.updateControlLoop(controlLoop);
+            } catch (PfModelException pfme) {
+                throw new ControlLoopException(pfme.getErrorResponse().getResponseCode(), pfme.getMessage(), pfme);
+            }
+        }
+    }
+
+    @Override
+    public void startAndRegisterListeners(MessageTypeDispatcher msgDispatcher) {
+        msgDispatcher.register(ParticipantMessageType.PARTICIPANT_STATUS.name(), new ParticipantStatusListener());
+    }
+
+    @Override
+    public void startAndRegisterPublishers(List<TopicSink> topicSinks) {
+        // TODO: Use a parameter for the timeout
+        // @formatter:off
+        this.publisherManager = new ServiceManager()
+                .addAction("Supervision scanner",
+                        () -> scanner = new SupervisionScanner(controlLoopProvider, 10000),
+                        () -> scanner = null)
+                .addAction("ControlLoopUpdate publisher",
+                        () -> controlLoopUpdatePublisher = new ParticipantControlLoopUpdatePublisher(topicSinks, -1),
+                        () -> controlLoopUpdatePublisher.terminate())
+                .addAction("StateChange Publisher",
+                        () -> stateChangePublisher = new ParticipantStateChangePublisher(topicSinks, 10000),
+                        () -> stateChangePublisher.terminate())
+                .addAction("ControlLoopStateChange Publisher",
+                        () -> controlLoopStateChangePublisher =
+                        new ParticipantControlLoopStateChangePublisher(topicSinks, -1),
+                        () -> controlLoopStateChangePublisher.terminate());
+        // @formatter:on
+        try {
+            publisherManager.start();
+        } catch (final ServiceManagerException exp) {
+            throw new ControlLoopRuntimeException(Status.INTERNAL_SERVER_ERROR,
+                    "Supervision handler start of publishers or scanner failed", exp);
+        }
+    }
+
+    @Override
+    public void stopAndUnregisterPublishers() {
+        try {
+            publisherManager.stop();
+        } catch (final ServiceManagerException exp) {
+            throw new ControlLoopRuntimeException(Status.INTERNAL_SERVER_ERROR,
+                    "Supervision handler stop of publishers or scanner failed", exp);
+        }
+    }
+
+    @Override
+    public void stopAndUnregisterListeners(MessageTypeDispatcher msgDispatcher) {
+        msgDispatcher.unregister(ParticipantMessageType.PARTICIPANT_STATUS.name());
+    }
+
+    /**
+     * Handle a ParticipantStatus message from a participant.
+     *
+     * @param participantStatusMessage the ParticipantStatus message received from a participant
+     */
+    public void handleParticipantStatusMessage(ParticipantStatus participantStatusMessage) {
+        LOGGER.debug("Participant Status received {}", participantStatusMessage);
+
+        try {
+            superviseParticipant(participantStatusMessage);
+        } catch (PfModelException | ControlLoopException svExc) {
+            LOGGER.warn("error supervising participant {}", participantStatusMessage.getParticipantId(), svExc);
+            return;
+        }
+
+        try {
+            superviseControlLoops(participantStatusMessage);
+        } catch (PfModelException | ControlLoopException svExc) {
+            LOGGER.warn("error supervising participant {}", participantStatusMessage.getParticipantId(), svExc);
+        }
+    }
+
+    /**
+     * Supervise a control loop, performing whatever actions need to be performed on the control loop.
+     *
+     * @param controlLoop the control loop to supervises
+     * @throws ControlLoopException on supervision errors
+     */
+    private void superviseControlLoop(ControlLoop controlLoop) throws ControlLoopException, PfModelException {
+        switch (controlLoop.getOrderedState()) {
+            case UNINITIALISED:
+                superviseControlLoopUninitialization(controlLoop);
+                break;
+
+            case PASSIVE:
+                superviseControlLoopPassivation(controlLoop);
+                break;
+
+            case RUNNING:
+                superviseControlLoopActivation(controlLoop);
+                break;
+
+            default:
+                exceptionOccured(Response.Status.NOT_ACCEPTABLE,
+                    "A control loop cannot be commanded to go into state " + controlLoop.getOrderedState().name());
+        }
+    }
+
+    /**
+     * Supervise a control loop uninitialisation, performing whatever actions need to be performed on the control loop,
+     * control loop ordered state is UNINITIALIZED.
+     *
+     * @param controlLoop the control loop to supervises
+     * @throws ControlLoopException on supervision errors
+     */
+    private void superviseControlLoopUninitialization(ControlLoop controlLoop) throws ControlLoopException {
+        switch (controlLoop.getState()) {
+            case UNINITIALISED:
+                exceptionOccured(Response.Status.NOT_ACCEPTABLE,
+                        CONTROL_LOOP_IS_ALREADY_IN_STATE + controlLoop.getState().name());
+                break;
+
+            case UNINITIALISED2PASSIVE:
+            case PASSIVE:
+                controlLoop.setState(ControlLoopState.PASSIVE2UNINITIALISED);
+                sendControlLoopStateChange(controlLoop);
+                break;
+
+            case PASSIVE2UNINITIALISED:
+                exceptionOccured(Response.Status.NOT_ACCEPTABLE, CONTROL_LOOP_IS_ALREADY_IN_STATE
+                        + controlLoop.getState().name() + AND_TRANSITIONING_TO_STATE + controlLoop.getOrderedState());
+                break;
+
+            default:
+                exceptionOccured(Response.Status.NOT_ACCEPTABLE, CONTROL_LOOP_CANNOT_TRANSITION_FROM_STATE
+                        + controlLoop.getState().name() + TO_STATE + controlLoop.getOrderedState());
+                break;
+        }
+    }
+
+    private void superviseControlLoopPassivation(ControlLoop controlLoop)
+            throws ControlLoopException, PfModelException {
+        switch (controlLoop.getState()) {
+            case PASSIVE:
+                exceptionOccured(Response.Status.NOT_ACCEPTABLE,
+                        CONTROL_LOOP_IS_ALREADY_IN_STATE + controlLoop.getState().name());
+                break;
+            case UNINITIALISED:
+                controlLoop.setState(ControlLoopState.UNINITIALISED2PASSIVE);
+                sendControlLoopUpdate(controlLoop);
+                break;
+
+            case UNINITIALISED2PASSIVE:
+            case RUNNING2PASSIVE:
+                exceptionOccured(Response.Status.NOT_ACCEPTABLE, CONTROL_LOOP_IS_ALREADY_IN_STATE
+                        + controlLoop.getState().name() + AND_TRANSITIONING_TO_STATE + controlLoop.getOrderedState());
+                break;
+
+            case RUNNING:
+                controlLoop.setState(ControlLoopState.RUNNING2PASSIVE);
+                sendControlLoopStateChange(controlLoop);
+                break;
+
+            default:
+                exceptionOccured(Response.Status.NOT_ACCEPTABLE, CONTROL_LOOP_CANNOT_TRANSITION_FROM_STATE
+                        + controlLoop.getState().name() + TO_STATE + controlLoop.getOrderedState());
+                break;
+        }
+    }
+
+    private void superviseControlLoopActivation(ControlLoop controlLoop) throws ControlLoopException {
+        switch (controlLoop.getState()) {
+            case RUNNING:
+                exceptionOccured(Response.Status.NOT_ACCEPTABLE,
+                        CONTROL_LOOP_IS_ALREADY_IN_STATE + controlLoop.getState().name());
+                break;
+
+            case PASSIVE2RUNNING:
+                exceptionOccured(Response.Status.NOT_ACCEPTABLE, CONTROL_LOOP_IS_ALREADY_IN_STATE
+                        + controlLoop.getState().name() + AND_TRANSITIONING_TO_STATE + controlLoop.getOrderedState());
+                break;
+
+            case PASSIVE:
+                controlLoop.setState(ControlLoopState.PASSIVE2RUNNING);
+                sendControlLoopStateChange(controlLoop);
+                break;
+
+            default:
+                exceptionOccured(Response.Status.NOT_ACCEPTABLE, CONTROL_LOOP_CANNOT_TRANSITION_FROM_STATE
+                        + controlLoop.getState().name() + TO_STATE + controlLoop.getOrderedState());
+                break;
+        }
+    }
+
+    private void sendControlLoopUpdate(ControlLoop controlLoop) throws PfModelException {
+        ParticipantControlLoopUpdate pclu = new ParticipantControlLoopUpdate();
+        pclu.setControlLoopId(controlLoop.getKey().asIdentifier());
+        pclu.setControlLoop(controlLoop);
+        // TODO: We should look up the correct TOSCA node template here for the control loop
+        // Tiny hack implemented to return the tosca service template entry from the database and be passed onto dmaap
+        commissioningProvider = CommissioningHandler.getInstance().getProvider();
+        pclu.setControlLoopDefinition(commissioningProvider.getToscaServiceTemplate(null, null));
+        controlLoopUpdatePublisher.send(pclu);
+    }
+
+    private void sendControlLoopStateChange(ControlLoop controlLoop) {
+        ParticipantControlLoopStateChange clsc = new ParticipantControlLoopStateChange();
+        clsc.setControlLoopId(controlLoop.getKey().asIdentifier());
+        clsc.setMessageId(UUID.randomUUID());
+        clsc.setOrderedState(controlLoop.getOrderedState());
+
+        controlLoopStateChangePublisher.send(clsc);
+    }
+
+    private void superviseParticipant(ParticipantStatus participantStatusMessage)
+            throws PfModelException, ControlLoopException {
+        if (participantStatusMessage.getParticipantId() == null) {
+            exceptionOccured(Response.Status.NOT_FOUND,
+                    "Participant ID on PARTICIPANT_STATUS message is null");
+        }
+
+        List<Participant> participantList =
+                participantProvider.getParticipants(participantStatusMessage.getParticipantId().getName(),
+                        participantStatusMessage.getParticipantId().getVersion());
+
+        if (CollectionUtils.isEmpty(participantList)) {
+            Participant participant = new Participant();
+            participant.setName(participantStatusMessage.getParticipantId().getName());
+            participant.setVersion(participantStatusMessage.getParticipantId().getVersion());
+            participant.setDefinition(new ToscaConceptIdentifier("unknown", "0.0.0"));
+            participant.setParticipantState(participantStatusMessage.getState());
+            participant.setHealthStatus(participantStatusMessage.getHealthStatus());
+
+            participantList.add(participant);
+            participantProvider.createParticipants(participantList);
+        } else {
+            for (Participant participant : participantList) {
+                participant.setParticipantState(participantStatusMessage.getState());
+                participant.setHealthStatus(participantStatusMessage.getHealthStatus());
+            }
+            participantProvider.updateParticipants(participantList);
+        }
+
+        monitoringProvider = MonitoringHandler.getInstance().getMonitoringProvider();
+        monitoringProvider.createParticipantStatistics(
+                                List.of(participantStatusMessage.getParticipantStatistics()));
+    }
+
+    private void superviseControlLoops(ParticipantStatus participantStatusMessage)
+            throws PfModelException, ControlLoopException {
+        if (CollectionUtils.isEmpty(participantStatusMessage.getControlLoops().getControlLoopList())) {
+            return;
+        }
+
+        for (ControlLoop controlLoop : participantStatusMessage.getControlLoops().getControlLoopList()) {
+            if (controlLoop == null) {
+                exceptionOccured(Response.Status.NOT_FOUND,
+                    "PARTICIPANT_STATUS message references unknown control loop: " + controlLoop);
+            }
+
+            ControlLoop dbControlLoop = controlLoopProvider
+                    .getControlLoop(new ToscaConceptIdentifier(controlLoop.getName(), controlLoop.getVersion()));
+            if (dbControlLoop == null) {
+                exceptionOccured(Response.Status.NOT_FOUND,
+                    "PARTICIPANT_STATUS control loop not found in database: " + controlLoop);
+            }
+
+            for (ControlLoopElement element : controlLoop.getElements().values()) {
+                ControlLoopElement dbElement = dbControlLoop.getElements().get(element.getId());
+
+                if (dbElement == null) {
+                    exceptionOccured(Response.Status.NOT_FOUND,
+                            "PARTICIPANT_STATUS message references unknown control loop element: " + element);
+                }
+
+                // Replace element entry in the database
+                dbControlLoop.getElements().put(element.getId(), element);
+            }
+            controlLoopProvider.updateControlLoop(dbControlLoop);
+        }
+
+        monitoringProvider = MonitoringHandler.getInstance().getMonitoringProvider();
+        for (ControlLoop controlLoop : participantStatusMessage.getControlLoops().getControlLoopList()) {
+            monitoringProvider.createClElementStatistics(controlLoop.getControlLoopElementStatisticsList(controlLoop));
+        }
+    }
+
+    @Override
+    public void startProviders() {
+        try {
+            manager.start();
+        } catch (final ServiceManagerException exp) {
+            throw new ControlLoopRuntimeException(Status.INTERNAL_SERVER_ERROR,
+                    "Supervision handler start of providers failed", exp);
+        }
+    }
+
+    @Override
+    public void stopProviders() {
+        try {
+            manager.stop();
+        } catch (final ServiceManagerException exp) {
+            throw new ControlLoopRuntimeException(Status.INTERNAL_SERVER_ERROR,
+                    "Supervision handler stop of providers failed", exp);
+        }
+    }
+
+    private void exceptionOccured(Response.Status status, String reason) throws ControlLoopException {
+        throw new ControlLoopException(status, reason);
+    }
+}
diff --git a/runtime-controlloop/src/main/java/org/onap/policy/clamp/controlloop/runtime/supervision/SupervisionScanner.java b/runtime-controlloop/src/main/java/org/onap/policy/clamp/controlloop/runtime/supervision/SupervisionScanner.java
new file mode 100644
index 0000000..0ccfddf
--- /dev/null
+++ b/runtime-controlloop/src/main/java/org/onap/policy/clamp/controlloop/runtime/supervision/SupervisionScanner.java
@@ -0,0 +1,116 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * Copyright (C) 2021 Nordix Foundation.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.policy.clamp.controlloop.runtime.supervision;
+
+import java.io.Closeable;
+import java.util.Collection;
+import java.util.List;
+import java.util.TimerTask;
+import java.util.concurrent.Callable;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.Executors;
+import java.util.concurrent.Future;
+import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.ScheduledFuture;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
+import org.onap.policy.clamp.controlloop.models.controlloop.concepts.ControlLoop;
+import org.onap.policy.clamp.controlloop.models.controlloop.concepts.ControlLoopElement;
+import org.onap.policy.clamp.controlloop.models.controlloop.persistence.provider.ControlLoopProvider;
+import org.onap.policy.models.base.PfModelException;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * This class is used to scan the control loops in the database and check if they are in the correct state.
+ */
+public class SupervisionScanner implements Runnable, Closeable {
+    private static final Logger LOGGER = LoggerFactory.getLogger(SupervisionScanner.class);
+
+    private ControlLoopProvider controlLoopProvider;
+    private ScheduledExecutorService timerPool;
+
+    /**
+     * Constructor for instantiating SupervisionScanner.
+     *
+     * @param controlLoopProvider the provider to use to read control loops from the database
+     * @param interval time interval to perform scans
+     */
+    public SupervisionScanner(final ControlLoopProvider controlLoopProvider, final long interval) {
+        this.controlLoopProvider = controlLoopProvider;
+
+        // Kick off the timer
+        timerPool = makeTimerPool();
+        timerPool.scheduleAtFixedRate(this, 0, interval, TimeUnit.SECONDS);
+    }
+
+    @Override
+    public void run() {
+        LOGGER.debug("Scanning control loops in the database . . .");
+
+        try {
+            for (ControlLoop controlLoop : controlLoopProvider.getControlLoops(null, null)) {
+                scanControlLoop(controlLoop);
+            }
+        } catch (PfModelException pfme) {
+            LOGGER.warn("error reading control loops from database", pfme);
+        }
+
+        LOGGER.debug("Control loop scan complete . . .");
+    }
+
+    @Override
+    public void close() {
+        timerPool.shutdown();
+    }
+
+    private void scanControlLoop(final ControlLoop controlLoop) throws PfModelException {
+        LOGGER.debug("scanning control loop {} . . .", controlLoop.getKey().asIdentifier());
+
+        if (controlLoop.getState().equals(controlLoop.getOrderedState().asState())) {
+            LOGGER.debug("control loop {} scanned, OK", controlLoop.getKey().asIdentifier());
+            return;
+        }
+
+        for (ControlLoopElement element : controlLoop.getElements().values()) {
+            if (!element.getState().equals(element.getOrderedState().asState())) {
+                LOGGER.debug("control loop scan: transitioning from state {} to {}", controlLoop.getState(),
+                        controlLoop.getOrderedState());
+                return;
+            }
+        }
+
+        LOGGER.debug("control loop scan: transition from state {} to {} completed", controlLoop.getState(),
+                controlLoop.getOrderedState());
+
+        controlLoop.setState(controlLoop.getOrderedState().asState());
+        controlLoopProvider.updateControlLoop(controlLoop);
+    }
+
+    /**
+     * Makes a new timer pool.
+     *
+     * @return a new timer pool
+     */
+    protected ScheduledExecutorService makeTimerPool() {
+        return Executors.newScheduledThreadPool(1);
+    }
+}
diff --git a/runtime-controlloop/src/main/java/org/onap/policy/clamp/controlloop/runtime/supervision/comm/ParticipantControlLoopStateChangePublisher.java b/runtime-controlloop/src/main/java/org/onap/policy/clamp/controlloop/runtime/supervision/comm/ParticipantControlLoopStateChangePublisher.java
new file mode 100644
index 0000000..c9c8ab8
--- /dev/null
+++ b/runtime-controlloop/src/main/java/org/onap/policy/clamp/controlloop/runtime/supervision/comm/ParticipantControlLoopStateChangePublisher.java
@@ -0,0 +1,75 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * Copyright (C) 2021 Nordix Foundation.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.policy.clamp.controlloop.runtime.supervision.comm;
+
+import java.util.List;
+import org.onap.policy.clamp.controlloop.models.messages.dmaap.participant.ParticipantControlLoopStateChange;
+import org.onap.policy.common.endpoints.event.comm.TopicSink;
+import org.onap.policy.common.endpoints.event.comm.client.TopicSinkClient;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * This class is used to send ParticipantControlLoopStateChangePublisher messages to participants on DMaaP.
+ */
+public class ParticipantControlLoopStateChangePublisher {
+    private static final Logger LOGGER = LoggerFactory.getLogger(ParticipantControlLoopStateChangePublisher.class);
+
+    private TopicSinkClient topicSinkClient;
+
+    /**
+     * Constructor for instantiating ParticipantControlLoopStateChangePublisherPublisher.
+     *
+     * @param topicSinks the topic sinks
+     * @param interval time interval to send ParticipantControlLoopStateChangePublisher messages
+     */
+    public ParticipantControlLoopStateChangePublisher(final List<TopicSink> topicSinks, final long interval) {
+        // TODO: Should not be dependent on the order of topic sinks in the config
+        this.topicSinkClient = new TopicSinkClient(topicSinks.get(0));
+    }
+
+    /**
+     * Terminates the current timer.
+     */
+    public void terminate() {
+        // This is a user initiated message and doesn't need a timer.
+    }
+
+    /**
+     * Get the current time interval used by the timer task.
+     *
+     * @return interval the current time interval
+     */
+    public long getInterval() {
+        // This is a user initiated message and doesn't need a timer.
+        return -1;
+    }
+
+    /**
+     * Method to send ParticipantControlLoopStateChangePublisher status message to participants on demand.
+     *
+     * @param controlLoopStateChange the ParticipantControlLoopStateChangePublisher message
+     */
+    public void send(final ParticipantControlLoopStateChange controlLoopStateChange) {
+        topicSinkClient.send(controlLoopStateChange);
+        LOGGER.debug("Sent ParticipantControlLoopStateChange to Participants - {}", controlLoopStateChange);
+    }
+}
diff --git a/runtime-controlloop/src/main/java/org/onap/policy/clamp/controlloop/runtime/supervision/comm/ParticipantControlLoopUpdatePublisher.java b/runtime-controlloop/src/main/java/org/onap/policy/clamp/controlloop/runtime/supervision/comm/ParticipantControlLoopUpdatePublisher.java
new file mode 100644
index 0000000..3c5d230
--- /dev/null
+++ b/runtime-controlloop/src/main/java/org/onap/policy/clamp/controlloop/runtime/supervision/comm/ParticipantControlLoopUpdatePublisher.java
@@ -0,0 +1,75 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * Copyright (C) 2021 Nordix Foundation.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.policy.clamp.controlloop.runtime.supervision.comm;
+
+import java.util.List;
+import org.onap.policy.clamp.controlloop.models.messages.dmaap.participant.ParticipantControlLoopUpdate;
+import org.onap.policy.common.endpoints.event.comm.TopicSink;
+import org.onap.policy.common.endpoints.event.comm.client.TopicSinkClient;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * This class is used to send ParticipantControlLoopUpdate messages to participants on DMaaP.
+ */
+public class ParticipantControlLoopUpdatePublisher {
+    private static final Logger LOGGER = LoggerFactory.getLogger(ParticipantControlLoopUpdatePublisher.class);
+
+    private TopicSinkClient topicSinkClient;
+
+    /**
+     * Constructor for instantiating ParticipantUpdatePublisher.
+     *
+     * @param topicSinks the topic sinks
+     * @param interval time interval to send ParticipantControlLoopUpdate messages
+     */
+    public ParticipantControlLoopUpdatePublisher(final List<TopicSink> topicSinks, final long interval) {
+        // TODO: Should not be dependent on the order of topic sinks in the config
+        this.topicSinkClient = new TopicSinkClient(topicSinks.get(0));
+    }
+
+    /**
+     * Terminates the current timer.
+     */
+    public void terminate() {
+        // This is a user initiated message and doesn't need a timer.
+    }
+
+    /**
+     * Get the current time interval used by the timer task.
+     *
+     * @return interval the current time interval
+     */
+    public long getInterval() {
+        // This is a user initiated message and doesn't need a timer.
+        return -1;
+    }
+
+    /**
+     * Method to send ParticipantControlLoopUpdate status message to participants on demand.
+     *
+     * @param participantControlLoopUpdate the ParticipantControlLoopUpdate message
+     */
+    public void send(final ParticipantControlLoopUpdate participantControlLoopUpdate) {
+        topicSinkClient.send(participantControlLoopUpdate);
+        LOGGER.debug("Sent ParticipantControlLoopUpdate to Participants - {}", participantControlLoopUpdate);
+    }
+}
diff --git a/runtime-controlloop/src/main/java/org/onap/policy/clamp/controlloop/runtime/supervision/comm/ParticipantStateChangePublisher.java b/runtime-controlloop/src/main/java/org/onap/policy/clamp/controlloop/runtime/supervision/comm/ParticipantStateChangePublisher.java
new file mode 100644
index 0000000..0990391
--- /dev/null
+++ b/runtime-controlloop/src/main/java/org/onap/policy/clamp/controlloop/runtime/supervision/comm/ParticipantStateChangePublisher.java
@@ -0,0 +1,74 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * Copyright (C) 2021 Nordix Foundation.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.policy.clamp.controlloop.runtime.supervision.comm;
+
+import java.util.List;
+import org.onap.policy.clamp.controlloop.models.messages.dmaap.participant.ParticipantStateChange;
+import org.onap.policy.common.endpoints.event.comm.TopicSink;
+import org.onap.policy.common.endpoints.event.comm.client.TopicSinkClient;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * This class is used to send ParticipantStateChange messages to participants on DMaaP.
+ */
+public class ParticipantStateChangePublisher {
+    private static final Logger LOGGER = LoggerFactory.getLogger(ParticipantStateChangePublisher.class);
+
+    private TopicSinkClient topicSinkClient;
+
+    /**
+     * Constructor for instantiating ParticipantStateChangePublisher.
+     *
+     * @param topicSinks the topic sinks
+     * @param interval time interval to send ParticipantStateChange messages
+     */
+    public ParticipantStateChangePublisher(final List<TopicSink> topicSinks, final long interval) {
+        // TODO: Should not be dependent on the order of topic sinks in the config
+        this.topicSinkClient = new TopicSinkClient(topicSinks.get(0));
+    }
+
+    /**
+     * Terminates the current timer.
+     */
+    public void terminate() {
+        // Nothing to terminate, this publisher does not have a timer
+    }
+
+    /**
+     * Get the current time interval used by the timer task.
+     *
+     * @return interval the current time interval
+     */
+    public long getInterval() {
+        return -1;
+    }
+
+    /**
+     * Method to send ParticipantStateChange status message to participants on demand.
+     *
+     * @param participantStateChange the ParticipantStateChange message
+     */
+    public void send(final ParticipantStateChange participantStateChange) {
+        topicSinkClient.send(participantStateChange);
+        LOGGER.debug("Sent ParticipantStateChange to Participants - {}", participantStateChange);
+    }
+}
diff --git a/runtime-controlloop/src/main/java/org/onap/policy/clamp/controlloop/runtime/supervision/comm/ParticipantStatusListener.java b/runtime-controlloop/src/main/java/org/onap/policy/clamp/controlloop/runtime/supervision/comm/ParticipantStatusListener.java
new file mode 100644
index 0000000..a05f4aa
--- /dev/null
+++ b/runtime-controlloop/src/main/java/org/onap/policy/clamp/controlloop/runtime/supervision/comm/ParticipantStatusListener.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.controlloop.runtime.supervision.comm;
+
+import org.onap.policy.clamp.controlloop.models.messages.dmaap.participant.ParticipantStatus;
+import org.onap.policy.clamp.controlloop.runtime.supervision.SupervisionHandler;
+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.onap.policy.common.utils.services.Registry;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Listener for ParticipantStatus messages sent by participants.
+ */
+public class ParticipantStatusListener extends ScoListener<ParticipantStatus> {
+    private static final Logger LOGGER = LoggerFactory.getLogger(ParticipantStatusListener.class);
+
+    private final SupervisionHandler supervisionHandler = Registry.get(SupervisionHandler.class.getName());
+
+    /**
+     * Constructs the object.
+     */
+    public ParticipantStatusListener() {
+        super(ParticipantStatus.class);
+    }
+
+    @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.handleParticipantStatusMessage(participantStatusMessage);
+    }
+}
diff --git a/runtime-controlloop/src/main/resources/META-INF/persistence.xml b/runtime-controlloop/src/main/resources/META-INF/persistence.xml
new file mode 100644
index 0000000..e5d2cab
--- /dev/null
+++ b/runtime-controlloop/src/main/resources/META-INF/persistence.xml
@@ -0,0 +1,121 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  ============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=========================================================
+-->
+<persistence xmlns="http://java.sun.com/xml/ns/persistence" version="2.0">
+    <persistence-unit name="CommissioningMariaDb" transaction-type="RESOURCE_LOCAL">
+        <provider>org.eclipse.persistence.jpa.PersistenceProvider</provider>
+
+        <class>org.onap.policy.models.tosca.simple.concepts.JpaToscaCapabilityAssignment</class>
+        <class>org.onap.policy.models.tosca.simple.concepts.JpaToscaCapabilityAssignments</class>
+        <class>org.onap.policy.models.tosca.simple.concepts.JpaToscaCapabilityType</class>
+        <class>org.onap.policy.models.tosca.simple.concepts.JpaToscaCapabilityTypes</class>
+        <class>org.onap.policy.models.tosca.simple.concepts.JpaToscaDataType</class>
+        <class>org.onap.policy.models.tosca.simple.concepts.JpaToscaDataTypes</class>
+        <class>org.onap.policy.models.tosca.simple.concepts.JpaToscaNodeTemplate</class>
+        <class>org.onap.policy.models.tosca.simple.concepts.JpaToscaNodeTemplates</class>
+        <class>org.onap.policy.models.tosca.simple.concepts.JpaToscaNodeType</class>
+        <class>org.onap.policy.models.tosca.simple.concepts.JpaToscaNodeTypes</class>
+        <class>org.onap.policy.models.tosca.simple.concepts.JpaToscaParameter</class>
+        <class>org.onap.policy.models.tosca.simple.concepts.JpaToscaPolicies</class>
+        <class>org.onap.policy.models.tosca.simple.concepts.JpaToscaPolicy</class>
+        <class>org.onap.policy.models.tosca.simple.concepts.JpaToscaPolicyType</class>
+        <class>org.onap.policy.models.tosca.simple.concepts.JpaToscaPolicyTypes</class>
+        <class>org.onap.policy.models.tosca.simple.concepts.JpaToscaProperty</class>
+        <class>org.onap.policy.models.tosca.simple.concepts.JpaToscaRelationshipType</class>
+        <class>org.onap.policy.models.tosca.simple.concepts.JpaToscaRelationshipTypes</class>
+        <class>org.onap.policy.models.tosca.simple.concepts.JpaToscaRequirement</class>
+        <class>org.onap.policy.models.tosca.simple.concepts.JpaToscaRequirements</class>
+        <class>org.onap.policy.models.tosca.simple.concepts.JpaToscaServiceTemplate</class>
+        <class>org.onap.policy.models.tosca.simple.concepts.JpaToscaTopologyTemplate</class>
+        <class>org.onap.policy.clamp.controlloop.models.controlloop.persistence.concepts.JpaControlLoop</class>
+        <class>org.onap.policy.clamp.controlloop.models.controlloop.persistence.concepts.JpaControlLoopElement</class>
+        <class>org.onap.policy.clamp.controlloop.models.controlloop.persistence.concepts.JpaParticipant</class>
+        <class>org.onap.policy.clamp.controlloop.models.controlloop.persistence.concepts.JpaParticipantStatistics</class>
+        <class>org.onap.policy.clamp.controlloop.models.controlloop.persistence.concepts.JpaClElementStatistics</class>
+
+        <properties>
+            <property name="eclipselink.ddl-generation" value="create-or-extend-tables" />
+            <property name="eclipselink.ddl-generation.output-mode" value="database" />
+            <property name="eclipselink.logging.level" value="INFO" />
+
+            <!-- property name="eclipselink.logging.level" value="ALL" />
+            <property name="eclipselink.logging.level.jpa" value="ALL" />
+            <property name="eclipselink.logging.level.ddl" value="ALL" />
+            <property name="eclipselink.logging.level.connection" value="ALL" />
+            <property name="eclipselink.logging.level.sql" value="ALL" />
+            <property name="eclipselink.logging.level.transaction" value="ALL" />
+            <property name="eclipselink.logging.level.sequencing" value="ALL" />
+            <property name="eclipselink.logging.level.server" value="ALL" />
+            <property name="eclipselink.logging.level.query" value="ALL" />
+            <property name="eclipselink.logging.level.properties" value="ALL" /-->
+        </properties>
+        <shared-cache-mode>NONE</shared-cache-mode>
+    </persistence-unit>
+
+    <persistence-unit name="ToscaConceptTest" transaction-type="RESOURCE_LOCAL">
+        <provider>org.eclipse.persistence.jpa.PersistenceProvider</provider>
+
+        <class>org.onap.policy.models.tosca.simple.concepts.JpaToscaCapabilityAssignment</class>
+        <class>org.onap.policy.models.tosca.simple.concepts.JpaToscaCapabilityAssignments</class>
+        <class>org.onap.policy.models.tosca.simple.concepts.JpaToscaCapabilityType</class>
+        <class>org.onap.policy.models.tosca.simple.concepts.JpaToscaCapabilityTypes</class>
+        <class>org.onap.policy.models.tosca.simple.concepts.JpaToscaDataType</class>
+        <class>org.onap.policy.models.tosca.simple.concepts.JpaToscaDataTypes</class>
+        <class>org.onap.policy.models.tosca.simple.concepts.JpaToscaNodeTemplate</class>
+        <class>org.onap.policy.models.tosca.simple.concepts.JpaToscaNodeTemplates</class>
+        <class>org.onap.policy.models.tosca.simple.concepts.JpaToscaNodeType</class>
+        <class>org.onap.policy.models.tosca.simple.concepts.JpaToscaNodeTypes</class>
+        <class>org.onap.policy.models.tosca.simple.concepts.JpaToscaParameter</class>
+        <class>org.onap.policy.models.tosca.simple.concepts.JpaToscaPolicies</class>
+        <class>org.onap.policy.models.tosca.simple.concepts.JpaToscaPolicy</class>
+        <class>org.onap.policy.models.tosca.simple.concepts.JpaToscaPolicyType</class>
+        <class>org.onap.policy.models.tosca.simple.concepts.JpaToscaPolicyTypes</class>
+        <class>org.onap.policy.models.tosca.simple.concepts.JpaToscaProperty</class>
+        <class>org.onap.policy.models.tosca.simple.concepts.JpaToscaRelationshipType</class>
+        <class>org.onap.policy.models.tosca.simple.concepts.JpaToscaRelationshipTypes</class>
+        <class>org.onap.policy.models.tosca.simple.concepts.JpaToscaRequirement</class>
+        <class>org.onap.policy.models.tosca.simple.concepts.JpaToscaRequirements</class>
+        <class>org.onap.policy.models.tosca.simple.concepts.JpaToscaServiceTemplate</class>
+        <class>org.onap.policy.models.tosca.simple.concepts.JpaToscaTopologyTemplate</class>
+        <class>org.onap.policy.clamp.controlloop.models.controlloop.persistence.concepts.JpaControlLoop</class>
+        <class>org.onap.policy.clamp.controlloop.models.controlloop.persistence.concepts.JpaControlLoopElement</class>
+        <class>org.onap.policy.clamp.controlloop.models.controlloop.persistence.concepts.JpaParticipant</class>
+        <class>org.onap.policy.clamp.controlloop.models.controlloop.persistence.concepts.JpaParticipantStatistics</class>
+        <class>org.onap.policy.clamp.controlloop.models.controlloop.persistence.concepts.JpaClElementStatistics</class>
+        <properties>
+            <property name="eclipselink.ddl-generation" value="drop-and-create-tables" />
+            <property name="eclipselink.ddl-generation.output-mode" value="database" />
+            <property name="eclipselink.logging.level" value="INFO" />
+
+            <!-- property name="eclipselink.logging.level" value="ALL" />
+            <property name="eclipselink.logging.level.jpa" value="ALL" />
+            <property name="eclipselink.logging.level.ddl" value="ALL" />
+            <property name="eclipselink.logging.level.connection" value="ALL" />
+            <property name="eclipselink.logging.level.sql" value="ALL" />
+            <property name="eclipselink.logging.level.transaction" value="ALL" />
+            <property name="eclipselink.logging.level.sequencing" value="ALL" />
+            <property name="eclipselink.logging.level.server" value="ALL" />
+            <property name="eclipselink.logging.level.query" value="ALL" />
+            <property name="eclipselink.logging.level.properties" value="ALL" /-->
+        </properties>
+        <shared-cache-mode>NONE</shared-cache-mode>
+    </persistence-unit>
+</persistence>
+
diff --git a/runtime-controlloop/src/main/resources/version.txt b/runtime-controlloop/src/main/resources/version.txt
new file mode 100644
index 0000000..e11449e
--- /dev/null
+++ b/runtime-controlloop/src/main/resources/version.txt
@@ -0,0 +1,4 @@
+ONAP Tosca defined control loop
+Version: ${project.version}
+Built (UTC): ${maven.build.timestamp}
+ONAP https://wiki.onap.org
diff --git a/runtime-controlloop/src/test/java/org/onap/policy/clamp/controlloop/runtime/commissioning/CommissioningProviderTest.java b/runtime-controlloop/src/test/java/org/onap/policy/clamp/controlloop/runtime/commissioning/CommissioningProviderTest.java
new file mode 100644
index 0000000..956b5e9
--- /dev/null
+++ b/runtime-controlloop/src/test/java/org/onap/policy/clamp/controlloop/runtime/commissioning/CommissioningProviderTest.java
@@ -0,0 +1,216 @@
+/*-
+ * ============LICENSE_START=======================================================
+ *  Copyright (C) 2021 Nordix Foundation.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.policy.clamp.controlloop.runtime.commissioning;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.assertThatThrownBy;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import java.util.ArrayList;
+import java.util.List;
+import org.junit.Before;
+import org.junit.Test;
+import org.onap.policy.clamp.controlloop.runtime.main.parameters.ClRuntimeParameterGroup;
+import org.onap.policy.common.utils.coder.Coder;
+import org.onap.policy.common.utils.coder.CoderException;
+import org.onap.policy.common.utils.coder.StandardCoder;
+import org.onap.policy.common.utils.coder.YamlJsonTranslator;
+import org.onap.policy.common.utils.resources.ResourceUtils;
+import org.onap.policy.models.provider.PolicyModelsProviderParameters;
+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.ToscaNodeType;
+import org.onap.policy.models.tosca.authorative.concepts.ToscaServiceTemplate;
+
+public class CommissioningProviderTest {
+    private static final String TOSCA_SERVICE_TEMPLATE_YAML =
+            "src/test/resources/rest/servicetemplates/pmsh_multiple_cl_tosca.yaml";
+    private static final String TEMPLATE_IS_NULL = ".*serviceTemplate is marked non-null but is null";
+    private static final Coder CODER = new StandardCoder();
+    private static final YamlJsonTranslator yamlTranslator = new YamlJsonTranslator();
+    private static int dbNum = 0;
+    private static final Object lockit = new Object();
+    private PolicyModelsProviderParameters databaseProviderParameters;
+
+    private static String getParameterGroupAsString() {
+        dbNum++;
+        return ResourceUtils.getResourceAsString("src/test/resources/parameters/TestParameters.json")
+                .replace("jdbc:h2:mem:testdb", "jdbc:h2:mem:commissioningdb" + dbNum);
+    }
+
+    /**
+     * Sets up db provider parameters before each test.
+     *
+     * @throws CoderException .
+     */
+    @Before
+    public void setupDbProviderParameters() throws CoderException {
+        synchronized (lockit) {
+            databaseProviderParameters = CODER.decode(getParameterGroupAsString(), ClRuntimeParameterGroup.class)
+                    .getDatabaseProviderParameters();
+        }
+    }
+
+    /**
+     * Test the fetching of control loop definitions (ToscaServiceTemplates).
+     *
+     * @throws Exception .
+     */
+    @Test
+    public void testGetControlLoopDefinitions() throws Exception {
+        List<ToscaNodeTemplate> listOfTemplates;
+
+        try (CommissioningProvider provider = new CommissioningProvider(databaseProviderParameters)) {
+            ToscaServiceTemplate serviceTemplate = yamlTranslator
+                    .fromYaml(ResourceUtils.getResourceAsString(TOSCA_SERVICE_TEMPLATE_YAML),
+                            ToscaServiceTemplate.class);
+
+
+            listOfTemplates = provider.getControlLoopDefinitions(null, null);
+            assertThat(listOfTemplates).isEmpty();
+
+            provider.createControlLoopDefinitions(serviceTemplate);
+            listOfTemplates = provider.getControlLoopDefinitions(null, null);
+            assertThat(listOfTemplates).hasSize(2);
+
+            //Test Filtering
+            listOfTemplates = provider.getControlLoopDefinitions("org.onap.domain.pmsh.PMSHControlLoopDefinition",
+                    "1.2.3");
+            assertThat(listOfTemplates).hasSize(1);
+            for (ToscaNodeTemplate template : listOfTemplates) {
+                //Other CL elements contain PMSD instead of PMSH in their name
+                assertFalse(template.getName().contains("PMSD"));
+            }
+
+            //Test Wrong Name
+            listOfTemplates = provider.getControlLoopDefinitions("WrongControlLoopName", "0.0.0");
+            assertThat(listOfTemplates).isEmpty();
+        }
+    }
+
+    /**
+     * Test the creation of control loop definitions (ToscaServiceTemplates).
+     *
+     * @throws Exception .
+     */
+    @Test
+    public void testCreateControlLoopDefinitions() throws Exception {
+        List<ToscaNodeTemplate> listOfTemplates;
+
+        try (CommissioningProvider provider = new CommissioningProvider(databaseProviderParameters)) {
+            //Test Service template is null
+            assertThatThrownBy(() -> provider.createControlLoopDefinitions(null)).hasMessageMatching(TEMPLATE_IS_NULL);
+            listOfTemplates = provider.getControlLoopDefinitions(null, null);
+            assertThat(listOfTemplates).isEmpty();
+
+            ToscaServiceTemplate serviceTemplate = yamlTranslator
+                    .fromYaml(ResourceUtils.getResourceAsString(TOSCA_SERVICE_TEMPLATE_YAML),
+                            ToscaServiceTemplate.class);
+
+            // Response should return the number of node templates present in the service template
+            List<ToscaConceptIdentifier> affectedDefinitions =
+                    provider.createControlLoopDefinitions(serviceTemplate).getAffectedControlLoopDefinitions();
+            assertThat(affectedDefinitions).hasSize(13);
+            listOfTemplates = provider.getControlLoopDefinitions(null, null);
+            assertThat(listOfTemplates).hasSize(2);
+        }
+    }
+
+    /**
+     * Test the deletion of control loop definitions (ToscaServiceTemplate).
+     *
+     * @throws Exception .
+     */
+    @Test
+    public void testDeleteControlLoopDefinitions() throws Exception {
+        List<ToscaNodeTemplate> listOfTemplates;
+
+        try (CommissioningProvider provider = new CommissioningProvider(databaseProviderParameters)) {
+            ToscaServiceTemplate serviceTemplate = yamlTranslator
+                    .fromYaml(ResourceUtils.getResourceAsString(TOSCA_SERVICE_TEMPLATE_YAML),
+                            ToscaServiceTemplate.class);
+
+            listOfTemplates = provider.getControlLoopDefinitions(null, null);
+            assertThat(listOfTemplates).isEmpty();
+
+            provider.createControlLoopDefinitions(serviceTemplate);
+            listOfTemplates = provider.getControlLoopDefinitions(null, null);
+            assertThat(listOfTemplates).hasSize(2);
+
+            provider.deleteControlLoopDefinition(serviceTemplate.getName(), serviceTemplate.getVersion());
+            listOfTemplates = provider.getControlLoopDefinitions(null, null);
+            assertThat(listOfTemplates).isEmpty();
+        }
+    }
+
+    /**
+     * Test the fetching of control loop element definitions.
+     *
+     * @throws Exception .
+     */
+    @Test
+    public void testGetControlLoopElementDefinitions() throws Exception {
+        try (CommissioningProvider provider = new CommissioningProvider(databaseProviderParameters)) {
+            ToscaServiceTemplate serviceTemplate = yamlTranslator
+                    .fromYaml(ResourceUtils.getResourceAsString(TOSCA_SERVICE_TEMPLATE_YAML),
+                            ToscaServiceTemplate.class);
+
+            provider.getControlLoopDefinitions(null, null);
+
+            provider.createControlLoopDefinitions(serviceTemplate);
+            List<ToscaNodeTemplate> controlLoopDefinitionList = provider.getControlLoopDefinitions(
+                    "org.onap.domain.pmsh.PMSHControlLoopDefinition", "1.2.3");
+
+            List<ToscaNodeTemplate> controlLoopElementNodeTemplates =
+                    provider.getControlLoopElementDefinitions(controlLoopDefinitionList.get(0));
+
+            // 4 PMSH control loop elements definitions.
+            assertThat(controlLoopElementNodeTemplates).hasSize(4);
+
+            List<ToscaNodeType> derivedTypes = getDerivedNodeTypes(serviceTemplate);
+            for (ToscaNodeTemplate template : controlLoopElementNodeTemplates) {
+                assertTrue(checkNodeType(template, derivedTypes));
+            }
+        }
+    }
+
+    private boolean checkNodeType(ToscaNodeTemplate template, List<ToscaNodeType> derivedNodeTypes) {
+        String controlLoopElementType = "org.onap.policy.clamp.controlloop.ControlLoopElement";
+        for (ToscaNodeType derivedType : derivedNodeTypes) {
+            if (template.getType().equals(derivedType.getName()) || template.getType().equals(controlLoopElementType)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    private List<ToscaNodeType> getDerivedNodeTypes(ToscaServiceTemplate serviceTemplate) {
+        String type = "org.onap.policy.clamp.controlloop.ControlLoopElement";
+        List<ToscaNodeType> nodeTypes = new ArrayList<>();
+        for (ToscaNodeType nodeType : serviceTemplate.getNodeTypes().values()) {
+            if (nodeType.getDerivedFrom().equals(type)) {
+                nodeTypes.add(nodeType);
+            }
+        }
+        return nodeTypes;
+    }
+}
diff --git a/runtime-controlloop/src/test/java/org/onap/policy/clamp/controlloop/runtime/commissioning/rest/CommissioningControllerTest.java b/runtime-controlloop/src/test/java/org/onap/policy/clamp/controlloop/runtime/commissioning/rest/CommissioningControllerTest.java
new file mode 100644
index 0000000..4dbb3ea
--- /dev/null
+++ b/runtime-controlloop/src/test/java/org/onap/policy/clamp/controlloop/runtime/commissioning/rest/CommissioningControllerTest.java
@@ -0,0 +1,202 @@
+/*-
+ * ============LICENSE_START=======================================================
+ *  Copyright (C) 2021 Nordix Foundation.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.policy.clamp.controlloop.runtime.commissioning.rest;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+
+import java.util.List;
+import javax.ws.rs.client.Entity;
+import javax.ws.rs.client.Invocation;
+import javax.ws.rs.core.Response;
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.onap.policy.clamp.controlloop.models.messages.rest.commissioning.CommissioningResponse;
+import org.onap.policy.clamp.controlloop.runtime.util.rest.CommonRestController;
+import org.onap.policy.common.utils.coder.YamlJsonTranslator;
+import org.onap.policy.common.utils.resources.ResourceUtils;
+import org.onap.policy.models.provider.PolicyModelsProvider;
+import org.onap.policy.models.provider.PolicyModelsProviderFactory;
+import org.onap.policy.models.tosca.authorative.concepts.ToscaServiceTemplate;
+
+public class CommissioningControllerTest extends CommonRestController {
+
+    private static final String TOSCA_SERVICE_TEMPLATE_YAML =
+            "src/test/resources/rest/servicetemplates/pmsh_multiple_cl_tosca.yaml";
+    private static final YamlJsonTranslator yamlTranslator = new YamlJsonTranslator();
+    private static final String COMMISSIONING_ENDPOINT = "commission";
+    private static ToscaServiceTemplate serviceTemplate = new ToscaServiceTemplate();
+
+    /**
+     * starts Main and inserts a commissioning template.
+     *
+     * @throws Exception if an error occurs
+     */
+    @BeforeClass
+    public static void setUpBeforeClass() throws Exception {
+        CommonRestController.setUpBeforeClass("CommissioningApi");
+
+        serviceTemplate = yamlTranslator.fromYaml(ResourceUtils.getResourceAsString(TOSCA_SERVICE_TEMPLATE_YAML),
+                ToscaServiceTemplate.class);
+    }
+
+    @AfterClass
+    public static void teardownAfterClass() {
+        CommonRestController.teardownAfterClass();
+    }
+
+    @Test
+    public void testSwagger() throws Exception {
+        super.testSwagger(COMMISSIONING_ENDPOINT);
+    }
+
+    @Test
+    public void testUnauthorizedCreate() throws Exception {
+        assertUnauthorizedPost(COMMISSIONING_ENDPOINT, Entity.json(serviceTemplate));
+    }
+
+    @Test
+    public void testUnauthorizedQuery() throws Exception {
+        assertUnauthorizedGet(COMMISSIONING_ENDPOINT);
+    }
+
+    @Test
+    public void testUnauthorizedQueryElements() throws Exception {
+        assertUnauthorizedGet(COMMISSIONING_ENDPOINT + "/elements");
+    }
+
+    @Test
+    public void testUnauthorizedDelete() throws Exception {
+        assertUnauthorizedDelete(COMMISSIONING_ENDPOINT);
+    }
+
+    @Test
+    public void testCreateBadRequest() throws Exception {
+        Invocation.Builder invocationBuilder = super.sendRequest(COMMISSIONING_ENDPOINT);
+        Response resp = invocationBuilder.post(Entity.json("NotToscaServiceTempalte"));
+
+        assertEquals(Response.Status.BAD_REQUEST.getStatusCode(), resp.getStatus());
+        CommissioningResponse commissioningResponse = resp.readEntity(CommissioningResponse.class);
+        assertNotNull(commissioningResponse.getErrorDetails());
+        assertNull(commissioningResponse.getAffectedControlLoopDefinitions());
+    }
+
+    @Test
+    public void testCreate() throws Exception {
+        Invocation.Builder invocationBuilder = super.sendRequest(COMMISSIONING_ENDPOINT);
+        Response resp = invocationBuilder.post(Entity.json(serviceTemplate));
+        assertEquals(Response.Status.OK.getStatusCode(), resp.getStatus());
+        CommissioningResponse commissioningResponse = resp.readEntity(CommissioningResponse.class);
+
+        assertNotNull(commissioningResponse);
+        assertNull(commissioningResponse.getErrorDetails());
+        // Response should return the number of node templates present in the service template
+        assertThat(commissioningResponse.getAffectedControlLoopDefinitions()).hasSize(13);
+        for (String nodeTemplateName : serviceTemplate.getToscaTopologyTemplate().getNodeTemplates().keySet()) {
+            assertTrue(commissioningResponse.getAffectedControlLoopDefinitions().stream()
+                    .anyMatch(ac -> ac.getName().equals(nodeTemplateName)));
+        }
+    }
+
+    @Test
+    public void testQuery_NoResultWithThisName() throws Exception {
+        createEntryInDB();
+
+        Invocation.Builder invocationBuilder = super.sendRequest(COMMISSIONING_ENDPOINT + "?name=noResultWithThisName");
+        Response rawresp = invocationBuilder.buildGet().invoke();
+        assertEquals(Response.Status.OK.getStatusCode(), rawresp.getStatus());
+        List entityList = rawresp.readEntity(List.class);
+        assertThat(entityList).isEmpty();
+    }
+
+    @Test
+    public void testQuery() throws Exception {
+        createEntryInDB();
+
+        Invocation.Builder invocationBuilder = super.sendRequest(COMMISSIONING_ENDPOINT);
+        Response rawresp = invocationBuilder.buildGet().invoke();
+        assertEquals(Response.Status.OK.getStatusCode(), rawresp.getStatus());
+        List entityList = rawresp.readEntity(List.class);
+        assertNotNull(entityList);
+        assertThat(entityList).hasSize(2);
+    }
+
+    @Test
+    public void testQueryElementsBadRequest() throws Exception {
+        createEntryInDB();
+
+        //Call get elements with no info
+        Invocation.Builder invocationBuilder = super.sendRequest(COMMISSIONING_ENDPOINT + "/elements");
+        Response resp = invocationBuilder.buildGet().invoke();
+        assertEquals(Response.Status.NOT_ACCEPTABLE.getStatusCode(), resp.getStatus());
+    }
+
+    @Test
+    public void testQueryElements() throws Exception {
+        createEntryInDB();
+
+        Invocation.Builder invocationBuilder = super.sendRequest(COMMISSIONING_ENDPOINT + "/elements"
+                + "?name=org.onap.domain.pmsh.PMSHControlLoopDefinition");
+        Response rawresp = invocationBuilder.buildGet().invoke();
+        assertEquals(Response.Status.OK.getStatusCode(), rawresp.getStatus());
+        List entityList = rawresp.readEntity(List.class);
+        assertNotNull(entityList);
+        assertThat(entityList).hasSize(4);
+    }
+
+    @Test
+    public void testDeleteBadRequest() throws Exception {
+        createEntryInDB();
+
+        Invocation.Builder invocationBuilder = super.sendRequest(COMMISSIONING_ENDPOINT);
+        //Call delete with no info
+        Response resp = invocationBuilder.delete();
+        assertEquals(Response.Status.INTERNAL_SERVER_ERROR.getStatusCode(), resp.getStatus());
+    }
+
+    @Test
+    public void testDelete() throws Exception {
+        createEntryInDB();
+
+        Invocation.Builder invocationBuilder = super.sendRequest(COMMISSIONING_ENDPOINT + "?name="
+                + serviceTemplate.getName() + "&version=" + serviceTemplate.getVersion());
+        //Call delete with no info
+        Response resp = invocationBuilder.delete();
+        assertEquals(Response.Status.OK.getStatusCode(), resp.getStatus());
+
+        try (PolicyModelsProvider modelsProvider = new PolicyModelsProviderFactory()
+                .createPolicyModelsProvider(CommonRestController.getParameters())) {
+            List<ToscaServiceTemplate> templatesInDB = modelsProvider.getServiceTemplateList(null, null);
+            assertThat(templatesInDB).isEmpty();
+        }
+    }
+
+    private synchronized void createEntryInDB() throws Exception {
+        try (PolicyModelsProvider modelsProvider = new PolicyModelsProviderFactory()
+                .createPolicyModelsProvider(CommonRestController.getParameters())) {
+            modelsProvider.createServiceTemplate(serviceTemplate);
+        }
+    }
+}
diff --git a/runtime-controlloop/src/test/java/org/onap/policy/clamp/controlloop/runtime/instantiation/ControlLoopInstantiationProviderTest.java b/runtime-controlloop/src/test/java/org/onap/policy/clamp/controlloop/runtime/instantiation/ControlLoopInstantiationProviderTest.java
new file mode 100644
index 0000000..ccc54b9
--- /dev/null
+++ b/runtime-controlloop/src/test/java/org/onap/policy/clamp/controlloop/runtime/instantiation/ControlLoopInstantiationProviderTest.java
@@ -0,0 +1,370 @@
+/*-
+ * ============LICENSE_START=======================================================
+ *  Copyright (C) 2021 Nordix Foundation.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.policy.clamp.controlloop.runtime.instantiation;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.assertThatThrownBy;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Collections;
+import org.junit.Assert;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.mockito.Mockito;
+import org.onap.policy.clamp.controlloop.common.exception.ControlLoopRuntimeException;
+import org.onap.policy.clamp.controlloop.models.controlloop.concepts.ControlLoop;
+import org.onap.policy.clamp.controlloop.models.controlloop.concepts.ControlLoopState;
+import org.onap.policy.clamp.controlloop.models.controlloop.concepts.ControlLoops;
+import org.onap.policy.clamp.controlloop.models.messages.rest.instantiation.InstantiationCommand;
+import org.onap.policy.clamp.controlloop.models.messages.rest.instantiation.InstantiationResponse;
+import org.onap.policy.clamp.controlloop.runtime.commissioning.CommissioningHandler;
+import org.onap.policy.clamp.controlloop.runtime.supervision.SupervisionHandler;
+import org.onap.policy.clamp.controlloop.runtime.util.CommonTestData;
+import org.onap.policy.common.endpoints.event.comm.TopicSink;
+import org.onap.policy.models.base.PfModelException;
+import org.onap.policy.models.provider.PolicyModelsProviderParameters;
+import org.onap.policy.models.tosca.authorative.concepts.ToscaConceptIdentifier;
+
+/**
+ * Class to perform unit test of {@link ControlLoopInstantiationProvider}}.
+ *
+ */
+public class ControlLoopInstantiationProviderTest {
+
+    private static final String CL_INSTANTIATION_CREATE_JSON = "src/test/resources/rest/controlloops/ControlLoops.json";
+    private static final String CL_INSTANTIATION_UPDATE_JSON =
+            "src/test/resources/rest/controlloops/ControlLoopsUpdate.json";
+    private static final String CL_INSTANTIATION_CHANGE_STATE_JSON =
+            "src/test/resources/rest/controlloops/PassiveCommand.json";
+    private static final String CL_INSTANTIATION_DEFINITION_NAME_NOT_FOUND_JSON =
+            "src/test/resources/rest/controlloops/ControlLoopElementsNotFound.json";
+    private static final String CL_INSTANTIATION_CONTROLLOOP_DEFINITION_NOT_FOUND_JSON =
+            "src/test/resources/rest/controlloops/ControlLoopsNotFound.json";
+    private static final String TOSCA_TEMPLATE_YAML =
+            "src/test/resources/rest/servicetemplates/pmsh_multiple_cl_tosca.yaml";
+    private static final String CONTROL_LOOP_NOT_FOUND = "Control Loop not found";
+    private static final String DELETE_BAD_REQUEST = "Control Loop State is still %s";
+    private static final String ORDERED_STATE_INVALID = "ordered state invalid or not specified on command";
+    private static final String CONTROLLOOP_ELEMENT_NAME_NOT_FOUND =
+            "\"ControlLoops\" INVALID, item has status INVALID\n"
+            + "  \"entry org.onap.domain.pmsh.PMSHControlLoopDefinition\" INVALID, item has status INVALID\n"
+            + "    \"entry org.onap.domain.pmsh.DCAEMicroservice\" INVALID, Not FOUND\n"
+            + "  \"entry org.onap.domain.pmsh.PMSHControlLoopDefinition\" INVALID, item has status INVALID\n"
+            + "    \"entry org.onap.domain.pmsh.DCAEMicroservice\" INVALID, Not FOUND\n";
+
+    private static final String CONTROLLOOP_DEFINITION_NOT_FOUND = "\"ControlLoops\" INVALID, item has status INVALID\n"
+            + "  \"entry org.onap.domain.PMSHControlLoopDefinition\" INVALID, item has status INVALID\n"
+            + "    item \"ControlLoop\" value \"org.onap.domain.PMSHControlLoopDefinition\" INVALID,"
+            + " Commissioned control loop definition not FOUND\n"
+            + "  \"entry org.onap.domain.PMSHControlLoopDefinition\" INVALID, item has status INVALID\n"
+            + "    item \"ControlLoop\" value \"org.onap.domain.PMSHControlLoopDefinition\" INVALID,"
+            + " Commissioned control loop definition not FOUND\n";
+
+    private static PolicyModelsProviderParameters databaseProviderParameters;
+    private static SupervisionHandler supervisionHandler;
+    private static CommissioningHandler commissioningHandler;
+
+    /**
+     * setup Db Provider Parameters.
+     *
+     * @throws PfModelException if an error occurs
+     */
+    @BeforeClass
+    public static void setupDbProviderParameters() throws PfModelException {
+        databaseProviderParameters =
+                CommonTestData.geParameterGroup(0, "instantproviderdb").getDatabaseProviderParameters();
+        commissioningHandler = new CommissioningHandler(CommonTestData.geParameterGroup(0, "instantproviderdb"));
+        commissioningHandler.startProviders();
+        supervisionHandler = new SupervisionHandler(CommonTestData.geParameterGroup(0, "instantproviderdb"));
+        supervisionHandler.startProviders();
+        supervisionHandler.startAndRegisterPublishers(Collections.singletonList(Mockito.mock(TopicSink.class)));
+    }
+
+    @Test
+    public void testInstantiationCrud() throws Exception {
+        ControlLoops controlLoopsCreate =
+                InstantiationUtils.getControlLoopsFromResource(CL_INSTANTIATION_CREATE_JSON, "Crud");
+        ControlLoops controlLoopsDb = getControlLoopsFromDb(controlLoopsCreate);
+        assertThat(controlLoopsDb.getControlLoopList()).isEmpty();
+        try (ControlLoopInstantiationProvider instantiationProvider =
+                     new ControlLoopInstantiationProvider(databaseProviderParameters)) {
+
+            // to validate control Loop, it needs to define ToscaServiceTemplate
+            InstantiationUtils.storeToscaServiceTemplate(TOSCA_TEMPLATE_YAML, databaseProviderParameters);
+
+            InstantiationResponse instantiationResponse = instantiationProvider.createControlLoops(controlLoopsCreate);
+            InstantiationUtils.assertInstantiationResponse(instantiationResponse, controlLoopsCreate);
+
+            controlLoopsDb = getControlLoopsFromDb(controlLoopsCreate);
+            assertThat(controlLoopsDb.getControlLoopList()).isNotEmpty();
+            Assert.assertEquals(controlLoopsCreate, controlLoopsDb);
+
+            for (ControlLoop controlLoop : controlLoopsCreate.getControlLoopList()) {
+                ControlLoops controlLoopsGet =
+                        instantiationProvider.getControlLoops(controlLoop.getName(), controlLoop.getVersion());
+                assertThat(controlLoopsGet.getControlLoopList()).hasSize(1);
+                Assert.assertEquals(controlLoop, controlLoopsGet.getControlLoopList().get(0));
+            }
+
+            ControlLoops controlLoopsUpdate =
+                    InstantiationUtils.getControlLoopsFromResource(CL_INSTANTIATION_UPDATE_JSON, "Crud");
+            Assert.assertNotEquals(controlLoopsUpdate, controlLoopsDb);
+
+            instantiationResponse = instantiationProvider.updateControlLoops(controlLoopsUpdate);
+            InstantiationUtils.assertInstantiationResponse(instantiationResponse, controlLoopsUpdate);
+
+            controlLoopsDb = getControlLoopsFromDb(controlLoopsCreate);
+            assertThat(controlLoopsDb.getControlLoopList()).isNotEmpty();
+            Assert.assertEquals(controlLoopsUpdate, controlLoopsDb);
+
+            InstantiationCommand instantiationCommand =
+                    InstantiationUtils.getInstantiationCommandFromResource(CL_INSTANTIATION_CHANGE_STATE_JSON, "Crud");
+            instantiationResponse = instantiationProvider.issueControlLoopCommand(instantiationCommand);
+            InstantiationUtils.assertInstantiationResponse(instantiationResponse, instantiationCommand);
+
+            for (ToscaConceptIdentifier toscaConceptIdentifier : instantiationCommand.getControlLoopIdentifierList()) {
+                ControlLoops controlLoopsGet = instantiationProvider.getControlLoops(toscaConceptIdentifier.getName(),
+                        toscaConceptIdentifier.getVersion());
+                assertThat(controlLoopsGet.getControlLoopList()).hasSize(1);
+                Assert.assertEquals(instantiationCommand.getOrderedState(),
+                        controlLoopsGet.getControlLoopList().get(0).getOrderedState());
+            }
+
+            // in order to delete a controlLoop the state must be UNINITIALISED
+            controlLoopsCreate.getControlLoopList().forEach(cl -> cl.setState(ControlLoopState.UNINITIALISED));
+            instantiationProvider.updateControlLoops(controlLoopsCreate);
+
+            for (ControlLoop controlLoop : controlLoopsCreate.getControlLoopList()) {
+                instantiationProvider.deleteControlLoop(controlLoop.getName(), controlLoop.getVersion());
+            }
+
+            controlLoopsDb = getControlLoopsFromDb(controlLoopsCreate);
+            assertThat(controlLoopsDb.getControlLoopList()).isEmpty();
+        }
+    }
+
+    private ControlLoops getControlLoopsFromDb(ControlLoops controlLoopsSource) throws Exception {
+        ControlLoops controlLoopsDb = new ControlLoops();
+        controlLoopsDb.setControlLoopList(new ArrayList<>());
+
+        try (ControlLoopInstantiationProvider instantiationProvider =
+                     new ControlLoopInstantiationProvider(databaseProviderParameters)) {
+
+            for (ControlLoop controlLoop : controlLoopsSource.getControlLoopList()) {
+                ControlLoops controlLoopsFromDb =
+                        instantiationProvider.getControlLoops(controlLoop.getName(), controlLoop.getVersion());
+                controlLoopsDb.getControlLoopList().addAll(controlLoopsFromDb.getControlLoopList());
+            }
+            return controlLoopsDb;
+        }
+    }
+
+    @Test
+    public void testInstantiationDelete() throws Exception {
+        ControlLoops controlLoops =
+                InstantiationUtils.getControlLoopsFromResource(CL_INSTANTIATION_CREATE_JSON, "Delete");
+        assertThat(getControlLoopsFromDb(controlLoops).getControlLoopList()).isEmpty();
+
+        ControlLoop controlLoop0 = controlLoops.getControlLoopList().get(0);
+
+        try (ControlLoopInstantiationProvider instantiationProvider =
+                     new ControlLoopInstantiationProvider(databaseProviderParameters)) {
+
+            // to validate control Loop, it needs to define ToscaServiceTemplate
+            InstantiationUtils.storeToscaServiceTemplate(TOSCA_TEMPLATE_YAML, databaseProviderParameters);
+
+            assertThatThrownBy(
+                    () -> instantiationProvider.deleteControlLoop(controlLoop0.getName(), controlLoop0.getVersion()))
+                    .hasMessageMatching(CONTROL_LOOP_NOT_FOUND);
+
+            InstantiationUtils.assertInstantiationResponse(instantiationProvider.createControlLoops(controlLoops),
+                    controlLoops);
+
+            for (ControlLoopState state : ControlLoopState.values()) {
+                if (!ControlLoopState.UNINITIALISED.equals(state)) {
+                    assertThatDeleteThrownBy(controlLoops, state);
+                }
+            }
+
+            controlLoop0.setState(ControlLoopState.UNINITIALISED);
+            instantiationProvider.updateControlLoops(controlLoops);
+
+            for (ControlLoop controlLoop : controlLoops.getControlLoopList()) {
+                instantiationProvider.deleteControlLoop(controlLoop.getName(), controlLoop.getVersion());
+            }
+
+            for (ControlLoop controlLoop : controlLoops.getControlLoopList()) {
+                ControlLoops controlLoopsGet =
+                        instantiationProvider.getControlLoops(controlLoop.getName(), controlLoop.getVersion());
+                assertThat(controlLoopsGet.getControlLoopList()).isEmpty();
+            }
+        }
+    }
+
+    private void assertThatDeleteThrownBy(ControlLoops controlLoops, ControlLoopState state) throws Exception {
+        ControlLoop controlLoop = controlLoops.getControlLoopList().get(0);
+
+        controlLoop.setState(state);
+
+        try (ControlLoopInstantiationProvider instantiationProvider =
+                     new ControlLoopInstantiationProvider(databaseProviderParameters)) {
+
+            instantiationProvider.updateControlLoops(controlLoops);
+            assertThatThrownBy(
+                    () -> instantiationProvider.deleteControlLoop(controlLoop.getName(), controlLoop.getVersion()))
+                    .hasMessageMatching(String.format(DELETE_BAD_REQUEST, state));
+        }
+    }
+
+    @Test
+    public void testCreateControlLoops_NoDuplicates() throws Exception {
+        ControlLoops controlLoopsCreate =
+                InstantiationUtils.getControlLoopsFromResource(CL_INSTANTIATION_CREATE_JSON, "NoDuplicates");
+
+        ControlLoops controlLoopsDb = getControlLoopsFromDb(controlLoopsCreate);
+        assertThat(controlLoopsDb.getControlLoopList()).isEmpty();
+
+        try (ControlLoopInstantiationProvider instantiationProvider =
+                     new ControlLoopInstantiationProvider(databaseProviderParameters)) {
+
+            // to validate control Loop, it needs to define ToscaServiceTemplate
+            InstantiationUtils.storeToscaServiceTemplate(TOSCA_TEMPLATE_YAML, databaseProviderParameters);
+
+            InstantiationResponse instantiationResponse = instantiationProvider.createControlLoops(controlLoopsCreate);
+            InstantiationUtils.assertInstantiationResponse(instantiationResponse, controlLoopsCreate);
+
+            assertThatThrownBy(() -> instantiationProvider.createControlLoops(controlLoopsCreate)).hasMessageMatching(
+                    controlLoopsCreate.getControlLoopList().get(0).getKey().asIdentifier() + " already defined");
+
+            for (ControlLoop controlLoop : controlLoopsCreate.getControlLoopList()) {
+                instantiationProvider.deleteControlLoop(controlLoop.getName(), controlLoop.getVersion());
+            }
+        }
+    }
+
+    @Test
+    public void testCreateControlLoops_CommissionedClElementNotFound() throws Exception {
+        ControlLoops controlLoops = InstantiationUtils
+                .getControlLoopsFromResource(CL_INSTANTIATION_DEFINITION_NAME_NOT_FOUND_JSON, "ClElementNotFound");
+
+        try (ControlLoopInstantiationProvider provider =
+                     new ControlLoopInstantiationProvider(databaseProviderParameters)) {
+
+            // to validate control Loop, it needs to define ToscaServiceTemplate
+            InstantiationUtils.storeToscaServiceTemplate(TOSCA_TEMPLATE_YAML, databaseProviderParameters);
+
+            assertThat(getControlLoopsFromDb(controlLoops).getControlLoopList()).isEmpty();
+
+            assertThatThrownBy(() -> provider.createControlLoops(controlLoops))
+                    .hasMessageMatching(CONTROLLOOP_ELEMENT_NAME_NOT_FOUND);
+        }
+    }
+
+    @Test
+    public void testCreateControlLoops_CommissionedClNotFound() throws Exception {
+        ControlLoops controlLoops = InstantiationUtils
+                .getControlLoopsFromResource(CL_INSTANTIATION_CONTROLLOOP_DEFINITION_NOT_FOUND_JSON, "ClNotFound");
+
+        assertThat(getControlLoopsFromDb(controlLoops).getControlLoopList()).isEmpty();
+
+        try (ControlLoopInstantiationProvider provider =
+                     new ControlLoopInstantiationProvider(databaseProviderParameters)) {
+            assertThatThrownBy(() -> provider.createControlLoops(controlLoops))
+                    .hasMessageMatching(CONTROLLOOP_DEFINITION_NOT_FOUND);
+        }
+    }
+
+    @Test
+    public void testIssueControlLoopCommand_OrderedStateInvalid() throws ControlLoopRuntimeException, IOException {
+        try (ControlLoopInstantiationProvider instantiationProvider =
+                     new ControlLoopInstantiationProvider(databaseProviderParameters)) {
+            assertThatThrownBy(() -> instantiationProvider.issueControlLoopCommand(new InstantiationCommand()))
+                    .hasMessageMatching(ORDERED_STATE_INVALID);
+        }
+    }
+
+    @Test
+    public void testInstantiationVersions() throws Exception {
+
+        // create controlLoops V1
+        ControlLoops controlLoopsV1 =
+                InstantiationUtils.getControlLoopsFromResource(CL_INSTANTIATION_CREATE_JSON, "V1");
+        assertThat(getControlLoopsFromDb(controlLoopsV1).getControlLoopList()).isEmpty();
+
+        try (ControlLoopInstantiationProvider instantiationProvider =
+                     new ControlLoopInstantiationProvider(databaseProviderParameters)) {
+
+            // to validate control Loop, it needs to define ToscaServiceTemplate
+            InstantiationUtils.storeToscaServiceTemplate(TOSCA_TEMPLATE_YAML, databaseProviderParameters);
+
+            InstantiationUtils.assertInstantiationResponse(instantiationProvider.createControlLoops(controlLoopsV1),
+                    controlLoopsV1);
+
+            // create controlLoops V2
+            ControlLoops controlLoopsV2 =
+                    InstantiationUtils.getControlLoopsFromResource(CL_INSTANTIATION_CREATE_JSON, "V2");
+            assertThat(getControlLoopsFromDb(controlLoopsV2).getControlLoopList()).isEmpty();
+            InstantiationUtils.assertInstantiationResponse(instantiationProvider.createControlLoops(controlLoopsV2),
+                    controlLoopsV2);
+
+            // GET controlLoops V2
+            for (ControlLoop controlLoop : controlLoopsV2.getControlLoopList()) {
+                ControlLoops controlLoopsGet =
+                        instantiationProvider.getControlLoops(controlLoop.getName(), controlLoop.getVersion());
+                assertThat(controlLoopsGet.getControlLoopList()).hasSize(1);
+                Assert.assertEquals(controlLoop, controlLoopsGet.getControlLoopList().get(0));
+            }
+
+            // DELETE controlLoops V1
+            for (ControlLoop controlLoop : controlLoopsV1.getControlLoopList()) {
+                instantiationProvider.deleteControlLoop(controlLoop.getName(), controlLoop.getVersion());
+            }
+
+            // GET controlLoops V1 is not available
+            for (ControlLoop controlLoop : controlLoopsV1.getControlLoopList()) {
+                ControlLoops controlLoopsGet =
+                        instantiationProvider.getControlLoops(controlLoop.getName(), controlLoop.getVersion());
+                assertThat(controlLoopsGet.getControlLoopList()).isEmpty();
+            }
+
+            // GET controlLoops V2 is still available
+            for (ControlLoop controlLoop : controlLoopsV2.getControlLoopList()) {
+                ControlLoops controlLoopsGet =
+                        instantiationProvider.getControlLoops(controlLoop.getName(), controlLoop.getVersion());
+                assertThat(controlLoopsGet.getControlLoopList()).hasSize(1);
+                Assert.assertEquals(controlLoop, controlLoopsGet.getControlLoopList().get(0));
+            }
+
+            // DELETE controlLoops V2
+            for (ControlLoop controlLoop : controlLoopsV2.getControlLoopList()) {
+                instantiationProvider.deleteControlLoop(controlLoop.getName(), controlLoop.getVersion());
+            }
+
+            // GET controlLoops V2 is not available
+            for (ControlLoop controlLoop : controlLoopsV2.getControlLoopList()) {
+                ControlLoops controlLoopsGet =
+                        instantiationProvider.getControlLoops(controlLoop.getName(), controlLoop.getVersion());
+                assertThat(controlLoopsGet.getControlLoopList()).isEmpty();
+            }
+        }
+    }
+}
diff --git a/runtime-controlloop/src/test/java/org/onap/policy/clamp/controlloop/runtime/instantiation/InstantiationUtils.java b/runtime-controlloop/src/test/java/org/onap/policy/clamp/controlloop/runtime/instantiation/InstantiationUtils.java
new file mode 100644
index 0000000..958d91d
--- /dev/null
+++ b/runtime-controlloop/src/test/java/org/onap/policy/clamp/controlloop/runtime/instantiation/InstantiationUtils.java
@@ -0,0 +1,149 @@
+/*-
+ * ============LICENSE_START=======================================================
+ *  Copyright (C) 2021 Nordix Foundation.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.policy.clamp.controlloop.runtime.instantiation;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
+import java.io.File;
+import org.junit.Assert;
+import org.onap.policy.clamp.controlloop.models.controlloop.concepts.ControlLoop;
+import org.onap.policy.clamp.controlloop.models.controlloop.concepts.ControlLoops;
+import org.onap.policy.clamp.controlloop.models.messages.rest.instantiation.InstantiationCommand;
+import org.onap.policy.clamp.controlloop.models.messages.rest.instantiation.InstantiationResponse;
+import org.onap.policy.common.utils.coder.Coder;
+import org.onap.policy.common.utils.coder.CoderException;
+import org.onap.policy.common.utils.coder.StandardCoder;
+import org.onap.policy.common.utils.coder.YamlJsonTranslator;
+import org.onap.policy.common.utils.resources.ResourceUtils;
+import org.onap.policy.models.base.PfModelException;
+import org.onap.policy.models.provider.PolicyModelsProvider;
+import org.onap.policy.models.provider.PolicyModelsProviderFactory;
+import org.onap.policy.models.provider.PolicyModelsProviderParameters;
+import org.onap.policy.models.tosca.authorative.concepts.ToscaConceptIdentifier;
+import org.onap.policy.models.tosca.authorative.concepts.ToscaServiceTemplate;
+
+/**
+ * Utility methods supporting tests for Instantiation.
+ */
+public class InstantiationUtils {
+
+    private static final Coder CODER = new StandardCoder();
+    private static final YamlJsonTranslator yamlTranslator = new YamlJsonTranslator();
+
+    /**
+     * Gets the ControlLoops from Resource.
+     *
+     * @param path path of the resource
+     * @param suffix suffix to add to all names in ControlLoops
+     * @return the ControlLoops from Resource
+     * @throws CoderException if an error occurs
+     */
+    public static ControlLoops getControlLoopsFromResource(final String path, final String suffix)
+            throws CoderException {
+        ControlLoops controlLoops = CODER.decode(new File(path), ControlLoops.class);
+
+        // add suffix to all names
+        controlLoops.getControlLoopList().forEach(controlLoop -> controlLoop.setName(controlLoop.getName() + suffix));
+        return controlLoops;
+    }
+
+    /**
+     * Gets InstantiationCommand from Resource.
+     *
+     * @param path path of the resource
+     * @param suffix suffix to add to all names in ControlLoops
+     * @return the InstantiationCommand
+     * @throws CoderException if an error occurs
+     */
+    public static InstantiationCommand getInstantiationCommandFromResource(final String path, final String suffix)
+            throws CoderException {
+        InstantiationCommand instantiationCommand = CODER.decode(new File(path), InstantiationCommand.class);
+
+        // add suffix to all names
+        instantiationCommand.getControlLoopIdentifierList().forEach(cl -> cl.setName(cl.getName() + suffix));
+        return instantiationCommand;
+    }
+
+    /**
+     * Assert that Instantiation Response contains proper ControlLoops.
+     *
+     * @param response InstantiationResponse
+     * @param controlLoops ControlLoops
+     */
+    public static void assertInstantiationResponse(InstantiationResponse response, ControlLoops controlLoops) {
+        assertNotNull(response);
+        Assert.assertNull(response.getErrorDetails());
+        assertEquals(response.getAffectedControlLoops().size(), controlLoops.getControlLoopList().size());
+        for (ControlLoop controlLoop : controlLoops.getControlLoopList()) {
+            assertTrue(response.getAffectedControlLoops().stream()
+                    .filter(ac -> ac.equals(controlLoop.getKey().asIdentifier())).findAny().isPresent());
+        }
+    }
+
+    /**
+     * Assert that Instantiation Response contains proper ControlLoops.
+     *
+     * @param response InstantiationResponse
+     * @param command InstantiationCommand
+     */
+    public static void assertInstantiationResponse(InstantiationResponse response, InstantiationCommand command) {
+        assertNotNull(response);
+        assertEquals(response.getAffectedControlLoops().size(), command.getControlLoopIdentifierList().size());
+        for (ToscaConceptIdentifier toscaConceptIdentifier : command.getControlLoopIdentifierList()) {
+            assertTrue(response.getAffectedControlLoops().stream()
+                    .filter(ac -> ac.compareTo(toscaConceptIdentifier) == 0).findAny().isPresent());
+        }
+    }
+
+    /**
+     * Assert that Instantiation Response contains ControlLoop equals to controlLoop.
+     *
+     * @param response InstantiationResponse
+     * @param controlLoop ControlLoop
+     */
+    public static void assertInstantiationResponse(InstantiationResponse response, ControlLoop controlLoop) {
+        assertNotNull(response);
+        Assert.assertNull(response.getErrorDetails());
+        assertEquals(1, response.getAffectedControlLoops().size());
+        assertEquals(0, response.getAffectedControlLoops().get(0).compareTo(controlLoop.getKey().asIdentifier()));
+    }
+
+    /**
+     * Store ToscaServiceTemplate from resource to DB.
+     *
+     * @param path path of the resource
+     * @param parameters The parameters for the implementation of the PolicyModelProvider
+     * @throws PfModelException if an error occurs
+     */
+    public static void storeToscaServiceTemplate(String path, PolicyModelsProviderParameters parameters)
+            throws PfModelException {
+
+        ToscaServiceTemplate template =
+                yamlTranslator.fromYaml(ResourceUtils.getResourceAsString(path), ToscaServiceTemplate.class);
+
+        try (PolicyModelsProvider modelsProvider =
+                new PolicyModelsProviderFactory().createPolicyModelsProvider(parameters)) {
+            modelsProvider.createServiceTemplate(template);
+        }
+    }
+}
diff --git a/runtime-controlloop/src/test/java/org/onap/policy/clamp/controlloop/runtime/instantiation/rest/InstantiationControllerTest.java b/runtime-controlloop/src/test/java/org/onap/policy/clamp/controlloop/runtime/instantiation/rest/InstantiationControllerTest.java
new file mode 100644
index 0000000..71e7624
--- /dev/null
+++ b/runtime-controlloop/src/test/java/org/onap/policy/clamp/controlloop/runtime/instantiation/rest/InstantiationControllerTest.java
@@ -0,0 +1,322 @@
+/*-
+ * ============LICENSE_START=======================================================
+ *  Copyright (C) 2021 Nordix Foundation.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.policy.clamp.controlloop.runtime.instantiation.rest;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+
+import javax.ws.rs.client.Entity;
+import javax.ws.rs.client.Invocation;
+import javax.ws.rs.core.Response;
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.onap.policy.clamp.controlloop.models.controlloop.concepts.ControlLoop;
+import org.onap.policy.clamp.controlloop.models.controlloop.concepts.ControlLoops;
+import org.onap.policy.clamp.controlloop.models.messages.rest.instantiation.InstantiationCommand;
+import org.onap.policy.clamp.controlloop.models.messages.rest.instantiation.InstantiationResponse;
+import org.onap.policy.clamp.controlloop.runtime.instantiation.ControlLoopInstantiationProvider;
+import org.onap.policy.clamp.controlloop.runtime.instantiation.InstantiationUtils;
+import org.onap.policy.clamp.controlloop.runtime.util.rest.CommonRestController;
+import org.onap.policy.models.tosca.authorative.concepts.ToscaConceptIdentifier;
+
+/**
+ * Class to perform unit test of {@link InstantiationController}}.
+ *
+ */
+public class InstantiationControllerTest extends CommonRestController {
+
+    private static final String CL_INSTANTIATION_CREATE_JSON = "src/test/resources/rest/controlloops/ControlLoops.json";
+
+    private static final String CL_INSTANTIATION_UPDATE_JSON =
+            "src/test/resources/rest/controlloops/ControlLoopsUpdate.json";
+
+    private static final String CL_INSTANTIATION_CHANGE_STATE_JSON =
+            "src/test/resources/rest/controlloops/PassiveCommand.json";
+
+    private static final String TOSCA_TEMPLATE_YAML =
+            "src/test/resources/rest/servicetemplates/pmsh_multiple_cl_tosca.yaml";
+
+    private static final String INSTANTIATION_ENDPOINT = "instantiation";
+
+    private static final String INSTANTIATION_COMMAND_ENDPOINT = "instantiation/command";
+
+    /**
+     * starts Main and inserts a commissioning template.
+     *
+     * @throws Exception if an error occurs
+     */
+    @BeforeClass
+    public static void setUpBeforeClass() throws Exception {
+        CommonRestController.setUpBeforeClass("InstApi");
+
+        // to validate control Loop, it needs to define ToscaServiceTemplate
+        InstantiationUtils.storeToscaServiceTemplate(TOSCA_TEMPLATE_YAML, getParameters());
+
+        ControlLoops controlLoops =
+                InstantiationUtils.getControlLoopsFromResource(CL_INSTANTIATION_CREATE_JSON, "Command");
+        try (ControlLoopInstantiationProvider instantiationProvider =
+                new ControlLoopInstantiationProvider(getParameters())) {
+            instantiationProvider.createControlLoops(controlLoops);
+        }
+    }
+
+    @AfterClass
+    public static void teardownAfterClass() {
+        CommonRestController.teardownAfterClass();
+    }
+
+    @Test
+    public void testSwagger() throws Exception {
+        super.testSwagger(INSTANTIATION_ENDPOINT);
+    }
+
+    @Test
+    public void testCreate_Unauthorized() throws Exception {
+        ControlLoops controlLoops =
+                InstantiationUtils.getControlLoopsFromResource(CL_INSTANTIATION_CREATE_JSON, "Unauthorized");
+
+        assertUnauthorizedPost(INSTANTIATION_ENDPOINT, Entity.json(controlLoops));
+    }
+
+    @Test
+    public void testQuery_Unauthorized() throws Exception {
+        assertUnauthorizedGet(INSTANTIATION_ENDPOINT);
+    }
+
+    @Test
+    public void testUpdate_Unauthorized() throws Exception {
+        ControlLoops controlLoops =
+                InstantiationUtils.getControlLoopsFromResource(CL_INSTANTIATION_UPDATE_JSON, "Unauthorized");
+
+        assertUnauthorizedPut(INSTANTIATION_ENDPOINT, Entity.json(controlLoops));
+    }
+
+    @Test
+    public void testDelete_Unauthorized() throws Exception {
+        assertUnauthorizedDelete(INSTANTIATION_ENDPOINT);
+    }
+
+    @Test
+    public void testCommand_Unauthorized() throws Exception {
+        InstantiationCommand instantiationCommand = InstantiationUtils
+                .getInstantiationCommandFromResource(CL_INSTANTIATION_CHANGE_STATE_JSON, "Unauthorized");
+
+        assertUnauthorizedPut(INSTANTIATION_COMMAND_ENDPOINT, Entity.json(instantiationCommand));
+    }
+
+    @Test
+    public void testCreate() throws Exception {
+        ControlLoops controlLoopsFromRsc =
+                InstantiationUtils.getControlLoopsFromResource(CL_INSTANTIATION_CREATE_JSON, "Create");
+
+        Invocation.Builder invocationBuilder = super.sendRequest(INSTANTIATION_ENDPOINT);
+        Response resp = invocationBuilder.post(Entity.json(controlLoopsFromRsc));
+        assertEquals(Response.Status.OK.getStatusCode(), resp.getStatus());
+        InstantiationResponse instResponse = resp.readEntity(InstantiationResponse.class);
+        InstantiationUtils.assertInstantiationResponse(instResponse, controlLoopsFromRsc);
+
+        try (ControlLoopInstantiationProvider instantiationProvider =
+                new ControlLoopInstantiationProvider(getParameters())) {
+            for (ControlLoop controlLoopFromRsc : controlLoopsFromRsc.getControlLoopList()) {
+                ControlLoops controlLoopsFromDb = instantiationProvider.getControlLoops(
+                        controlLoopFromRsc.getKey().getName(), controlLoopFromRsc.getKey().getVersion());
+
+                assertNotNull(controlLoopsFromDb);
+                assertThat(controlLoopsFromDb.getControlLoopList()).hasSize(1);
+                assertEquals(controlLoopFromRsc, controlLoopsFromDb.getControlLoopList().get(0));
+            }
+        }
+    }
+
+    @Test
+    public void testCreateBadRequest() throws Exception {
+        ControlLoops controlLoopsFromRsc =
+                InstantiationUtils.getControlLoopsFromResource(CL_INSTANTIATION_CREATE_JSON, "CreateBadRequest");
+
+        Invocation.Builder invocationBuilder = super.sendRequest(INSTANTIATION_ENDPOINT);
+        Response resp = invocationBuilder.post(Entity.json(controlLoopsFromRsc));
+        assertEquals(Response.Status.OK.getStatusCode(), resp.getStatus());
+
+        // testing Bad Request: CL already defined
+        resp = invocationBuilder.post(Entity.json(controlLoopsFromRsc));
+        assertEquals(Response.Status.BAD_REQUEST.getStatusCode(), resp.getStatus());
+        InstantiationResponse instResponse = resp.readEntity(InstantiationResponse.class);
+        assertNotNull(instResponse.getErrorDetails());
+        assertNull(instResponse.getAffectedControlLoops());
+    }
+
+    @Test
+    public void testQuery_NoResultWithThisName() throws Exception {
+        Invocation.Builder invocationBuilder = super.sendRequest(INSTANTIATION_ENDPOINT + "?name=noResultWithThisName");
+        Response rawresp = invocationBuilder.buildGet().invoke();
+        assertEquals(Response.Status.OK.getStatusCode(), rawresp.getStatus());
+        ControlLoops resp = rawresp.readEntity(ControlLoops.class);
+        assertThat(resp.getControlLoopList()).isEmpty();
+    }
+
+    @Test
+    public void testQuery() throws Exception {
+        // inserts a ControlLoops to DB
+        ControlLoops controlLoops =
+                InstantiationUtils.getControlLoopsFromResource(CL_INSTANTIATION_CREATE_JSON, "Query");
+        try (ControlLoopInstantiationProvider instantiationProvider =
+                new ControlLoopInstantiationProvider(getParameters())) {
+            instantiationProvider.createControlLoops(controlLoops);
+        }
+
+        for (ControlLoop controlLoopFromRsc : controlLoops.getControlLoopList()) {
+            Invocation.Builder invocationBuilder =
+                    super.sendRequest(INSTANTIATION_ENDPOINT + "?name=" + controlLoopFromRsc.getKey().getName());
+            Response rawresp = invocationBuilder.buildGet().invoke();
+            assertEquals(Response.Status.OK.getStatusCode(), rawresp.getStatus());
+            ControlLoops controlLoopsQuery = rawresp.readEntity(ControlLoops.class);
+            assertNotNull(controlLoopsQuery);
+            assertThat(controlLoopsQuery.getControlLoopList()).hasSize(1);
+            assertEquals(controlLoopFromRsc, controlLoopsQuery.getControlLoopList().get(0));
+        }
+    }
+
+    @Test
+    public void testUpdate() throws Exception {
+        ControlLoops controlLoopsCreate =
+                InstantiationUtils.getControlLoopsFromResource(CL_INSTANTIATION_CREATE_JSON, "Update");
+
+        ControlLoops controlLoops =
+                InstantiationUtils.getControlLoopsFromResource(CL_INSTANTIATION_UPDATE_JSON, "Update");
+
+        try (ControlLoopInstantiationProvider instantiationProvider =
+                new ControlLoopInstantiationProvider(getParameters())) {
+            instantiationProvider.createControlLoops(controlLoopsCreate);
+
+            Invocation.Builder invocationBuilder = super.sendRequest(INSTANTIATION_ENDPOINT);
+            Response resp = invocationBuilder.put(Entity.json(controlLoops));
+            assertEquals(Response.Status.OK.getStatusCode(), resp.getStatus());
+
+            InstantiationResponse instResponse = resp.readEntity(InstantiationResponse.class);
+            InstantiationUtils.assertInstantiationResponse(instResponse, controlLoops);
+
+            for (ControlLoop controlLoopUpdate : controlLoops.getControlLoopList()) {
+                ControlLoops controlLoopsFromDb = instantiationProvider
+                        .getControlLoops(controlLoopUpdate.getKey().getName(), controlLoopUpdate.getKey().getVersion());
+
+                assertNotNull(controlLoopsFromDb);
+                assertThat(controlLoopsFromDb.getControlLoopList()).hasSize(1);
+                assertEquals(controlLoopUpdate, controlLoopsFromDb.getControlLoopList().get(0));
+            }
+        }
+    }
+
+    @Test
+    public void testDelete_NoResultWithThisName() throws Exception {
+        Invocation.Builder invocationBuilder = super.sendRequest(INSTANTIATION_ENDPOINT + "?name=noResultWithThisName");
+        Response resp = invocationBuilder.delete();
+        assertEquals(Response.Status.NOT_FOUND.getStatusCode(), resp.getStatus());
+        InstantiationResponse instResponse = resp.readEntity(InstantiationResponse.class);
+        assertNotNull(instResponse.getErrorDetails());
+        assertNull(instResponse.getAffectedControlLoops());
+    }
+
+    @Test
+    public void testDelete() throws Exception {
+        ControlLoops controlLoopsFromRsc =
+                InstantiationUtils.getControlLoopsFromResource(CL_INSTANTIATION_CREATE_JSON, "Delete");
+        try (ControlLoopInstantiationProvider instantiationProvider =
+                new ControlLoopInstantiationProvider(getParameters())) {
+            instantiationProvider.createControlLoops(controlLoopsFromRsc);
+
+            for (ControlLoop controlLoopFromRsc : controlLoopsFromRsc.getControlLoopList()) {
+                Invocation.Builder invocationBuilder =
+                        super.sendRequest(INSTANTIATION_ENDPOINT + "?name=" + controlLoopFromRsc.getKey().getName()
+                                + "&version=" + controlLoopFromRsc.getKey().getVersion());
+                Response resp = invocationBuilder.delete();
+                assertEquals(Response.Status.OK.getStatusCode(), resp.getStatus());
+                InstantiationResponse instResponse = resp.readEntity(InstantiationResponse.class);
+                InstantiationUtils.assertInstantiationResponse(instResponse, controlLoopFromRsc);
+
+                ControlLoops controlLoopsFromDb = instantiationProvider.getControlLoops(
+                        controlLoopFromRsc.getKey().getName(), controlLoopFromRsc.getKey().getVersion());
+                assertThat(controlLoopsFromDb.getControlLoopList()).isEmpty();
+            }
+        }
+    }
+
+    @Test
+    public void testDeleteBadRequest() throws Exception {
+        ControlLoops controlLoopsFromRsc =
+                InstantiationUtils.getControlLoopsFromResource(CL_INSTANTIATION_CREATE_JSON, "DelBadRequest");
+        try (ControlLoopInstantiationProvider instantiationProvider =
+                new ControlLoopInstantiationProvider(getParameters())) {
+            instantiationProvider.createControlLoops(controlLoopsFromRsc);
+
+            for (ControlLoop controlLoopFromRsc : controlLoopsFromRsc.getControlLoopList()) {
+                Invocation.Builder invocationBuilder =
+                        super.sendRequest(INSTANTIATION_ENDPOINT + "?name=" + controlLoopFromRsc.getKey().getName());
+                Response resp = invocationBuilder.delete();
+                // should be BAD_REQUEST
+                assertEquals(Response.Status.INTERNAL_SERVER_ERROR.getStatusCode(), resp.getStatus());
+            }
+        }
+    }
+
+    @Test
+    public void testCommand_NotFound1() throws Exception {
+        Invocation.Builder invocationBuilder = super.sendRequest(INSTANTIATION_COMMAND_ENDPOINT);
+        Response resp = invocationBuilder.put(Entity.json(new InstantiationCommand()));
+        assertEquals(Response.Status.BAD_REQUEST.getStatusCode(), resp.getStatus());
+    }
+
+    @Test
+    public void testCommand_NotFound2() throws Exception {
+        InstantiationCommand command =
+                InstantiationUtils.getInstantiationCommandFromResource(CL_INSTANTIATION_CHANGE_STATE_JSON, "Command");
+        command.setOrderedState(null);
+
+        Invocation.Builder invocationBuilder = super.sendRequest(INSTANTIATION_COMMAND_ENDPOINT);
+        Response resp = invocationBuilder.put(Entity.json(command));
+        assertEquals(Response.Status.BAD_REQUEST.getStatusCode(), resp.getStatus());
+    }
+
+    @Test
+    public void testCommand() throws Exception {
+        InstantiationCommand command =
+                InstantiationUtils.getInstantiationCommandFromResource(CL_INSTANTIATION_CHANGE_STATE_JSON, "Command");
+
+        Invocation.Builder invocationBuilder = super.sendRequest(INSTANTIATION_COMMAND_ENDPOINT);
+        Response resp = invocationBuilder.put(Entity.json(command));
+        assertEquals(Response.Status.ACCEPTED.getStatusCode(), resp.getStatus());
+        InstantiationResponse instResponse = resp.readEntity(InstantiationResponse.class);
+        InstantiationUtils.assertInstantiationResponse(instResponse, command);
+
+        // check passive state on DB
+        try (ControlLoopInstantiationProvider instantiationProvider =
+                new ControlLoopInstantiationProvider(getParameters())) {
+            for (ToscaConceptIdentifier toscaConceptIdentifier : command.getControlLoopIdentifierList()) {
+                ControlLoops controlLoopsGet = instantiationProvider.getControlLoops(toscaConceptIdentifier.getName(),
+                        toscaConceptIdentifier.getVersion());
+                assertThat(controlLoopsGet.getControlLoopList()).hasSize(1);
+                assertEquals(command.getOrderedState(), controlLoopsGet.getControlLoopList().get(0).getOrderedState());
+            }
+        }
+    }
+}
diff --git a/runtime-controlloop/src/test/java/org/onap/policy/clamp/controlloop/runtime/main/rest/RestControllerTest.java b/runtime-controlloop/src/test/java/org/onap/policy/clamp/controlloop/runtime/main/rest/RestControllerTest.java
new file mode 100644
index 0000000..4f68b4f
--- /dev/null
+++ b/runtime-controlloop/src/test/java/org/onap/policy/clamp/controlloop/runtime/main/rest/RestControllerTest.java
@@ -0,0 +1,71 @@
+/*-
+ * ============LICENSE_START=======================================================
+ *  Copyright (C) 2021 Nordix Foundation.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.policy.clamp.controlloop.runtime.main.rest;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+
+import java.util.UUID;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+import org.junit.Test;
+
+/**
+ * Class to perform unit test of {@link RestController}}.
+ *
+ */
+public class RestControllerTest {
+
+    @Test
+    public void testProduces() {
+        Produces annotation = RestController.class.getAnnotation(Produces.class);
+        assertNotNull(annotation);
+        assertThat(annotation.value()).contains(MediaType.APPLICATION_JSON)
+                        .contains(RestController.APPLICATION_YAML);
+    }
+
+    @Test
+    public void testAddVersionControlHeaders() {
+        RestController ctlr = new RestController();
+        Response resp = ctlr.addVersionControlHeaders(Response.status(Response.Status.OK)).build();
+        assertEquals("0", resp.getHeaderString(RestController.VERSION_MINOR_NAME));
+        assertEquals("0", resp.getHeaderString(RestController.VERSION_PATCH_NAME));
+        assertEquals("1.0.0", resp.getHeaderString(RestController.VERSION_LATEST_NAME));
+    }
+
+    @Test
+    public void testAddLoggingHeaders_Null() {
+        RestController ctlr = new RestController();
+        Response resp = ctlr.addLoggingHeaders(Response.status(Response.Status.OK), null).build();
+        assertNotNull(resp.getHeaderString(RestController.REQUEST_ID_NAME));
+    }
+
+    @Test
+    public void testAddLoggingHeaders_NonNull() {
+        UUID uuid = UUID.randomUUID();
+        RestController ctlr = new RestController();
+        Response resp = ctlr.addLoggingHeaders(Response.status(Response.Status.OK), uuid).build();
+        assertEquals(uuid.toString(), resp.getHeaderString(RestController.REQUEST_ID_NAME));
+    }
+
+}
diff --git a/runtime-controlloop/src/test/java/org/onap/policy/clamp/controlloop/runtime/main/startstop/ClRuntimeActivatorTest.java b/runtime-controlloop/src/test/java/org/onap/policy/clamp/controlloop/runtime/main/startstop/ClRuntimeActivatorTest.java
new file mode 100644
index 0000000..da71c23
--- /dev/null
+++ b/runtime-controlloop/src/test/java/org/onap/policy/clamp/controlloop/runtime/main/startstop/ClRuntimeActivatorTest.java
@@ -0,0 +1,82 @@
+/*-
+ * ============LICENSE_START=======================================================
+ *  Copyright (C) 2021 Nordix Foundation.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.policy.clamp.controlloop.runtime.main.startstop;
+
+import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
+import static org.assertj.core.api.Assertions.assertThatIllegalStateException;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import org.junit.Test;
+import org.onap.policy.clamp.controlloop.common.exception.ControlLoopRuntimeException;
+import org.onap.policy.clamp.controlloop.runtime.main.parameters.ClRuntimeParameterGroup;
+import org.onap.policy.clamp.controlloop.runtime.main.parameters.ClRuntimeParameterHandler;
+import org.onap.policy.common.utils.services.Registry;
+
+/**
+ * Class to perform unit test of {@link ClRuntimeActivator}}.
+ *
+ */
+public class ClRuntimeActivatorTest {
+
+    @Test
+    public void testStartAndStop() throws Exception {
+        Registry.newRegistry();
+        final String[] configParameters = {"-c", "src/test/resources/parameters/TestParameters.json"};
+        final ClRuntimeCommandLineArguments arguments = new ClRuntimeCommandLineArguments();
+        arguments.parse(configParameters);
+        ClRuntimeParameterGroup parameterGroup = new ClRuntimeParameterHandler().getParameters(arguments);
+        ClRuntimeActivator activator = new ClRuntimeActivator(parameterGroup);
+        activator.isAlive();
+
+        assertFalse(activator.isAlive());
+        activator.start();
+        assertTrue(activator.isAlive());
+        assertTrue(activator.getParameterGroup().isValid());
+        assertEquals(activator.getParameterGroup().getName(),
+                activator.getParameterGroup().getRestServerParameters().getName());
+
+        // repeat start - should throw an exception
+        assertThatIllegalStateException().isThrownBy(() -> activator.start());
+        assertTrue(activator.isAlive());
+        assertTrue(activator.getParameterGroup().isValid());
+
+        activator.stop();
+        assertFalse(activator.isAlive());
+
+        // repeat stop - should throw an exception
+        assertThatIllegalStateException().isThrownBy(() -> activator.stop());
+        assertFalse(activator.isAlive());
+    }
+
+    @Test
+    public void testNull() {
+        assertThatExceptionOfType(ControlLoopRuntimeException.class).isThrownBy(() -> new ClRuntimeActivator(null));
+    }
+
+    @Test
+    public void testNotValid() {
+        ClRuntimeParameterGroup parameterGroup = new ClRuntimeParameterGroup("name");
+        assertThatExceptionOfType(ControlLoopRuntimeException.class)
+                .isThrownBy(() -> new ClRuntimeActivator(parameterGroup));
+    }
+}
diff --git a/runtime-controlloop/src/test/java/org/onap/policy/clamp/controlloop/runtime/main/startstop/MainTest.java b/runtime-controlloop/src/test/java/org/onap/policy/clamp/controlloop/runtime/main/startstop/MainTest.java
new file mode 100644
index 0000000..b06383c
--- /dev/null
+++ b/runtime-controlloop/src/test/java/org/onap/policy/clamp/controlloop/runtime/main/startstop/MainTest.java
@@ -0,0 +1,157 @@
+/*-
+ * ============LICENSE_START=======================================================
+ *  Copyright (C) 2021 Nordix Foundation.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.policy.clamp.controlloop.runtime.main.startstop;
+
+import static org.assertj.core.api.Assertions.assertThatCode;
+import static org.assertj.core.api.Assertions.assertThatThrownBy;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.onap.policy.clamp.controlloop.common.ControlLoopConstants;
+import org.onap.policy.clamp.controlloop.common.exception.ControlLoopRuntimeException;
+import org.onap.policy.common.utils.resources.MessageConstants;
+import org.onap.policy.common.utils.services.Registry;
+
+/**
+ * Class to perform unit test of {@link Main}}.
+ *
+ */
+public class MainTest {
+
+    public static final String POLICY_CLAMP_FAILURE_MSG =
+            String.format(MessageConstants.START_FAILURE_MSG, MessageConstants.POLICY_CLAMP);
+
+    /**
+     * Set up.
+     */
+    @BeforeClass
+    public static void setUp() {
+        Registry.newRegistry();
+    }
+
+    /**
+     * Shuts "main" down.
+     *
+     * @throws Exception if an error occurs
+     */
+    @AfterClass
+    public static void tearDown() throws Exception {
+        // shut down activator
+        final ClRuntimeActivator activator =
+                Registry.getOrDefault(ControlLoopConstants.REG_CLRUNTIME_ACTIVATOR, ClRuntimeActivator.class, null);
+        if (activator != null && activator.isAlive()) {
+            activator.shutdown();
+        }
+    }
+
+    @Test
+    public void testMain_Help() {
+        final String[] configParameters = {"-h"};
+        Main main = new Main(configParameters);
+        assertFalse(main.isRunning());
+    }
+
+    @Test
+    public void testMain_Version() {
+        final String[] configParameters = {"-v"};
+        Main main = new Main(configParameters);
+        assertFalse(main.isRunning());
+    }
+
+    @Test
+    public void testMain_Valid() {
+        final String[] configParameters = {"-c", "src/test/resources/parameters/TestParameters.json"};
+        Main main = new Main(configParameters);
+        assertTrue(main.isRunning());
+
+        // ensure items were added to the registry
+        assertNotNull(Registry.get(ControlLoopConstants.REG_CLRUNTIME_ACTIVATOR, ClRuntimeActivator.class));
+
+        assertThatCode(() -> main.shutdown()).doesNotThrowAnyException();
+
+        assertFalse(main.isRunning());
+    }
+
+    @Test
+    public void testMain_NoParameter() {
+        assertThatConfigParameterThrownException(new String[] {});
+    }
+
+    @Test
+    public void testMain_FilePathNotDefined() {
+        assertThatConfigParameterThrownException(new String[] {"-c"});
+    }
+
+    @Test
+    public void testMain_TooManyCommand() {
+        assertThatConfigParameterThrownException(new String[] {"-h", "d"});
+    }
+
+    @Test
+    public void testMain_WrongParameter() {
+        assertThatConfigParameterThrownException(new String[] {"-d"});
+    }
+
+    private void assertThatConfigParameterThrownException(final String[] configParameters) {
+        assertThatThrownBy(() -> Main.main(configParameters)).isInstanceOf(ControlLoopRuntimeException.class)
+                .hasMessage(POLICY_CLAMP_FAILURE_MSG);
+    }
+
+    @Test
+    public void testParticipant_NoFileWithThisName() {
+        assertThatConfigFileThrownException("src/test/resources/parameters/NoFileWithThisName.json");
+    }
+
+    @Test
+    public void testParticipant_NotValidFile() {
+        assertThatConfigFileThrownException("src/test/resources/parameters");
+    }
+
+    @Test
+    public void testParticipant_FileEmpty() {
+        assertThatConfigFileThrownException("src/test/resources/parameters/EmptyParameters.json");
+    }
+
+    @Test
+    public void testParticipant_NoParameters() {
+        assertThatConfigFileThrownException("src/test/resources/parameters/NoParameters.json");
+    }
+
+    @Test
+    public void testParticipant_InvalidParameters() {
+        assertThatConfigFileThrownException("src/test/resources/parameters/InvalidParameters.json");
+    }
+
+    @Test
+    public void testParticipant_WrongJsonFormat() {
+        assertThatConfigFileThrownException("src/test/resources/parameters/Unreadable.json");
+    }
+
+    private void assertThatConfigFileThrownException(final String configFilePath) {
+        final String[] configParameters = new String[] {"-c", configFilePath};
+        assertThatThrownBy(() -> new Main(configParameters)).isInstanceOf(ControlLoopRuntimeException.class)
+                .hasMessage(String.format(POLICY_CLAMP_FAILURE_MSG));
+    }
+}
diff --git a/runtime-controlloop/src/test/java/org/onap/policy/clamp/controlloop/runtime/monitoring/TestMonitoringProvider.java b/runtime-controlloop/src/test/java/org/onap/policy/clamp/controlloop/runtime/monitoring/TestMonitoringProvider.java
new file mode 100644
index 0000000..44096ee
--- /dev/null
+++ b/runtime-controlloop/src/test/java/org/onap/policy/clamp/controlloop/runtime/monitoring/TestMonitoringProvider.java
@@ -0,0 +1,264 @@
+/*-
+ * ============LICENSE_START=======================================================
+ *  Copyright (C) 2021 Nordix Foundation.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.policy.clamp.controlloop.runtime.monitoring;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.assertThatThrownBy;
+import static org.junit.Assert.assertEquals;
+import static org.mockito.Mockito.when;
+
+import java.io.File;
+import java.lang.reflect.Field;
+import java.time.Instant;
+import java.util.ArrayList;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.mockito.Mockito;
+import org.onap.policy.clamp.controlloop.models.controlloop.concepts.ClElementStatisticsList;
+import org.onap.policy.clamp.controlloop.models.controlloop.concepts.ControlLoop;
+import org.onap.policy.clamp.controlloop.models.controlloop.concepts.ControlLoopElement;
+import org.onap.policy.clamp.controlloop.models.controlloop.concepts.ParticipantStatisticsList;
+import org.onap.policy.clamp.controlloop.models.controlloop.persistence.provider.ControlLoopProvider;
+import org.onap.policy.clamp.controlloop.runtime.util.CommonTestData;
+import org.onap.policy.common.utils.coder.Coder;
+import org.onap.policy.common.utils.coder.CoderException;
+import org.onap.policy.common.utils.coder.StandardCoder;
+import org.onap.policy.models.provider.PolicyModelsProviderParameters;
+import org.onap.policy.models.tosca.authorative.concepts.ToscaConceptIdentifier;
+
+
+public class TestMonitoringProvider {
+
+    private static final String CL_PARTICIPANT_STATISTICS_JSON =
+        "src/test/resources/rest/monitoring/TestParticipantStatistics.json";
+    private static final String INVALID_PARTICIPANT_JSON_INPUT =
+        "src/test/resources/rest/monitoring/TestParticipantStatistics_Invalid.json";
+    private static final String CL_ELEMENT_STATISTICS_JSON =
+        "src/test/resources/rest/monitoring/TestClElementStatistics.json";
+    private static final String INVALID_CL_ELEMENT_JSON_INPUT =
+        "src/test/resources/rest/monitoring/TestClElementStatistics_Invalid.json";
+    private static final Coder CODER = new StandardCoder();
+
+    private static final String CL_PROVIDER_FIELD = "controlLoopProvider";
+
+    private static final String LIST_IS_NULL = ".*StatisticsList is marked .*ull but is null";
+    private static ParticipantStatisticsList inputParticipantStatistics;
+    private static ParticipantStatisticsList invalidParticipantInput;
+    private static ClElementStatisticsList inputClElementStatistics;
+    private static ClElementStatisticsList invalidClElementInput;
+
+
+
+    @BeforeClass
+    public static void beforeSetupStatistics() throws CoderException {
+        // Reading input json for statistics data
+        inputParticipantStatistics =
+            CODER.decode(new File(CL_PARTICIPANT_STATISTICS_JSON), ParticipantStatisticsList.class);
+        invalidParticipantInput =
+            CODER.decode(new File(INVALID_PARTICIPANT_JSON_INPUT), ParticipantStatisticsList.class);
+        inputClElementStatistics = CODER.decode(new File(CL_ELEMENT_STATISTICS_JSON), ClElementStatisticsList.class);
+        invalidClElementInput = CODER.decode(new File(INVALID_CL_ELEMENT_JSON_INPUT), ClElementStatisticsList.class);
+    }
+
+
+    @Test
+    public void testCreateParticipantStatistics() throws Exception {
+        PolicyModelsProviderParameters parameters =
+            CommonTestData.geParameterGroup(0, "createparStat").getDatabaseProviderParameters();
+
+        try (MonitoringProvider provider = new MonitoringProvider(parameters)) {
+            // Creating statistics data in db with null input
+            assertThatThrownBy(() -> {
+                provider.createParticipantStatistics(null);
+            }).hasMessageMatching(LIST_IS_NULL);
+
+            assertThatThrownBy(() -> {
+                provider.createParticipantStatistics(invalidParticipantInput.getStatisticsList());
+            }).hasMessageMatching("participantStatisticsList is marked .*null but is null");
+
+            // Creating statistics data from input json
+            ParticipantStatisticsList createResponse =
+                provider.createParticipantStatistics(inputParticipantStatistics.getStatisticsList());
+
+            assertThat(createResponse.getStatisticsList()).hasSize(3);
+            assertEquals(createResponse.getStatisticsList().toString().replaceAll("\\s+", ""),
+                inputParticipantStatistics.getStatisticsList().toString().replaceAll("\\s+", ""));
+        }
+    }
+
+    @Test
+    public void testGetParticipantStatistics() throws Exception {
+        PolicyModelsProviderParameters parameters =
+            CommonTestData.geParameterGroup(0, "getparStat").getDatabaseProviderParameters();
+        try (MonitoringProvider provider = new MonitoringProvider(parameters)) {
+            ParticipantStatisticsList getResponse;
+
+            provider.createParticipantStatistics(inputParticipantStatistics.getStatisticsList());
+
+            assertThatThrownBy(() -> {
+                provider.fetchFilteredParticipantStatistics(null, null, 0, null, null);
+            }).hasMessageMatching("name is marked .*null but is null");
+
+            // Fetch specific statistics record with name, version and record count
+            getResponse = provider.fetchFilteredParticipantStatistics("name2", "1.001", 1,
+                null, null);
+            assertThat(getResponse.getStatisticsList()).hasSize(1);
+            assertEquals(getResponse.getStatisticsList().get(0).toString().replaceAll("\\s+", ""),
+                inputParticipantStatistics.getStatisticsList().get(2).toString().replaceAll("\\s+", ""));
+
+            // Fetch statistics using timestamp
+            getResponse = provider.fetchFilteredParticipantStatistics("name1", "1.001", 0,
+                null, Instant.parse("2021-01-10T15:00:00.000Z"));
+            assertThat(getResponse.getStatisticsList()).hasSize(1);
+
+            getResponse = provider.fetchFilteredParticipantStatistics("name1", "1.001", 0,
+                Instant.parse("2021-01-11T12:00:00.000Z"), Instant.parse("2021-01-11T16:00:00.000Z"));
+
+            assertThat(getResponse.getStatisticsList()).isEmpty();
+        }
+    }
+
+    @Test
+    public void testCreateClElementStatistics() throws Exception {
+        PolicyModelsProviderParameters parameters =
+            CommonTestData.geParameterGroup(0, "createelemstat").getDatabaseProviderParameters();
+        try (MonitoringProvider provider = new MonitoringProvider(parameters)) {
+            // Creating statistics data in db with null input
+            assertThatThrownBy(() -> {
+                provider.createClElementStatistics(null);
+            }).hasMessageMatching(LIST_IS_NULL);
+
+            assertThatThrownBy(() -> {
+                provider.createClElementStatistics(invalidClElementInput.getClElementStatistics());
+            }).hasMessageMatching("clElementStatisticsList is marked .*null but is null");
+
+            // Creating clElement statistics data from input json
+            ClElementStatisticsList createResponse =
+                provider.createClElementStatistics(inputClElementStatistics.getClElementStatistics());
+
+            assertThat(createResponse.getClElementStatistics()).hasSize(4);
+            assertEquals(createResponse.getClElementStatistics().toString().replaceAll("\\s+", ""),
+                inputClElementStatistics.getClElementStatistics().toString().replaceAll("\\s+", ""));
+        }
+    }
+
+    @Test
+    public void testGetClElementStatistics() throws Exception {
+        PolicyModelsProviderParameters parameters =
+            CommonTestData.geParameterGroup(0, "getelemstat").getDatabaseProviderParameters();
+        try (MonitoringProvider provider = new MonitoringProvider(parameters)) {
+            ClElementStatisticsList getResponse;
+
+            assertThatThrownBy(() -> {
+                provider.fetchFilteredClElementStatistics(null, null, null,  null,
+                    null, 0);
+            }).hasMessageMatching("name is marked .*null but is null");
+
+            ClElementStatisticsList lists = provider.createClElementStatistics(inputClElementStatistics
+                .getClElementStatistics());
+
+            getResponse = provider.fetchFilteredClElementStatistics("name1", null, null, null,
+                null, 0);
+
+            assertThat(getResponse.getClElementStatistics()).hasSize(2);
+            assertEquals(getResponse.getClElementStatistics().get(0).toString().replaceAll("\\s+", ""),
+                inputClElementStatistics.getClElementStatistics().get(0).toString().replaceAll("\\s+", ""));
+
+            // Fetch specific statistics record with name, id and record count
+            getResponse = provider.fetchFilteredClElementStatistics("name1", "1.001",
+                "709c62b3-8918-41b9-a747-d21eb79c6c20", null, null, 0);
+            assertThat(getResponse.getClElementStatistics()).hasSize(2);
+
+            // Fetch statistics using timestamp
+            getResponse = provider.fetchFilteredClElementStatistics("name1", "1.001", null,
+                Instant.parse("2021-01-10T13:45:00.000Z"), null, 0);
+            assertThat(getResponse.getClElementStatistics()).hasSize(2);
+        }
+    }
+
+    @Test
+    public void testGetParticipantStatsPerCL() throws Exception {
+        PolicyModelsProviderParameters parameters =
+            CommonTestData.geParameterGroup(0, "getparStatCL").getDatabaseProviderParameters();
+        try (MonitoringProvider provider = Mockito.spy(new MonitoringProvider(parameters))) {
+
+            provider.createParticipantStatistics(inputParticipantStatistics.getStatisticsList());
+            //Mock the response for fetching participant conceptIdentifiers per control loop
+            List<ToscaConceptIdentifier> conceptIdentifiers = new ArrayList<>();
+            conceptIdentifiers.add(new ToscaConceptIdentifier("name1", "1.001"));
+            when(provider.getAllParticipantIdsPerControlLoop("testName", "1.001"))
+                .thenReturn(conceptIdentifiers);
+            ParticipantStatisticsList getResponse;
+            getResponse = provider.fetchParticipantStatsPerControlLoop("testName", "1.001");
+            assertThat(getResponse.getStatisticsList()).hasSize(2);
+            assertEquals(getResponse.getStatisticsList().get(0).toString().replaceAll("\\s+", ""),
+                inputParticipantStatistics.getStatisticsList().get(0).toString().replaceAll("\\s+", ""));
+            assertThat(provider.fetchParticipantStatsPerControlLoop("invalidCLName", "1.002")
+                .getStatisticsList()).isEmpty();
+        }
+
+    }
+
+    @Test
+    public void testClElementStatsPerCL() throws Exception {
+        PolicyModelsProviderParameters parameters =
+            CommonTestData.geParameterGroup(0, "getelemstatPerCL").getDatabaseProviderParameters();
+        //Setup a dummy Control loop data
+        ControlLoopElement mockClElement = new ControlLoopElement();
+        mockClElement.setId(inputClElementStatistics.getClElementStatistics().get(0).getId());
+        mockClElement.setParticipantId(new ToscaConceptIdentifier(inputClElementStatistics.getClElementStatistics()
+            .get(0).getParticipantId().getName(), inputClElementStatistics.getClElementStatistics().get(0)
+            .getParticipantId().getVersion()));
+        ControlLoop mockCL = new ControlLoop();
+        mockCL.setElements(new LinkedHashMap<>());
+        mockCL.getElements().put(mockClElement.getId(), mockClElement);
+
+        //Mock controlloop data to be returned for the given CL Id
+        ControlLoopProvider mockClProvider = Mockito.mock(ControlLoopProvider.class);
+        when(mockClProvider.getControlLoop(new ToscaConceptIdentifier("testCLName", "1.001")))
+            .thenReturn(mockCL);
+
+        try (MonitoringProvider monitoringProvider = new MonitoringProvider(parameters)) {
+            monitoringProvider.createClElementStatistics(inputClElementStatistics.getClElementStatistics());
+            Field controlLoopProviderField = monitoringProvider.getClass().getDeclaredField(CL_PROVIDER_FIELD);
+            controlLoopProviderField.setAccessible(true);
+            controlLoopProviderField.set(monitoringProvider, mockClProvider);
+
+            ClElementStatisticsList getResponse;
+            getResponse = monitoringProvider.fetchClElementStatsPerControlLoop("testCLName", "1.001");
+
+            assertThat(getResponse.getClElementStatistics()).hasSize(2);
+            assertEquals(getResponse.getClElementStatistics().get(1).toString().replaceAll("\\s+", ""),
+                inputClElementStatistics.getClElementStatistics().get(1).toString().replaceAll("\\s+", ""));
+
+            assertThat(monitoringProvider.fetchClElementStatsPerControlLoop("invalidCLName", "1.002")
+                .getClElementStatistics()).isEmpty();
+
+            Map<String, ToscaConceptIdentifier> clElementIds = monitoringProvider
+                .getAllClElementsIdPerControlLoop("testCLName", "1.001");
+            assertThat(clElementIds).containsKey(inputClElementStatistics.getClElementStatistics().get(0).getId()
+                .toString());
+        }
+    }
+}
diff --git a/runtime-controlloop/src/test/java/org/onap/policy/clamp/controlloop/runtime/monitoring/rest/MonitoringQueryControllerTest.java b/runtime-controlloop/src/test/java/org/onap/policy/clamp/controlloop/runtime/monitoring/rest/MonitoringQueryControllerTest.java
new file mode 100644
index 0000000..118199a
--- /dev/null
+++ b/runtime-controlloop/src/test/java/org/onap/policy/clamp/controlloop/runtime/monitoring/rest/MonitoringQueryControllerTest.java
@@ -0,0 +1,237 @@
+/*-
+ * ============LICENSE_START=======================================================
+ *  Copyright (C) 2021 Nordix Foundation.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.policy.clamp.controlloop.runtime.monitoring.rest;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+
+import java.io.File;
+import java.time.Instant;
+import javax.ws.rs.client.Invocation;
+import javax.ws.rs.core.Response;
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+import org.junit.Ignore;
+import org.junit.Test;
+import org.onap.policy.clamp.controlloop.models.controlloop.concepts.ClElementStatisticsList;
+import org.onap.policy.clamp.controlloop.models.controlloop.concepts.ParticipantStatisticsList;
+import org.onap.policy.clamp.controlloop.runtime.monitoring.MonitoringProvider;
+import org.onap.policy.clamp.controlloop.runtime.util.rest.CommonRestController;
+import org.onap.policy.common.utils.coder.Coder;
+import org.onap.policy.common.utils.coder.StandardCoder;
+
+public class MonitoringQueryControllerTest extends CommonRestController {
+
+    private static final String CL_PARTICIPANT_STATISTICS_JSON =
+        "src/test/resources/rest/monitoring/TestParticipantStatistics.json";
+    private static final String CL_ELEMENT_STATISTICS_JSON =
+        "src/test/resources/rest/monitoring/TestClElementStatistics.json";
+
+    private static final Coder CODER = new StandardCoder();
+
+    private static ParticipantStatisticsList inputParticipantStatistics;
+    private static ClElementStatisticsList inputClElementStatistics;
+
+    private static ParticipantStatisticsList participantStatisticsList;
+    private static  ClElementStatisticsList clElementStatisticsList;
+
+    private static final String CLELEMENT_STATS_ENDPOINT = "monitoring/clelement";
+    private static final String PARTICIPANT_STATS_ENDPOINT = "monitoring/participant";
+    private static final String PARTICIPANT_STATS_PER_CL_ENDPOINT = "monitoring/participants/controlloop";
+    private static final String CLELEMENT_STATS_PER_CL_ENDPOINT = "monitoring/clelements/controlloop";
+
+
+    /**
+     * starts Main.
+     *
+     * @throws Exception if an error occurs
+     */
+    @BeforeClass
+    public static void setUpBeforeClass() throws Exception {
+        CommonRestController.setUpBeforeClass("testStatisticsQuery");
+        inputParticipantStatistics = CODER.decode(new File(CL_PARTICIPANT_STATISTICS_JSON),
+            ParticipantStatisticsList.class);
+        inputClElementStatistics = CODER.decode(new File(CL_ELEMENT_STATISTICS_JSON),
+            ClElementStatisticsList.class);
+
+        try (MonitoringProvider monitoringProvider = new MonitoringProvider(getParameters())) {
+            // Insert Participant statistics to DB
+            participantStatisticsList = monitoringProvider.createParticipantStatistics(inputParticipantStatistics
+                .getStatisticsList());
+            // Insert CL Element statistics to DB
+            clElementStatisticsList = monitoringProvider.createClElementStatistics(inputClElementStatistics
+                .getClElementStatistics());
+        }
+    }
+
+    @AfterClass
+    public static void teardownAfterClass() {
+        CommonRestController.teardownAfterClass();
+    }
+
+    @Test
+    public void testQuery_Unauthorized_for_ClElementStats() throws Exception {
+        assertUnauthorizedGet(CLELEMENT_STATS_ENDPOINT);
+    }
+
+    @Test
+    public void testQuery_Unauthorized_for_ClParticipantStats() throws Exception {
+        assertUnauthorizedGet(PARTICIPANT_STATS_ENDPOINT);
+    }
+
+    @Test
+    public void testQuery_Unauthorized_for_ParticipantStatsPerCl() throws Exception {
+        assertUnauthorizedGet(PARTICIPANT_STATS_PER_CL_ENDPOINT);
+    }
+
+    @Test
+    public void testQuery_Unauthorized_for_ClElementStatsPerCl() throws Exception {
+        assertUnauthorizedGet(CLELEMENT_STATS_PER_CL_ENDPOINT);
+    }
+
+    @Test
+    public void testSwagger_ClStats() throws Exception {
+        super.testSwagger(CLELEMENT_STATS_ENDPOINT);
+        super.testSwagger(PARTICIPANT_STATS_ENDPOINT);
+        super.testSwagger(CLELEMENT_STATS_PER_CL_ENDPOINT);
+        super.testSwagger(PARTICIPANT_STATS_PER_CL_ENDPOINT);
+    }
+
+    @Test
+    public void testClElementStatisticsEndpoint() throws Exception {
+        // Filter statistics only based on participant Id and UUID
+        Invocation.Builder invokeRequest1 =
+            super.sendRequest(CLELEMENT_STATS_ENDPOINT + "?name=" + clElementStatisticsList
+                .getClElementStatistics().get(0).getParticipantId().getName() + "&version=" + clElementStatisticsList
+                .getClElementStatistics().get(0).getParticipantId().getVersion() + "&id=" + clElementStatisticsList
+                .getClElementStatistics().get(0).getId().toString());
+        Response response1 = invokeRequest1.buildGet().invoke();
+        assertEquals(Response.Status.OK.getStatusCode(), response1.getStatus());
+
+        ClElementStatisticsList result1 = response1.readEntity(ClElementStatisticsList.class);
+
+        assertNotNull(result1);
+        assertThat(result1.getClElementStatistics()).hasSize(2);
+        assertEquals(result1.getClElementStatistics().get(0), clElementStatisticsList
+            .getClElementStatistics().get(0));
+
+        // Filter statistics based on timestamp
+        Invocation.Builder invokeRequest2 =
+            super.sendRequest(CLELEMENT_STATS_ENDPOINT + "?name=" + clElementStatisticsList
+                .getClElementStatistics().get(1).getParticipantId().getName() + "&version=" + clElementStatisticsList
+                .getClElementStatistics().get(1).getParticipantId().getVersion() + "&startTime="
+                + Instant.parse("2021-01-10T13:00:00.000Z") + "&endTime=" + Instant.parse("2021-01-10T14:00:00.000Z"));
+        Response response2 = invokeRequest2.buildGet().invoke();
+        assertEquals(Response.Status.OK.getStatusCode(), response2.getStatus());
+        ClElementStatisticsList result2 = response2.readEntity(ClElementStatisticsList.class);
+
+        assertNotNull(result2);
+        assertThat(result2.getClElementStatistics()).hasSize(1);
+        assertEquals(result1.getClElementStatistics().get(0), clElementStatisticsList
+            .getClElementStatistics().get(0));
+    }
+
+    @Test
+    public void testClElementStats_BadRequest() throws Exception {
+        Invocation.Builder invokeRequest1 =
+            super.sendRequest(CLELEMENT_STATS_ENDPOINT + "?version=1.0.0");
+        Response response1 = invokeRequest1.buildGet().invoke();
+        assertEquals(Response.Status.INTERNAL_SERVER_ERROR.getStatusCode(), response1.getStatus());
+    }
+
+    @Test
+    public void testParticipantStatisticsEndpoint() throws Exception {
+
+        // Filter statistics only based on participant Id
+        Invocation.Builder invokeRequest1 =
+            super.sendRequest(PARTICIPANT_STATS_ENDPOINT + "?name=" + participantStatisticsList
+                .getStatisticsList().get(0).getParticipantId().getName() + "&version=" + participantStatisticsList
+                .getStatisticsList().get(0).getParticipantId().getVersion());
+        Response response1 = invokeRequest1.buildGet().invoke();
+        assertEquals(Response.Status.OK.getStatusCode(), response1.getStatus());
+        ParticipantStatisticsList result1 = response1.readEntity(ParticipantStatisticsList.class);
+
+        assertNotNull(result1);
+        assertThat(result1.getStatisticsList()).hasSize(2);
+        assertEquals(result1.getStatisticsList().get(0), participantStatisticsList
+            .getStatisticsList().get(0));
+
+        // Filter statistics based on timestamp
+        Invocation.Builder invokeRequest2 =
+            super.sendRequest(PARTICIPANT_STATS_ENDPOINT + "?name=" + participantStatisticsList
+                .getStatisticsList().get(1).getParticipantId().getName() + "&version=" + participantStatisticsList
+                .getStatisticsList().get(1).getParticipantId().getVersion() + "&startTime="
+                + Instant.parse("2021-01-10T13:00:00.000Z") + "&endTime=" + Instant.parse("2021-01-10T14:00:00.000Z"));
+        Response response2 = invokeRequest2.buildGet().invoke();
+        assertEquals(Response.Status.OK.getStatusCode(), response2.getStatus());
+        ParticipantStatisticsList result2 = response2.readEntity(ParticipantStatisticsList.class);
+
+        assertNotNull(result2);
+        assertThat(result2.getStatisticsList()).hasSize(1);
+        assertEquals(result1.getStatisticsList().get(0), participantStatisticsList
+            .getStatisticsList().get(0));
+    }
+
+    @Test
+    public void testParticipantStats_BadRequest() throws Exception {
+        Invocation.Builder invokeRequest1 =
+            super.sendRequest(PARTICIPANT_STATS_ENDPOINT + "?version=0.0");
+        Response response1 = invokeRequest1.buildGet().invoke();
+        assertEquals(Response.Status.INTERNAL_SERVER_ERROR.getStatusCode(), response1.getStatus());
+    }
+
+    @Test
+    public void testParticipantStatsPerClEndpoint() throws Exception {
+        Invocation.Builder invokeRequest1 =
+            super.sendRequest(PARTICIPANT_STATS_PER_CL_ENDPOINT + "?name=dummyName&version=1.001");
+        Response response1 = invokeRequest1.buildGet().invoke();
+        assertEquals(Response.Status.OK.getStatusCode(), response1.getStatus());
+        ParticipantStatisticsList result1 = response1.readEntity(ParticipantStatisticsList.class);
+        assertThat(result1.getStatisticsList()).isEmpty();
+    }
+
+    @Test
+    public void testParticipantStatsPerCl_BadRequest() throws Exception {
+        Invocation.Builder invokeRequest1 =
+            super.sendRequest(PARTICIPANT_STATS_PER_CL_ENDPOINT);
+        Response response1 = invokeRequest1.buildGet().invoke();
+        assertEquals(Response.Status.INTERNAL_SERVER_ERROR.getStatusCode(), response1.getStatus());
+    }
+
+    @Test
+    public void testClElementStatisticsPerClEndpoint() throws Exception {
+        Invocation.Builder invokeRequest1 =
+            super.sendRequest(CLELEMENT_STATS_PER_CL_ENDPOINT + "?name=dummyName&version=1.001");
+        Response response1 = invokeRequest1.buildGet().invoke();
+        assertEquals(Response.Status.OK.getStatusCode(), response1.getStatus());
+        ClElementStatisticsList result1 = response1.readEntity(ClElementStatisticsList.class);
+        assertThat(result1.getClElementStatistics()).isEmpty();
+    }
+
+    @Test
+    public void testClElementStatsPerCl_BadRequest() throws Exception {
+        Invocation.Builder invokeRequest1 =
+            super.sendRequest(CLELEMENT_STATS_PER_CL_ENDPOINT);
+        Response response1 = invokeRequest1.buildGet().invoke();
+        assertEquals(Response.Status.INTERNAL_SERVER_ERROR.getStatusCode(), response1.getStatus());
+    }
+}
diff --git a/runtime-controlloop/src/test/java/org/onap/policy/clamp/controlloop/runtime/util/CommonTestData.java b/runtime-controlloop/src/test/java/org/onap/policy/clamp/controlloop/runtime/util/CommonTestData.java
new file mode 100644
index 0000000..77f802d
--- /dev/null
+++ b/runtime-controlloop/src/test/java/org/onap/policy/clamp/controlloop/runtime/util/CommonTestData.java
@@ -0,0 +1,63 @@
+/*-
+ * ============LICENSE_START=======================================================
+ *  Copyright (C) 2021 Nordix Foundation.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.policy.clamp.controlloop.runtime.util;
+
+import org.onap.policy.clamp.controlloop.runtime.main.parameters.ClRuntimeParameterGroup;
+import org.onap.policy.common.utils.coder.Coder;
+import org.onap.policy.common.utils.coder.CoderException;
+import org.onap.policy.common.utils.coder.StandardCoder;
+import org.onap.policy.common.utils.resources.ResourceUtils;
+
+/**
+ * Class to hold/create all parameters for test cases.
+ *
+ */
+public class CommonTestData {
+    private static final Coder coder = new StandardCoder();
+
+    /**
+     * Gets the standard Control Loop parameters.
+     *
+     * @param port port to be inserted into the parameters
+     * @param dbName the database name
+     * @return the standard Control Loop parameters
+     */
+    public static ClRuntimeParameterGroup geParameterGroup(final int port, final String dbName) {
+        try {
+            return coder.decode(getParameterGroupAsString(port, dbName), ClRuntimeParameterGroup.class);
+
+        } catch (CoderException e) {
+            throw new RuntimeException("cannot read Control Loop parameters", e);
+        }
+    }
+
+    /**
+     * Gets the standard Control Loop parameters, as a String.
+     *
+     * @param port port to be inserted into the parameters
+     * @param dbName the database name
+     * @return the standard Control Loop parameters as string
+     */
+    public static String getParameterGroupAsString(final int port, final String dbName) {
+        return ResourceUtils.getResourceAsString("src/test/resources/parameters/InstantiationConfigParametersStd.json")
+                .replace("${port}", String.valueOf(port)).replace("${dbName}", "jdbc:h2:mem:" + dbName);
+    }
+}
diff --git a/runtime-controlloop/src/test/java/org/onap/policy/clamp/controlloop/runtime/util/rest/CommonRestController.java b/runtime-controlloop/src/test/java/org/onap/policy/clamp/controlloop/runtime/util/rest/CommonRestController.java
new file mode 100644
index 0000000..0d668f1
--- /dev/null
+++ b/runtime-controlloop/src/test/java/org/onap/policy/clamp/controlloop/runtime/util/rest/CommonRestController.java
@@ -0,0 +1,263 @@
+/*-
+ * ============LICENSE_START=======================================================
+ *  Copyright (C) 2021 Nordix Foundation.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.policy.clamp.controlloop.runtime.util.rest;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.nio.charset.StandardCharsets;
+import javax.ws.rs.client.Client;
+import javax.ws.rs.client.ClientBuilder;
+import javax.ws.rs.client.Entity;
+import javax.ws.rs.client.Invocation;
+import javax.ws.rs.client.WebTarget;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+import org.glassfish.jersey.client.ClientProperties;
+import org.glassfish.jersey.client.authentication.HttpAuthenticationFeature;
+import org.onap.policy.clamp.controlloop.common.exception.ControlLoopException;
+import org.onap.policy.clamp.controlloop.runtime.main.startstop.Main;
+import org.onap.policy.clamp.controlloop.runtime.util.CommonTestData;
+import org.onap.policy.common.gson.GsonMessageBodyHandler;
+import org.onap.policy.common.utils.network.NetworkUtil;
+import org.onap.policy.common.utils.services.Registry;
+import org.onap.policy.models.provider.PolicyModelsProviderParameters;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Class to perform Rest unit tests.
+ *
+ */
+public class CommonRestController {
+
+    private static final String CONFIG_FILE = "src/test/resources/parameters/RuntimeConfigParameters%d.json";
+
+    private static final Logger LOGGER = LoggerFactory.getLogger(CommonRestController.class);
+
+    public static final String SELF = NetworkUtil.getHostname();
+    public static final String ENDPOINT_PREFIX = "onap/controlloop/v2/";
+
+    private static int port;
+    private static String httpPrefix;
+    private static Main main;
+
+    /**
+     * Allocates a port for the server, writes a config file, and then starts Main.
+     *
+     * @param dbName database name
+     * @throws Exception if an error occurs
+     */
+    public static void setUpBeforeClass(final String dbName) throws Exception {
+        port = NetworkUtil.allocPort();
+
+        httpPrefix = "http://" + SELF + ":" + port + "/";
+
+        makeConfigFile(dbName);
+        startMain();
+    }
+
+    /**
+     * Stops Main.
+     */
+    public static void teardownAfterClass() {
+        try {
+            stopMain();
+        } catch (Exception ex) {
+            LOGGER.error("cannot stop main", ex);
+        }
+    }
+
+    protected static PolicyModelsProviderParameters getParameters() {
+        return main.getParameters().getDatabaseProviderParameters();
+    }
+
+    /**
+     * Verifies that an endpoint appears within the swagger response.
+     *
+     * @param endpoint the endpoint of interest
+     * @throws Exception if an error occurs
+     */
+    protected void testSwagger(final String endpoint) throws Exception {
+        final Invocation.Builder invocationBuilder = sendFqeRequest(httpPrefix + "swagger.yaml", true);
+        final String resp = invocationBuilder.get(String.class);
+
+        assertTrue(resp.contains(ENDPOINT_PREFIX + endpoint + ":"));
+    }
+
+    /**
+     * Makes a parameter configuration file.
+     *
+     * @param dbName database name
+     * @throws IOException if an error occurs writing the configuration file
+     * @throws FileNotFoundException if an error occurs writing the configuration file
+     */
+    private static void makeConfigFile(final String dbName) throws FileNotFoundException, IOException {
+        String json = CommonTestData.getParameterGroupAsString(port, dbName);
+
+        File file = new File(String.format(CONFIG_FILE, port));
+        file.deleteOnExit();
+
+        try (FileOutputStream output = new FileOutputStream(file)) {
+            output.write(json.getBytes(StandardCharsets.UTF_8));
+        }
+    }
+
+    /**
+     * Starts the "Main".
+     *
+     * @throws InterruptedException
+     *
+     * @throws Exception if an error occurs
+     */
+    protected static void startMain() throws InterruptedException {
+        Registry.newRegistry();
+
+        // make sure port is available
+        if (NetworkUtil.isTcpPortOpen(SELF, port, 1, 1L)) {
+            throw new IllegalStateException("port " + port + " is not available");
+        }
+
+        final String[] configParameters = {"-c", String.format(CONFIG_FILE, port)};
+
+        main = new Main(configParameters);
+
+        if (!NetworkUtil.isTcpPortOpen(SELF, port, 40, 250L)) {
+            throw new IllegalStateException("server is not listening on port " + port);
+        }
+    }
+
+    /**
+     * Stops the "Main".
+     *
+     * @throws ControlLoopException
+     *
+     * @throws Exception if an error occurs
+     */
+    private static void stopMain() throws Exception {
+        if (main != null) {
+            Main main2 = main;
+            main = null;
+
+            main2.shutdown();
+        }
+        // make sure port is close
+        if (NetworkUtil.isTcpPortOpen(SELF, port, 1, 1L)) {
+            throw new IllegalStateException("port " + port + " is still in use");
+        }
+    }
+
+    /**
+     * Sends a request to an endpoint.
+     *
+     * @param endpoint the target endpoint
+     * @return a request builder
+     * @throws Exception if an error occurs
+     */
+    protected Invocation.Builder sendRequest(final String endpoint) throws Exception {
+        return sendFqeRequest(httpPrefix + ENDPOINT_PREFIX + endpoint, true);
+    }
+
+    /**
+     * Sends a request to an endpoint, without any authorization header.
+     *
+     * @param endpoint the target endpoint
+     * @return a request builder
+     * @throws Exception if an error occurs
+     */
+    protected Invocation.Builder sendNoAuthRequest(final String endpoint) throws Exception {
+        return sendFqeRequest(httpPrefix + ENDPOINT_PREFIX + endpoint, false);
+    }
+
+    /**
+     * Sends a request to a fully qualified endpoint.
+     *
+     * @param fullyQualifiedEndpoint the fully qualified target endpoint
+     * @param includeAuth if authorization header should be included
+     * @return a request builder
+     * @throws Exception if an error occurs
+     */
+    protected Invocation.Builder sendFqeRequest(final String fullyQualifiedEndpoint, boolean includeAuth)
+            throws Exception {
+        final Client client = ClientBuilder.newBuilder().build();
+
+        client.property(ClientProperties.METAINF_SERVICES_LOOKUP_DISABLE, "true");
+        client.register(GsonMessageBodyHandler.class);
+
+        if (includeAuth) {
+            client.register(HttpAuthenticationFeature.basic("healthcheck", "zb!XztG34"));
+        }
+
+        final WebTarget webTarget = client.target(fullyQualifiedEndpoint);
+
+        return webTarget.request(MediaType.APPLICATION_JSON);
+    }
+
+    /**
+     * Assert that POST call is Unauthorized.
+     *
+     * @param endPoint the endpoint
+     * @param entity the entity ofthe body
+     * @throws Exception if an error occurs
+     */
+    protected void assertUnauthorizedPost(final String endPoint, final Entity<?> entity) throws Exception {
+        Response rawresp = sendNoAuthRequest(endPoint).post(entity);
+        assertEquals(Response.Status.UNAUTHORIZED.getStatusCode(), rawresp.getStatus());
+    }
+
+    /**
+     * Assert that PUT call is Unauthorized.
+     *
+     * @param endPoint the endpoint
+     * @param entity the entity ofthe body
+     * @throws Exception if an error occurs
+     */
+    protected void assertUnauthorizedPut(final String endPoint, final Entity<?> entity) throws Exception {
+        Response rawresp = sendNoAuthRequest(endPoint).put(entity);
+        assertEquals(Response.Status.UNAUTHORIZED.getStatusCode(), rawresp.getStatus());
+    }
+
+    /**
+     * Assert that GET call is Unauthorized.
+     *
+     * @param endPoint the endpoint
+     * @throws Exception if an error occurs
+     */
+    protected void assertUnauthorizedGet(final String endPoint) throws Exception {
+        Response rawresp = sendNoAuthRequest(endPoint).buildGet().invoke();
+        assertEquals(Response.Status.UNAUTHORIZED.getStatusCode(), rawresp.getStatus());
+    }
+
+    /**
+     * Assert that DELETE call is Unauthorized.
+     *
+     * @param endPoint the endpoint
+     * @throws Exception if an error occurs
+     */
+    protected void assertUnauthorizedDelete(final String endPoint) throws Exception {
+        Response rawresp = sendNoAuthRequest(endPoint).delete();
+        assertEquals(Response.Status.UNAUTHORIZED.getStatusCode(), rawresp.getStatus());
+    }
+}
\ No newline at end of file
diff --git a/runtime-controlloop/src/test/resources/META-INF/persistence.xml b/runtime-controlloop/src/test/resources/META-INF/persistence.xml
new file mode 100644
index 0000000..6e31cca
--- /dev/null
+++ b/runtime-controlloop/src/test/resources/META-INF/persistence.xml
@@ -0,0 +1,159 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  ============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=========================================================
+-->
+<persistence xmlns="http://java.sun.com/xml/ns/persistence" version="2.0">
+    <persistence-unit name="CommissioningMariaDb" transaction-type="RESOURCE_LOCAL">
+        <provider>org.eclipse.persistence.jpa.PersistenceProvider</provider>
+
+        <class>org.onap.policy.models.base.PfConceptKey</class>
+        <class>org.onap.policy.models.dao.converters.CDataConditioner</class>
+        <class>org.onap.policy.models.dao.converters.Uuid2String</class>
+        <class>org.onap.policy.models.pdp.persistence.concepts.JpaPdp</class>
+        <class>org.onap.policy.models.pdp.persistence.concepts.JpaPdpGroup</class>
+        <class>org.onap.policy.models.pdp.persistence.concepts.JpaPdpStatistics</class>
+        <class>org.onap.policy.models.pdp.persistence.concepts.JpaPdpSubGroup</class>
+        <class>org.onap.policy.models.tosca.simple.concepts.JpaToscaCapabilityAssignment</class>
+        <class>org.onap.policy.models.tosca.simple.concepts.JpaToscaCapabilityAssignments</class>
+        <class>org.onap.policy.models.tosca.simple.concepts.JpaToscaCapabilityType</class>
+        <class>org.onap.policy.models.tosca.simple.concepts.JpaToscaCapabilityTypes</class>
+        <class>org.onap.policy.models.tosca.simple.concepts.JpaToscaDataType</class>
+        <class>org.onap.policy.models.tosca.simple.concepts.JpaToscaDataTypes</class>
+        <class>org.onap.policy.models.tosca.simple.concepts.JpaToscaNodeTemplate</class>
+        <class>org.onap.policy.models.tosca.simple.concepts.JpaToscaNodeTemplates</class>
+        <class>org.onap.policy.models.tosca.simple.concepts.JpaToscaNodeType</class>
+        <class>org.onap.policy.models.tosca.simple.concepts.JpaToscaNodeTypes</class>
+        <class>org.onap.policy.models.tosca.simple.concepts.JpaToscaParameter</class>
+        <class>org.onap.policy.models.tosca.simple.concepts.JpaToscaPolicies</class>
+        <class>org.onap.policy.models.tosca.simple.concepts.JpaToscaPolicy</class>
+        <class>org.onap.policy.models.tosca.simple.concepts.JpaToscaPolicyType</class>
+        <class>org.onap.policy.models.tosca.simple.concepts.JpaToscaPolicyTypes</class>
+        <class>org.onap.policy.models.tosca.simple.concepts.JpaToscaProperty</class>
+        <class>org.onap.policy.models.tosca.simple.concepts.JpaToscaRelationshipType</class>
+        <class>org.onap.policy.models.tosca.simple.concepts.JpaToscaRelationshipTypes</class>
+        <class>org.onap.policy.models.tosca.simple.concepts.JpaToscaRequirement</class>
+        <class>org.onap.policy.models.tosca.simple.concepts.JpaToscaRequirements</class>
+        <class>org.onap.policy.models.tosca.simple.concepts.JpaToscaServiceTemplate</class>
+        <class>org.onap.policy.models.tosca.simple.concepts.JpaToscaTopologyTemplate</class>
+        <class>org.onap.policy.models.tosca.simple.concepts.JpaToscaTrigger</class>
+        <class>org.onap.policy.clamp.controlloop.models.controlloop.persistence.concepts.JpaControlLoop</class>
+        <class>org.onap.policy.clamp.controlloop.models.controlloop.persistence.concepts.JpaControlLoopElement</class>
+        <class>org.onap.policy.clamp.controlloop.models.controlloop.persistence.concepts.JpaParticipant</class>
+        <class>org.onap.policy.clamp.controlloop.models.controlloop.persistence.concepts.JpaParticipantStatistics</class>
+        <class>org.onap.policy.clamp.controlloop.models.controlloop.persistence.concepts.JpaClElementStatistics</class>
+
+        <properties>
+            <property name="eclipselink.ddl-generation" value="create-or-extend-tables" />
+            <property name="eclipselink.ddl-generation.output-mode" value="database" />
+            <property name="eclipselink.logging.level" value="INFO" />
+
+            <!-- property name="eclipselink.logging.level" value="ALL" />
+            <property name="eclipselink.logging.level.jpa" value="ALL" />
+            <property name="eclipselink.logging.level.ddl" value="ALL" />
+            <property name="eclipselink.logging.level.connection" value="ALL" />
+            <property name="eclipselink.logging.level.sql" value="ALL" />
+            <property name="eclipselink.logging.level.transaction" value="ALL" />
+            <property name="eclipselink.logging.level.sequencing" value="ALL" />
+            <property name="eclipselink.logging.level.server" value="ALL" />
+            <property name="eclipselink.logging.level.query" value="ALL" />
+            <property name="eclipselink.logging.level.properties" value="ALL" /-->
+        </properties>
+        <shared-cache-mode>NONE</shared-cache-mode>
+    </persistence-unit>
+
+    <persistence-unit name="ToscaConceptTest" transaction-type="RESOURCE_LOCAL">
+        <provider>org.eclipse.persistence.jpa.PersistenceProvider</provider>
+
+        <class>org.onap.policy.models.tosca.simple.concepts.JpaToscaCapabilityAssignment</class>
+        <class>org.onap.policy.models.tosca.simple.concepts.JpaToscaCapabilityAssignments</class>
+        <class>org.onap.policy.models.tosca.simple.concepts.JpaToscaCapabilityType</class>
+        <class>org.onap.policy.models.tosca.simple.concepts.JpaToscaCapabilityTypes</class>
+        <class>org.onap.policy.models.tosca.simple.concepts.JpaToscaDataType</class>
+        <class>org.onap.policy.models.tosca.simple.concepts.JpaToscaDataTypes</class>
+        <class>org.onap.policy.models.tosca.simple.concepts.JpaToscaNodeTemplate</class>
+        <class>org.onap.policy.models.tosca.simple.concepts.JpaToscaNodeTemplates</class>
+        <class>org.onap.policy.models.tosca.simple.concepts.JpaToscaNodeType</class>
+        <class>org.onap.policy.models.tosca.simple.concepts.JpaToscaNodeTypes</class>
+        <class>org.onap.policy.models.tosca.simple.concepts.JpaToscaParameter</class>
+        <class>org.onap.policy.models.tosca.simple.concepts.JpaToscaPolicies</class>
+        <class>org.onap.policy.models.tosca.simple.concepts.JpaToscaPolicy</class>
+        <class>org.onap.policy.models.tosca.simple.concepts.JpaToscaPolicyType</class>
+        <class>org.onap.policy.models.tosca.simple.concepts.JpaToscaPolicyTypes</class>
+        <class>org.onap.policy.models.tosca.simple.concepts.JpaToscaProperty</class>
+        <class>org.onap.policy.models.tosca.simple.concepts.JpaToscaRelationshipType</class>
+        <class>org.onap.policy.models.tosca.simple.concepts.JpaToscaRelationshipTypes</class>
+        <class>org.onap.policy.models.tosca.simple.concepts.JpaToscaRequirement</class>
+        <class>org.onap.policy.models.tosca.simple.concepts.JpaToscaRequirements</class>
+        <class>org.onap.policy.models.tosca.simple.concepts.JpaToscaServiceTemplate</class>
+        <class>org.onap.policy.models.tosca.simple.concepts.JpaToscaTopologyTemplate</class>
+        <class>org.onap.policy.clamp.controlloop.models.controlloop.persistence.concepts.JpaControlLoop</class>
+        <class>org.onap.policy.clamp.controlloop.models.controlloop.persistence.concepts.JpaControlLoopElement</class>
+        <class>org.onap.policy.clamp.controlloop.models.controlloop.persistence.concepts.JpaParticipantStatistics</class>
+        <class>org.onap.policy.clamp.controlloop.models.controlloop.persistence.concepts.JpaClElementStatistics</class>
+
+        <properties>
+            <property name="eclipselink.target-database" value="MySQL" />
+            <property name="eclipselink.ddl-generation" value="drop-and-create-tables" />
+            <property name="eclipselink.ddl-generation.output-mode" value="database" />
+            <property name="eclipselink.logging.level" value="INFO" />
+        </properties>
+        <shared-cache-mode>NONE</shared-cache-mode>
+    </persistence-unit>
+
+    <persistence-unit name="InstantiationTests" transaction-type="RESOURCE_LOCAL">
+        <provider>org.eclipse.persistence.jpa.PersistenceProvider</provider>
+
+        <class>org.onap.policy.models.tosca.simple.concepts.JpaToscaCapabilityAssignment</class>
+        <class>org.onap.policy.models.tosca.simple.concepts.JpaToscaCapabilityAssignments</class>
+        <class>org.onap.policy.models.tosca.simple.concepts.JpaToscaCapabilityType</class>
+        <class>org.onap.policy.models.tosca.simple.concepts.JpaToscaCapabilityTypes</class>
+        <class>org.onap.policy.models.tosca.simple.concepts.JpaToscaDataType</class>
+        <class>org.onap.policy.models.tosca.simple.concepts.JpaToscaDataTypes</class>
+        <class>org.onap.policy.models.tosca.simple.concepts.JpaToscaNodeTemplate</class>
+        <class>org.onap.policy.models.tosca.simple.concepts.JpaToscaNodeTemplates</class>
+        <class>org.onap.policy.models.tosca.simple.concepts.JpaToscaNodeType</class>
+        <class>org.onap.policy.models.tosca.simple.concepts.JpaToscaNodeTypes</class>
+        <class>org.onap.policy.models.tosca.simple.concepts.JpaToscaParameter</class>
+        <class>org.onap.policy.models.tosca.simple.concepts.JpaToscaPolicies</class>
+        <class>org.onap.policy.models.tosca.simple.concepts.JpaToscaPolicy</class>
+        <class>org.onap.policy.models.tosca.simple.concepts.JpaToscaPolicyType</class>
+        <class>org.onap.policy.models.tosca.simple.concepts.JpaToscaPolicyTypes</class>
+        <class>org.onap.policy.models.tosca.simple.concepts.JpaToscaProperty</class>
+        <class>org.onap.policy.models.tosca.simple.concepts.JpaToscaRelationshipType</class>
+        <class>org.onap.policy.models.tosca.simple.concepts.JpaToscaRelationshipTypes</class>
+        <class>org.onap.policy.models.tosca.simple.concepts.JpaToscaRequirement</class>
+        <class>org.onap.policy.models.tosca.simple.concepts.JpaToscaRequirements</class>
+        <class>org.onap.policy.models.tosca.simple.concepts.JpaToscaServiceTemplate</class>
+        <class>org.onap.policy.models.tosca.simple.concepts.JpaToscaTopologyTemplate</class>
+        <class>org.onap.policy.clamp.controlloop.models.controlloop.persistence.concepts.JpaControlLoop</class>
+        <class>org.onap.policy.clamp.controlloop.models.controlloop.persistence.concepts.JpaControlLoopElement</class>
+        <class>org.onap.policy.clamp.controlloop.models.controlloop.persistence.concepts.JpaParticipant</class>
+        <class>org.onap.policy.clamp.controlloop.models.controlloop.persistence.concepts.JpaParticipantStatistics</class>
+        <class>org.onap.policy.clamp.controlloop.models.controlloop.persistence.concepts.JpaClElementStatistics</class>
+
+        <properties>
+            <property name="eclipselink.ddl-generation" value="create-or-extend-tables" />
+            <property name="eclipselink.ddl-generation.output-mode" value="database" />
+            <property name="eclipselink.logging.level" value="INFO" />
+        </properties>
+        <shared-cache-mode>NONE</shared-cache-mode>
+    </persistence-unit>
+
+</persistence>
+
diff --git a/runtime-controlloop/src/test/resources/parameters/CommissioningConfig.json b/runtime-controlloop/src/test/resources/parameters/CommissioningConfig.json
new file mode 100644
index 0000000..bda9da6
--- /dev/null
+++ b/runtime-controlloop/src/test/resources/parameters/CommissioningConfig.json
@@ -0,0 +1,20 @@
+{
+  "name": "CommissioningGroup",
+  "restServerParameters": {
+    "host": "127.0.0.1",
+    "port": 6969,
+    "userName": "admin",
+    "password": "password",
+    "https": false,
+    "aaf": false
+  },
+  "databaseProviderParameters": {
+    "name": "CommissioningProviderParameterGroup",
+    "implementation": "org.onap.policy.models.provider.impl.DatabasePolicyModelsProviderImpl",
+    "databaseDriver": "org.h2.Driver",
+    "databaseUrl": "jdbc:h2:mem:testdb",
+    "databaseUser": "controlloop",
+    "databasePassword": "C0ntr0lL00p",
+    "persistenceUnit": "ToscaConceptTest"
+  }
+}
diff --git a/runtime-controlloop/src/test/resources/parameters/EmptyParameters.json b/runtime-controlloop/src/test/resources/parameters/EmptyParameters.json
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/runtime-controlloop/src/test/resources/parameters/EmptyParameters.json
diff --git a/runtime-controlloop/src/test/resources/parameters/InstantiationConfigParametersStd.json b/runtime-controlloop/src/test/resources/parameters/InstantiationConfigParametersStd.json
new file mode 100644
index 0000000..7682a18
--- /dev/null
+++ b/runtime-controlloop/src/test/resources/parameters/InstantiationConfigParametersStd.json
@@ -0,0 +1,79 @@
+{
+    "name": "ControlLoopRuntimeGroup",
+    "restServerParameters": {
+        "host": "0.0.0.0",
+        "port": ${port},
+        "userName": "healthcheck",
+        "password": "zb!XztG34",
+        "https": false,
+        "aaf": false
+    },
+    "participantParameters": {
+        "heartBeatMs": 120000,
+        "updateParameters": {
+            "maxRetryCount": 1,
+            "maxWaitMs": 30000
+        },
+        "stateChangeParameters": {
+            "maxRetryCount": 1,
+            "maxWaitMs": 30000
+        }
+    },
+    "databaseProviderParameters": {
+        "name": "PolicyProviderParameterGroup",
+        "implementation": "org.onap.policy.models.provider.impl.DatabasePolicyModelsProviderImpl",
+        "databaseDriver": "org.h2.Driver",
+        "databaseUrl": "${dbName}",
+        "databaseUser": "policy",
+        "databasePassword": "P01icY",
+        "persistenceUnit": "InstantiationTests"
+    },
+    "topicParameterGroup": {
+        "topicSources": [
+            {
+                "topic": "POLICY-CLRUNTIME-PARTICIPANT",
+                "servers": [
+                    "localhost"
+                ],
+                "topicCommInfrastructure": "dmaap",
+                "fetchTimeout": 15000
+            }
+        ],
+        "topicSinks": [
+            {
+                "topic": "POLICY-CLRUNTIME-PARTICIPANT",
+                "servers": [
+                    "localhost"
+                ],
+                "topicCommInfrastructure": "dmaap"
+            },
+            {
+                "topic": "POLICY-NOTIFICATION",
+                "servers": [
+                    "localhost"
+                ],
+                "topicCommInfrastructure": "dmaap"
+            }
+        ]
+    },
+    "healthCheckRestClientParameters": [
+        {
+            "clientName": "api",
+            "hostname": "policy-api",
+            "port": 6969,
+            "userName": "healthcheck",
+            "password": "zb!XztG34",
+            "useHttps": true,
+            "basePath": "policy/api/v1/healthcheck"
+        },
+        {
+            "clientName": "distribution",
+            "hostname": "policy-distribution",
+            "port": 6969,
+            "userName": "healthcheck",
+            "password": "zb!XztG34",
+            "useHttps": true,
+            "basePath": "healthcheck"
+        }
+    ]
+}
diff --git a/runtime-controlloop/src/test/resources/parameters/InstantiationConfigParameters_InvalidName.json b/runtime-controlloop/src/test/resources/parameters/InstantiationConfigParameters_InvalidName.json
new file mode 100644
index 0000000..b0c322c
--- /dev/null
+++ b/runtime-controlloop/src/test/resources/parameters/InstantiationConfigParameters_InvalidName.json
@@ -0,0 +1,31 @@
+{
+    "name":" ",
+  "restServerParameters": {
+    "host": "127.0.0.1",
+    "port": 6969,
+    "userName": "admin",
+    "password": "password",
+    "https": false,
+    "aaf": false
+  },
+    "pdpParameters": {
+        "heartBeatMs": 1,
+        "updateParameters": {
+            "maxRetryCount": 1,
+            "maxWaitMs": 1
+        },
+        "stateChangeParameters": {
+            "maxRetryCount": 1,
+            "maxWaitMs": 1
+        }
+    },
+    "databaseProviderParameters": {
+        "name": "PolicyProviderParameterGroup",
+        "implementation": "org.onap.policy.models.provider.impl.DatabasePolicyModelsProviderImpl",
+        "databaseDriver": "org.h2.Driver",
+        "databaseUrl": "jdbc:h2:mem:testdb",
+        "databaseUser": "policy",
+        "databasePassword": "P01icY",
+        "persistenceUnit": "PdpGroupTest"
+    }
+}
diff --git a/runtime-controlloop/src/test/resources/parameters/InstantiationConfigParameters_sim.json b/runtime-controlloop/src/test/resources/parameters/InstantiationConfigParameters_sim.json
new file mode 100644
index 0000000..0977da9
--- /dev/null
+++ b/runtime-controlloop/src/test/resources/parameters/InstantiationConfigParameters_sim.json
@@ -0,0 +1,43 @@
+{
+    "name": "Instantiation",
+  "restServerParameters": {
+    "host": "127.0.0.1",
+    "port": 6969,
+    "userName": "admin",
+    "password": "password",
+    "https": false,
+    "aaf": false
+  },
+    "pdpParameters": {
+        "heartBeatMs": 10,
+        "updateParameters": {
+            "maxRetryCount": 1,
+            "maxWaitMs": 30000
+        },
+        "stateChangeParameters": {
+            "maxRetryCount": 1,
+            "maxWaitMs": 30000
+        }
+    },
+    "databaseProviderParameters": {
+        "name": "PolicyProviderParameterGroup",
+        "implementation": "org.onap.policy.models.provider.impl.DatabasePolicyModelsProviderImpl",
+        "databaseDriver": "org.mariadb.jdbc.Driver",
+        "databaseUrl": "jdbc:mariadb://localhost:3306/policyadmin",
+        "databaseUser": "policy",
+        "databasePassword": "UDAxaWNZ",
+        "persistenceUnit": "PolicyMariaDb"
+    },
+    "topicParameterGroup": {
+        "topicSources" : [{
+            "topic" : "INSTANTIATION",
+            "servers" : [ "localhost:6845" ],
+            "topicCommInfrastructure" : "dmaap"
+        }],
+        "topicSinks" : [{
+            "topic" : "INSTANTIATION",
+            "servers" : [ "localhost:6845" ],
+            "topicCommInfrastructure" : "dmaap"
+        }]
+    }
+}
diff --git a/runtime-controlloop/src/test/resources/parameters/InvalidParameters.json b/runtime-controlloop/src/test/resources/parameters/InvalidParameters.json
new file mode 100644
index 0000000..976ec29
--- /dev/null
+++ b/runtime-controlloop/src/test/resources/parameters/InvalidParameters.json
@@ -0,0 +1,3 @@
+{
+  "name": ""
+}
diff --git a/runtime-controlloop/src/test/resources/parameters/MinimumParametersH2.json b/runtime-controlloop/src/test/resources/parameters/MinimumParametersH2.json
new file mode 100644
index 0000000..f784dcd
--- /dev/null
+++ b/runtime-controlloop/src/test/resources/parameters/MinimumParametersH2.json
@@ -0,0 +1,59 @@
+{
+    "name":"PapGroup",
+    "restServerParameters":{
+        "host":"0.0.0.0",
+        "port":6969,
+        "userName":"healthcheck",
+        "password":"zb!XztG34"
+    },
+    "pdpParameters": {
+        "heartBeatMs": 1,
+        "updateParameters": {
+            "maxRetryCount": 1,
+            "maxWaitMs": 1
+        },
+        "stateChangeParameters": {
+            "maxRetryCount": 1,
+            "maxWaitMs": 1
+        }
+    },
+    "databaseProviderParameters": {
+        "name": "PolicyProviderParameterGroup",
+        "implementation": "org.onap.policy.models.provider.impl.DatabasePolicyModelsProviderImpl",
+        "databaseDriver": "org.h2.Driver",
+        "databaseUrl": "jdbc:h2:mem:testdb",
+        "databaseUser": "policy",
+        "databasePassword": "P01icY",
+        "persistenceUnit": "PdpGroupTest"
+    },
+    "topicParameterGroup": {
+        "topicSources" : [{
+            "topic" : "POLICY-PDP-PAP",
+            "servers" : [ "message-router" ],
+            "topicCommInfrastructure" : "dmaap"
+        }],
+        "topicSinks" : [{
+            "topic" : "POLICY-PDP-PAP",
+            "servers" : [ "message-router" ],
+            "topicCommInfrastructure" : "dmaap"
+        }]
+    },
+    "healthCheckRestClientParameters":[{
+        "clientName": "api",
+        "hostname": "policy-api",
+        "port": 6969,
+        "userName": "healthcheck",
+        "password": "zb!XztG34",
+        "useHttps": true,
+        "basePath": "policy/api/v1/healthcheck"
+    },
+    {
+        "clientName": "distribution",
+        "hostname": "policy-distribution",
+        "port": 6969,
+        "userName": "healthcheck",
+        "password": "zb!XztG34",
+        "useHttps": true,
+        "basePath": "healthcheck"
+    }]
+}
diff --git a/runtime-controlloop/src/test/resources/parameters/NoParameters.json b/runtime-controlloop/src/test/resources/parameters/NoParameters.json
new file mode 100644
index 0000000..2c63c08
--- /dev/null
+++ b/runtime-controlloop/src/test/resources/parameters/NoParameters.json
@@ -0,0 +1,2 @@
+{
+}
diff --git a/runtime-controlloop/src/test/resources/parameters/TestParameters.json b/runtime-controlloop/src/test/resources/parameters/TestParameters.json
new file mode 100644
index 0000000..c3be762
--- /dev/null
+++ b/runtime-controlloop/src/test/resources/parameters/TestParameters.json
@@ -0,0 +1,79 @@
+{
+    "name": "ControlLoopRuntimeGroup",
+    "restServerParameters": {
+        "host": "0.0.0.0",
+        "port": 6969,
+        "userName": "healthcheck",
+        "password": "zb!XztG34",
+        "https": false,
+        "aaf": false
+    },
+    "participantParameters": {
+        "heartBeatMs": 120000,
+        "updateParameters": {
+            "maxRetryCount": 1,
+            "maxWaitMs": 30000
+        },
+        "stateChangeParameters": {
+            "maxRetryCount": 1,
+            "maxWaitMs": 30000
+        }
+    },
+    "databaseProviderParameters": {
+        "name": "PolicyProviderParameterGroup",
+        "implementation": "org.onap.policy.models.provider.impl.DatabasePolicyModelsProviderImpl",
+        "databaseDriver": "org.h2.Driver",
+        "databaseUrl": "jdbc:h2:mem:testdb",
+        "databaseUser": "policy",
+        "databasePassword": "P01icY",
+        "persistenceUnit": "ToscaConceptTest"
+    },
+    "topicParameterGroup": {
+        "topicSources": [
+            {
+                "topic": "POLICY-CLRUNTIME-PARTICIPANT",
+                "servers": [
+                    "localhost"
+                ],
+                "topicCommInfrastructure": "dmaap",
+                "fetchTimeout": 15000
+            }
+        ],
+        "topicSinks": [
+            {
+                "topic": "POLICY-CLRUNTIME-PARTICIPANT",
+                "servers": [
+                    "localhost"
+                ],
+                "topicCommInfrastructure": "dmaap"
+            },
+            {
+                "topic": "POLICY-NOTIFICATION",
+                "servers": [
+                    "localhost"
+                ],
+                "topicCommInfrastructure": "dmaap"
+            }
+        ]
+    },
+    "healthCheckRestClientParameters": [
+        {
+            "clientName": "api",
+            "hostname": "policy-api",
+            "port": 6969,
+            "userName": "healthcheck",
+            "password": "zb!XztG34",
+            "useHttps": true,
+            "basePath": "policy/api/v1/healthcheck"
+        },
+        {
+            "clientName": "distribution",
+            "hostname": "policy-distribution",
+            "port": 6969,
+            "userName": "healthcheck",
+            "password": "zb!XztG34",
+            "useHttps": true,
+            "basePath": "healthcheck"
+        }
+    ]
+}
diff --git a/runtime-controlloop/src/test/resources/parameters/TestParametersMariaDB.json b/runtime-controlloop/src/test/resources/parameters/TestParametersMariaDB.json
new file mode 100644
index 0000000..2c0127b
--- /dev/null
+++ b/runtime-controlloop/src/test/resources/parameters/TestParametersMariaDB.json
@@ -0,0 +1,79 @@
+{
+    "name": "ControlLoopRuntimeGroup",
+    "restServerParameters": {
+        "host": "0.0.0.0",
+        "port": 6969,
+        "userName": "healthcheck",
+        "password": "zb!XztG34",
+        "https": false,
+        "aaf": false
+    },
+    "participantParameters": {
+        "heartBeatMs": 120000,
+        "updateParameters": {
+            "maxRetryCount": 1,
+            "maxWaitMs": 30000
+        },
+        "stateChangeParameters": {
+            "maxRetryCount": 1,
+            "maxWaitMs": 30000
+        }
+    },
+    "databaseProviderParameters": {
+        "name": "PolicyProviderParameterGroup",
+        "implementation": "org.onap.policy.models.provider.impl.DatabasePolicyModelsProviderImpl",
+        "databaseDriver": "org.mariadb.jdbc.Driver",
+        "databaseUrl": "jdbc:mariadb://localhost:3306/controlloop",
+        "databaseUser": "policy",
+        "databasePassword": "P01icY",
+        "persistenceUnit": "CommissioningMariaDb"
+    },
+    "topicParameterGroup": {
+        "topicSources": [
+            {
+                "topic": "POLICY-CLRUNTIME-PARTICIPANT",
+                "servers": [
+                    "localhost"
+                ],
+                "topicCommInfrastructure": "dmaap",
+                "fetchTimeout": 15000
+            }
+        ],
+        "topicSinks": [
+            {
+                "topic": "POLICY-CLRUNTIME-PARTICIPANT",
+                "servers": [
+                    "localhost"
+                ],
+                "topicCommInfrastructure": "dmaap"
+            },
+            {
+                "topic": "POLICY-NOTIFICATION",
+                "servers": [
+                    "localhost"
+                ],
+                "topicCommInfrastructure": "dmaap"
+            }
+        ]
+    },
+    "healthCheckRestClientParameters": [
+        {
+            "clientName": "api",
+            "hostname": "policy-api",
+            "port": 6969,
+            "userName": "healthcheck",
+            "password": "zb!XztG34",
+            "useHttps": true,
+            "basePath": "policy/api/v1/healthcheck"
+        },
+        {
+            "clientName": "distribution",
+            "hostname": "policy-distribution",
+            "port": 6969,
+            "userName": "healthcheck",
+            "password": "zb!XztG34",
+            "useHttps": true,
+            "basePath": "healthcheck"
+        }
+    ]
+}
diff --git a/runtime-controlloop/src/test/resources/parameters/Unreadable.json b/runtime-controlloop/src/test/resources/parameters/Unreadable.json
new file mode 100644
index 0000000..3d117f4
--- /dev/null
+++ b/runtime-controlloop/src/test/resources/parameters/Unreadable.json
@@ -0,0 +1,78 @@
+{
+    "name": "ControlLoopRuntimeGroup",
+    "restServerParameters": {
+        "host": "0.0.0.0",
+        "port": 6969,
+        "userName": "healthcheck",
+        "password": "zb!XztG34",
+        "https": false,
+        "aaf": false
+    },
+    "participantParameters": {
+        "heartBeatMs": 120000,
+        "updateParameters": {
+            "maxRetryCount": 1,
+            "maxWaitMs": 30000
+        },
+        "stateChangeParameters": {
+            "maxRetryCount": 1,
+            "maxWaitMs": 30000
+        }
+    },
+    "databaseProviderParameters": {
+        "name": "PolicyProviderParameterGroup",
+        "implementation": "org.onap.policy.models.provider.impl.DatabasePolicyModelsProviderImpl",
+        "databaseDriver": "org.h2.Driver",
+        "databaseUrl": "jdbc:h2:mem:testdb",
+        "databaseUser": "policy",
+        "databasePassword": "P01icY",
+        "persistenceUnit": "ToscaConceptTest"
+    },
+    "topicParameterGroup": {
+        "topicSources": [
+            {
+                "topic": "POLICY-CLRUNTIME-PARTICIPANT",
+                "servers": [
+                    "localhost"
+                ],
+                "topicCommInfrastructure": "dmaap",
+                "fetchTimeout": 15000
+            }
+        ],
+        "topicSinks": [
+            {
+                "topic": "POLICY-CLRUNTIME-PARTICIPANT",
+                "servers": [
+                    "localhost"
+                ],
+                "topicCommInfrastructure": "dmaap"
+            },
+            {
+                "topic": "POLICY-NOTIFICATION",
+                "servers": [
+                    "localhost"
+                ],
+                "topicCommInfrastructure": "dmaap"
+            }
+        ]
+    },
+    "healthCheckRestClientParameters": [
+        {
+            "clientName": "api",
+            "hostname": "policy-api",
+            "port": 6969,
+            "userName": "healthcheck",
+            "password": "zb!XztG34",
+            "useHttps": true,
+            "basePath": "policy/api/v1/healthcheck"
+        },
+        {
+            "clientName": "distribution",
+            "hostname": "policy-distribution",
+            "port": 6969,
+            "userName": "healthcheck",
+            "password": "zb!XztG34",
+            "useHttps": true,
+            "basePath": "healthcheck"
+        }
+    ]
diff --git a/runtime-controlloop/src/test/resources/parameters/logback-test.xml b/runtime-controlloop/src/test/resources/parameters/logback-test.xml
new file mode 100644
index 0000000..e00c36b
--- /dev/null
+++ b/runtime-controlloop/src/test/resources/parameters/logback-test.xml
@@ -0,0 +1,42 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  ============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=========================================================
+-->
+
+<configuration>
+
+    <contextName>Apex</contextName>
+    <statusListener class="ch.qos.logback.core.status.OnConsoleStatusListener" />
+    <property name="LOG_DIR" value="${java.io.tmpdir}/clamp_logging/" />
+
+    <!-- USE FOR STD OUT ONLY -->
+    <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
+        <encoder>
+            <Pattern>%d %contextName [%t] %level %logger{36} - %msg%n</Pattern>
+        </encoder>
+    </appender>
+
+    <root level="info">
+        <appender-ref ref="STDOUT" />
+    </root>
+
+    <logger name="org.onap.policy.clamp.controlloop.runtime" level="trace" additivity="false">
+        <appender-ref ref="STDOUT" />
+    </logger>
+</configuration>
diff --git a/runtime-controlloop/src/test/resources/rest/controlloops/ControlLoopElementsNotFound.json b/runtime-controlloop/src/test/resources/rest/controlloops/ControlLoopElementsNotFound.json
new file mode 100644
index 0000000..faea7cd
--- /dev/null
+++ b/runtime-controlloop/src/test/resources/rest/controlloops/ControlLoopElementsNotFound.json
@@ -0,0 +1,142 @@
+{
+    "controlLoopList": [
+        {
+            "name": "PMSHInstance0",
+            "version": "1.0.1",
+            "definition": {
+                "name": "org.onap.domain.pmsh.PMSHControlLoopDefinition",
+                "version": "1.2.3"
+            },
+            "state": "UNINITIALISED",
+            "orderedState": "UNINITIALISED",
+            "description": "PMSH control loop instance 0",
+            "elements": {
+                "709c62b3-8918-41b9-a747-d21eb79c6c20": {
+                    "id": "709c62b3-8918-41b9-a747-d21eb79c6c20",
+                    "definition": {
+                        "name": "org.onap.domain.pmsh.DCAEMicroservice",
+                        "version": "1.2.3"
+                    },
+                    "participantType": {
+                        "name": "org.onap.dcae.controlloop.DCAEMicroserviceControlLoopParticipant",
+                        "version": "2.3.4"
+                    },
+                    "state": "UNINITIALISED",
+                    "orderedState": "UNINITIALISED",
+                    "description": "DCAE Control Loop Element for the PMSH instance 0 control loop"
+                },
+                "709c62b3-8918-41b9-a747-d21eb79c6c21": {
+                    "id": "709c62b3-8918-41b9-a747-d21eb79c6c21",
+                    "definition": {
+                        "name": "org.onap.domain.pmsh.PMSH_MonitoringPolicyControlLoopElement",
+                        "version": "1.2.3"
+                    },
+                    "participantType": {
+                        "name": "org.onap.policy.controlloop.PolicyControlLoopParticipant",
+                        "version": "2.3.1"
+                    },
+                    "state": "UNINITIALISED",
+                    "orderedState": "UNINITIALISED",
+                    "description": "Monitoring Policy Control Loop Element for the PMSH instance 0 control loop"
+                },
+                "709c62b3-8918-41b9-a747-d21eb79c6c22": {
+                    "id": "709c62b3-8918-41b9-a747-d21eb79c6c22",
+                    "definition": {
+                        "name": "org.onap.domain.pmsh.PMSH_OperationalPolicyControlLoopElement",
+                        "version": "1.2.3"
+                    },
+                    "participantType": {
+                        "name": "org.onap.policy.controlloop.PolicyControlLoopParticipant",
+                        "version": "2.3.1"
+                    },
+                    "state": "UNINITIALISED",
+                    "orderedState": "UNINITIALISED",
+                    "description": "Operational Policy Control Loop Element for the PMSH instance 0 control loop"
+                },
+                "709c62b3-8918-41b9-a747-d21eb79c6c23": {
+                    "id": "709c62b3-8918-41b9-a747-d21eb79c6c23",
+                    "definition": {
+                        "name": "org.onap.domain.pmsh.PMSH_CDS_ControlLoopElement",
+                        "version": "1.2.3"
+                    },
+                    "participantType": {
+                        "name": "org.onap.ccsdk.cds.controlloop.CdsControlLoopParticipant",
+                        "version": "2.2.1"
+                    },
+                    "state": "UNINITIALISED",
+                    "orderedState": "UNINITIALISED",
+                    "description": "CDS Control Loop Element for the PMSH instance 0 control loop"
+                }
+            }
+        },
+        {
+            "name": "PMSHInstance1",
+            "version": "1.0.1",
+            "definition": {
+                "name": "org.onap.domain.pmsh.PMSHControlLoopDefinition",
+                "version": "1.2.3"
+            },
+            "state": "UNINITIALISED",
+            "orderedState": "UNINITIALISED",
+            "description": "PMSH control loop instance 1",
+            "elements": {
+                "709c62b3-8918-41b9-a747-d21eb79c6c24": {
+                    "id": "709c62b3-8918-41b9-a747-e21eb79c6c24",
+                    "definition": {
+                        "name": "org.onap.domain.pmsh.DCAEMicroservice",
+                        "version": "1.2.3"
+                    },
+                    "participantType": {
+                        "name": "org.onap.dcae.controlloop.DCAEMicroserviceControlLoopParticipant",
+                        "version": "2.3.4"
+                    },
+                    "state": "UNINITIALISED",
+                    "orderedState": "UNINITIALISED",
+                    "description": "DCAE Control Loop Element for the PMSH instance 1 control loop"
+                },
+                "709c62b3-8918-41b9-a747-d21eb79c6c25": {
+                    "id": "709c62b3-8918-41b9-a747-e21eb79c6c25",
+                    "definition": {
+                        "name": "org.onap.domain.pmsh.PMSH_MonitoringPolicyControlLoopElement",
+                        "version": "1.2.3"
+                    },
+                    "participantType": {
+                        "name": "org.onap.policy.controlloop.PolicyControlLoopParticipant",
+                        "version": "2.3.1"
+                    },
+                    "state": "UNINITIALISED",
+                    "orderedState": "UNINITIALISED",
+                    "description": "Monitoring Policy Control Loop Element for the PMSH instance 1 control loop"
+                },
+                "709c62b3-8918-41b9-a747-d21eb79c6c26": {
+                    "id": "709c62b3-8918-41b9-a747-e21eb79c6c26",
+                    "definition": {
+                        "name": "org.onap.domain.pmsh.PMSH_OperationalPolicyControlLoopElement",
+                        "version": "1.2.3"
+                    },
+                    "participantType": {
+                        "name": "org.onap.policy.controlloop.PolicyControlLoopParticipant",
+                        "version": "2.3.1"
+                    },
+                    "state": "UNINITIALISED",
+                    "orderedState": "UNINITIALISED",
+                    "description": "Operational Policy Control Loop Element for the PMSH instance 1 control loop"
+                },
+                "709c62b3-8918-41b9-a747-d21eb79c6c27": {
+                    "id": "709c62b3-8918-41b9-a747-e21eb79c6c27",
+                    "definition": {
+                        "name": "org.onap.domain.pmsh.PMSH_CDS_ControlLoopElement",
+                        "version": "1.2.3"
+                    },
+                    "participantType": {
+                        "name": "org.onap.ccsdk.cds.controlloop.CdsControlLoopParticipant",
+                        "version": "2.2.1"
+                    },
+                    "state": "UNINITIALISED",
+                    "orderedState": "UNINITIALISED",
+                    "description": "CDS Control Loop Element for the PMSH instance 1 control loop"
+                }
+            }
+        }
+    ]
+}
diff --git a/runtime-controlloop/src/test/resources/rest/controlloops/ControlLoops.json b/runtime-controlloop/src/test/resources/rest/controlloops/ControlLoops.json
new file mode 100644
index 0000000..13ea1bf
--- /dev/null
+++ b/runtime-controlloop/src/test/resources/rest/controlloops/ControlLoops.json
@@ -0,0 +1,142 @@
+{
+    "controlLoopList": [
+        {
+            "name": "PMSHInstance0",
+            "version": "1.0.1",
+            "definition": {
+                "name": "org.onap.domain.pmsh.PMSHControlLoopDefinition",
+                "version": "1.2.3"
+            },
+            "state": "UNINITIALISED",
+            "orderedState": "UNINITIALISED",
+            "description": "PMSH control loop instance 0",
+            "elements": {
+                "709c62b3-8918-41b9-a747-d21eb79c6c20": {
+                    "id": "709c62b3-8918-41b9-a747-d21eb79c6c20",
+                    "definition": {
+                        "name": "org.onap.domain.pmsh.PMSH_DCAEMicroservice",
+                        "version": "1.2.3"
+                    },
+                    "participantType": {
+                        "name": "org.onap.dcae.controlloop.DCAEMicroserviceControlLoopParticipant",
+                        "version": "2.3.4"
+                    },
+                    "state": "UNINITIALISED",
+                    "orderedState": "UNINITIALISED",
+                    "description": "DCAE Control Loop Element for the PMSH instance 0 control loop"
+                },
+                "709c62b3-8918-41b9-a747-d21eb79c6c21": {
+                    "id": "709c62b3-8918-41b9-a747-d21eb79c6c21",
+                    "definition": {
+                        "name": "org.onap.domain.pmsh.PMSH_MonitoringPolicyControlLoopElement",
+                        "version": "1.2.3"
+                    },
+                    "participantType": {
+                        "name": "org.onap.policy.controlloop.PolicyControlLoopParticipant",
+                        "version": "2.3.1"
+                    },
+                    "state": "UNINITIALISED",
+                    "orderedState": "UNINITIALISED",
+                    "description": "Monitoring Policy Control Loop Element for the PMSH instance 0 control loop"
+                },
+                "709c62b3-8918-41b9-a747-d21eb79c6c22": {
+                    "id": "709c62b3-8918-41b9-a747-d21eb79c6c22",
+                    "definition": {
+                        "name": "org.onap.domain.pmsh.PMSH_OperationalPolicyControlLoopElement",
+                        "version": "1.2.3"
+                    },
+                    "participantType": {
+                        "name": "org.onap.policy.controlloop.PolicyControlLoopParticipant",
+                        "version": "2.3.1"
+                    },
+                    "state": "UNINITIALISED",
+                    "orderedState": "UNINITIALISED",
+                    "description": "Operational Policy Control Loop Element for the PMSH instance 0 control loop"
+                },
+                "709c62b3-8918-41b9-a747-d21eb79c6c23": {
+                    "id": "709c62b3-8918-41b9-a747-d21eb79c6c23",
+                    "definition": {
+                        "name": "org.onap.domain.pmsh.PMSH_CDS_ControlLoopElement",
+                        "version": "1.2.3"
+                    },
+                    "participantType": {
+                        "name": "org.onap.ccsdk.cds.controlloop.CdsControlLoopParticipant",
+                        "version": "2.2.1"
+                    },
+                    "state": "UNINITIALISED",
+                    "orderedState": "UNINITIALISED",
+                    "description": "CDS Control Loop Element for the PMSH instance 0 control loop"
+                }
+            }
+        },
+        {
+            "name": "PMSHInstance1",
+            "version": "1.0.1",
+            "definition": {
+                "name": "org.onap.domain.pmsh.PMSHControlLoopDefinition",
+                "version": "1.2.3"
+            },
+            "state": "UNINITIALISED",
+            "orderedState": "UNINITIALISED",
+            "description": "PMSH control loop instance 1",
+            "elements": {
+                "709c62b3-8918-41b9-a747-d21eb79c6c24": {
+                    "id": "709c62b3-8918-41b9-a747-e21eb79c6c24",
+                    "definition": {
+                        "name": "org.onap.domain.pmsh.PMSH_DCAEMicroservice",
+                        "version": "1.2.3"
+                    },
+                    "participantType": {
+                        "name": "org.onap.dcae.controlloop.DCAEMicroserviceControlLoopParticipant",
+                        "version": "2.3.4"
+                    },
+                    "state": "UNINITIALISED",
+                    "orderedState": "UNINITIALISED",
+                    "description": "DCAE Control Loop Element for the PMSH instance 1 control loop"
+                },
+                "709c62b3-8918-41b9-a747-d21eb79c6c25": {
+                    "id": "709c62b3-8918-41b9-a747-e21eb79c6c25",
+                    "definition": {
+                        "name": "org.onap.domain.pmsh.PMSH_MonitoringPolicyControlLoopElement",
+                        "version": "1.2.3"
+                    },
+                    "participantType": {
+                        "name": "org.onap.policy.controlloop.PolicyControlLoopParticipant",
+                        "version": "2.3.1"
+                    },
+                    "state": "UNINITIALISED",
+                    "orderedState": "UNINITIALISED",
+                    "description": "Monitoring Policy Control Loop Element for the PMSH instance 1 control loop"
+                },
+                "709c62b3-8918-41b9-a747-d21eb79c6c26": {
+                    "id": "709c62b3-8918-41b9-a747-e21eb79c6c26",
+                    "definition": {
+                        "name": "org.onap.domain.pmsh.PMSH_OperationalPolicyControlLoopElement",
+                        "version": "1.2.3"
+                    },
+                    "participantType": {
+                        "name": "org.onap.policy.controlloop.PolicyControlLoopParticipant",
+                        "version": "2.3.1"
+                    },
+                    "state": "UNINITIALISED",
+                    "orderedState": "UNINITIALISED",
+                    "description": "Operational Policy Control Loop Element for the PMSH instance 1 control loop"
+                },
+                "709c62b3-8918-41b9-a747-d21eb79c6c27": {
+                    "id": "709c62b3-8918-41b9-a747-e21eb79c6c27",
+                    "definition": {
+                        "name": "org.onap.domain.pmsh.PMSH_CDS_ControlLoopElement",
+                        "version": "1.2.3"
+                    },
+                    "participantType": {
+                        "name": "org.onap.ccsdk.cds.controlloop.CdsControlLoopParticipant",
+                        "version": "2.2.1"
+                    },
+                    "state": "UNINITIALISED",
+                    "orderedState": "UNINITIALISED",
+                    "description": "CDS Control Loop Element for the PMSH instance 1 control loop"
+                }
+            }
+        }
+    ]
+}
diff --git a/runtime-controlloop/src/test/resources/rest/controlloops/ControlLoopsNotFound.json b/runtime-controlloop/src/test/resources/rest/controlloops/ControlLoopsNotFound.json
new file mode 100644
index 0000000..9e97674
--- /dev/null
+++ b/runtime-controlloop/src/test/resources/rest/controlloops/ControlLoopsNotFound.json
@@ -0,0 +1,142 @@
+{
+    "controlLoopList": [
+        {
+            "name": "PMSHInstance0",
+            "version": "1.0.1",
+            "definition": {
+                "name": "org.onap.domain.PMSHControlLoopDefinition",
+                "version": "1.2.3"
+            },
+            "state": "UNINITIALISED",
+            "orderedState": "UNINITIALISED",
+            "description": "PMSH control loop instance 0",
+            "elements": {
+                "709c62b3-8918-41b9-a747-d21eb79c6c20": {
+                    "id": "709c62b3-8918-41b9-a747-d21eb79c6c20",
+                    "definition": {
+                        "name": "org.onap.domain.pmsh.PMSH_DCAEMicroservice",
+                        "version": "1.2.3"
+                    },
+                    "participantType": {
+                        "name": "org.onap.dcae.controlloop.DCAEMicroserviceControlLoopParticipant",
+                        "version": "2.3.4"
+                    },
+                    "state": "UNINITIALISED",
+                    "orderedState": "UNINITIALISED",
+                    "description": "DCAE Control Loop Element for the PMSH instance 0 control loop"
+                },
+                "709c62b3-8918-41b9-a747-d21eb79c6c21": {
+                    "id": "709c62b3-8918-41b9-a747-d21eb79c6c21",
+                    "definition": {
+                        "name": "org.onap.domain.pmsh.PMSH_MonitoringPolicyControlLoopElement",
+                        "version": "1.2.3"
+                    },
+                    "participantType": {
+                        "name": "org.onap.policy.controlloop.PolicyControlLoopParticipant",
+                        "version": "2.3.1"
+                    },
+                    "state": "UNINITIALISED",
+                    "orderedState": "UNINITIALISED",
+                    "description": "Monitoring Policy Control Loop Element for the PMSH instance 0 control loop"
+                },
+                "709c62b3-8918-41b9-a747-d21eb79c6c22": {
+                    "id": "709c62b3-8918-41b9-a747-d21eb79c6c22",
+                    "definition": {
+                        "name": "org.onap.domain.pmsh.PMSH_OperationalPolicyControlLoopElement",
+                        "version": "1.2.3"
+                    },
+                    "participantType": {
+                        "name": "org.onap.policy.controlloop.PolicyControlLoopParticipant",
+                        "version": "2.3.1"
+                    },
+                    "state": "UNINITIALISED",
+                    "orderedState": "UNINITIALISED",
+                    "description": "Operational Policy Control Loop Element for the PMSH instance 0 control loop"
+                },
+                "709c62b3-8918-41b9-a747-d21eb79c6c23": {
+                    "id": "709c62b3-8918-41b9-a747-d21eb79c6c23",
+                    "definition": {
+                        "name": "org.onap.domain.pmsh.PMSH_CDS_ControlLoopElement",
+                        "version": "1.2.3"
+                    },
+                    "participantType": {
+                        "name": "org.onap.ccsdk.cds.controlloop.CdsControlLoopParticipant",
+                        "version": "2.2.1"
+                    },
+                    "state": "UNINITIALISED",
+                    "orderedState": "UNINITIALISED",
+                    "description": "CDS Control Loop Element for the PMSH instance 0 control loop"
+                }
+            }
+        },
+        {
+            "name": "PMSHInstance1",
+            "version": "1.0.1",
+            "definition": {
+                "name": "org.onap.domain.PMSHControlLoopDefinition",
+                "version": "1.2.3"
+            },
+            "state": "UNINITIALISED",
+            "orderedState": "UNINITIALISED",
+            "description": "PMSH control loop instance 1",
+            "elements": {
+                "709c62b3-8918-41b9-a747-d21eb79c6c24": {
+                    "id": "709c62b3-8918-41b9-a747-e21eb79c6c24",
+                    "definition": {
+                        "name": "org.onap.domain.pmsh.PMSH_DCAEMicroservice",
+                        "version": "1.2.3"
+                    },
+                    "participantType": {
+                        "name": "org.onap.dcae.controlloop.DCAEMicroserviceControlLoopParticipant",
+                        "version": "2.3.4"
+                    },
+                    "state": "UNINITIALISED",
+                    "orderedState": "UNINITIALISED",
+                    "description": "DCAE Control Loop Element for the PMSH instance 1 control loop"
+                },
+                "709c62b3-8918-41b9-a747-d21eb79c6c25": {
+                    "id": "709c62b3-8918-41b9-a747-e21eb79c6c25",
+                    "definition": {
+                        "name": "org.onap.domain.pmsh.PMSH_MonitoringPolicyControlLoopElement",
+                        "version": "1.2.3"
+                    },
+                    "participantType": {
+                        "name": "org.onap.policy.controlloop.PolicyControlLoopParticipant",
+                        "version": "2.3.1"
+                    },
+                    "state": "UNINITIALISED",
+                    "orderedState": "UNINITIALISED",
+                    "description": "Monitoring Policy Control Loop Element for the PMSH instance 1 control loop"
+                },
+                "709c62b3-8918-41b9-a747-d21eb79c6c26": {
+                    "id": "709c62b3-8918-41b9-a747-e21eb79c6c26",
+                    "definition": {
+                        "name": "org.onap.domain.pmsh.PMSH_OperationalPolicyControlLoopElement",
+                        "version": "1.2.3"
+                    },
+                    "participantType": {
+                        "name": "org.onap.policy.controlloop.PolicyControlLoopParticipant",
+                        "version": "2.3.1"
+                    },
+                    "state": "UNINITIALISED",
+                    "orderedState": "UNINITIALISED",
+                    "description": "Operational Policy Control Loop Element for the PMSH instance 1 control loop"
+                },
+                "709c62b3-8918-41b9-a747-d21eb79c6c27": {
+                    "id": "709c62b3-8918-41b9-a747-e21eb79c6c27",
+                    "definition": {
+                        "name": "org.onap.domain.pmsh.PMSH_CDS_ControlLoopElement",
+                        "version": "1.2.3"
+                    },
+                    "participantType": {
+                        "name": "org.onap.ccsdk.cds.controlloop.CdsControlLoopParticipant",
+                        "version": "2.2.1"
+                    },
+                    "state": "UNINITIALISED",
+                    "orderedState": "UNINITIALISED",
+                    "description": "CDS Control Loop Element for the PMSH instance 1 control loop"
+                }
+            }
+        }
+    ]
+}
diff --git a/runtime-controlloop/src/test/resources/rest/controlloops/ControlLoopsUpdate.json b/runtime-controlloop/src/test/resources/rest/controlloops/ControlLoopsUpdate.json
new file mode 100644
index 0000000..025e2a1
--- /dev/null
+++ b/runtime-controlloop/src/test/resources/rest/controlloops/ControlLoopsUpdate.json
@@ -0,0 +1,142 @@
+{
+    "controlLoopList": [
+        {
+            "name": "PMSHInstance0",
+            "version": "1.0.1",
+            "definition": {
+                "name": "org.onap.domain.pmsh.PMSHControlLoopDefinition",
+                "version": "1.2.3"
+            },
+            "state": "UNINITIALISED",
+            "orderedState": "UNINITIALISED",
+            "description": "PMSH control loop instance 1",
+            "elements": {
+                "709c62b3-8918-41b9-a747-d21eb79c6c21": {
+                    "id": "709c62b3-8918-41b9-a747-d21eb79c6c21",
+                    "definition": {
+                        "name": "org.onap.domain.pmsh.PMSH_DCAEMicroservice",
+                        "version": "1.2.3"
+                    },
+                    "participantType": {
+                        "name": "org.onap.dcae.controlloop.DCAEMicroserviceControlLoopParticipant",
+                        "version": "2.3.4"
+                    },
+                    "state": "UNINITIALISED",
+                    "orderedState": "UNINITIALISED",
+                    "description": "DCAE Control Loop Element for the PMSH instance 0 control loop"
+                },
+                "709c62b3-8918-41b9-a747-d21eb79c6c22": {
+                    "id": "709c62b3-8918-41b9-a747-d21eb79c6c22",
+                    "definition": {
+                        "name": "org.onap.domain.pmsh.PMSH_MonitoringPolicyControlLoopElement",
+                        "version": "1.2.3"
+                    },
+                    "participantType": {
+                        "name": "org.onap.policy.controlloop.PolicyControlLoopParticipant",
+                        "version": "2.3.1"
+                    },
+                    "state": "UNINITIALISED",
+                    "orderedState": "UNINITIALISED",
+                    "description": "Monitoring Policy Control Loop Element for the PMSH instance 0 control loop"
+                },
+                "709c62b3-8918-41b9-a747-d21eb79c6c23": {
+                    "id": "709c62b3-8918-41b9-a747-d21eb79c6c23",
+                    "definition": {
+                        "name": "org.onap.domain.pmsh.PMSH_MonitoringPolicyControlLoopElement",
+                        "version": "1.2.3"
+                    },
+                    "participantType": {
+                        "name": "org.onap.policy.controlloop.PolicyControlLoopParticipant",
+                        "version": "2.3.1"
+                    },
+                    "state": "UNINITIALISED",
+                    "orderedState": "UNINITIALISED",
+                    "description": "Operational Policy Control Loop Element for the PMSH instance 0 control loop"
+                },
+                "709c62b3-8918-41b9-a747-d21eb79c6c24": {
+                    "id": "709c62b3-8918-41b9-a747-d21eb79c6c24",
+                    "definition": {
+                        "name": "org.onap.domain.pmsh.PMSH_CDS_ControlLoopElement",
+                        "version": "1.2.3"
+                    },
+                    "participantType": {
+                        "name": "org.onap.ccsdk.cds.controlloop.CdsControlLoopParticipant",
+                        "version": "2.2.1"
+                    },
+                    "state": "UNINITIALISED",
+                    "orderedState": "UNINITIALISED",
+                    "description": "CDS Control Loop Element for the PMSH instance 0 control loop"
+                }
+            }
+        },
+        {
+            "name": "PMSHInstance1",
+            "version": "1.0.1",
+            "definition": {
+                "name": "org.onap.domain.pmsh.PMSHControlLoopDefinition",
+                "version": "1.2.3"
+            },
+            "state": "UNINITIALISED",
+            "orderedState": "UNINITIALISED",
+            "description": "PMSH control loop instance 1",
+            "elements": {
+                "709c62b3-8918-41b9-a747-d21eb79c6c25": {
+                    "id": "709c62b3-8918-41b9-a747-e21eb79c6c25",
+                    "definition": {
+                        "name": "org.onap.domain.pmsh.PMSH_DCAEMicroservice",
+                        "version": "1.2.3"
+                    },
+                    "participantType": {
+                        "name": "org.onap.dcae.controlloop.DCAEMicroserviceControlLoopParticipant",
+                        "version": "2.3.4"
+                    },
+                    "state": "UNINITIALISED",
+                    "orderedState": "UNINITIALISED",
+                    "description": "DCAE Control Loop Element for the PMSH instance 1 control loop"
+                },
+                "709c62b3-8918-41b9-a747-d21eb79c6c26": {
+                    "id": "709c62b3-8918-41b9-a747-e21eb79c6c26",
+                    "definition": {
+                        "name": "org.onap.domain.pmsh.PMSH_MonitoringPolicyControlLoopElement",
+                        "version": "1.2.3"
+                    },
+                    "participantType": {
+                        "name": "org.onap.policy.controlloop.PolicyControlLoopParticipant",
+                        "version": "2.3.1"
+                    },
+                    "state": "UNINITIALISED",
+                    "orderedState": "UNINITIALISED",
+                    "description": "Monitoring Policy Control Loop Element for the PMSH instance 1 control loop"
+                },
+                "709c62b3-8918-41b9-a747-d21eb79c6c27": {
+                    "id": "709c62b3-8918-41b9-a747-e21eb79c6c27",
+                    "definition": {
+                        "name": "org.onap.domain.pmsh.PMSH_MonitoringPolicyControlLoopElement",
+                        "version": "1.2.3"
+                    },
+                    "participantType": {
+                        "name": "org.onap.policy.controlloop.PolicyControlLoopParticipant",
+                        "version": "2.3.1"
+                    },
+                    "state": "UNINITIALISED",
+                    "orderedState": "UNINITIALISED",
+                    "description": "Operational Policy Control Loop Element for the PMSH instance 1 control loop"
+                },
+                "709c62b3-8918-41b9-a747-d21eb79c6c28": {
+                    "id": "709c62b3-8918-41b9-a747-e21eb79c6c28",
+                    "definition": {
+                        "name": "org.onap.domain.pmsh.PMSH_CDS_ControlLoopElement",
+                        "version": "1.2.3"
+                    },
+                    "participantType": {
+                        "name": "org.onap.ccsdk.cds.controlloop.CdsControlLoopParticipant",
+                        "version": "2.2.1"
+                    },
+                    "state": "UNINITIALISED",
+                    "orderedState": "UNINITIALISED",
+                    "description": "CDS Control Loop Element for the PMSH instance 1 control loop"
+                }
+            }
+        }
+    ]
+}
diff --git a/runtime-controlloop/src/test/resources/rest/controlloops/ControlLoopsVersionNotMatches.json b/runtime-controlloop/src/test/resources/rest/controlloops/ControlLoopsVersionNotMatches.json
new file mode 100644
index 0000000..76131af
--- /dev/null
+++ b/runtime-controlloop/src/test/resources/rest/controlloops/ControlLoopsVersionNotMatches.json
@@ -0,0 +1,142 @@
+{
+    "controlLoopList": [
+        {
+            "name": "PMSHInstance0",
+            "version": "1.0.1",
+            "definition": {
+                "name": "org.onap.domain.pmsh.PMSHControlLoopDefinition",
+                "version": "1.2.3"
+            },
+            "state": "UNINITIALISED",
+            "orderedState": "UNINITIALISED",
+            "description": "PMSH control loop instance 0",
+            "elements": {
+                "709c62b3-8918-41b9-a747-d21eb79c6c20": {
+                    "id": "709c62b3-8918-41b9-a747-d21eb79c6c20",
+                    "definition": {
+                        "name": "org.onap.domain.pmsh.PMSH_DCAEMicroservice",
+                        "version": "1.0.0"
+                    },
+                    "participantType": {
+                        "name": "org.onap.dcae.controlloop.DCAEMicroserviceControlLoopParticipant",
+                        "version": "2.3.4"
+                    },
+                    "state": "UNINITIALISED",
+                    "orderedState": "UNINITIALISED",
+                    "description": "DCAE Control Loop Element for the PMSH instance 0 control loop"
+                },
+                "709c62b3-8918-41b9-a747-d21eb79c6c21": {
+                    "id": "709c62b3-8918-41b9-a747-d21eb79c6c21",
+                    "definition": {
+                        "name": "org.onap.domain.pmsh.PMSH_MonitoringPolicyControlLoopElement",
+                        "version": "1.2.3"
+                    },
+                    "participantType": {
+                        "name": "org.onap.policy.controlloop.PolicyControlLoopParticipant",
+                        "version": "2.3.1"
+                    },
+                    "state": "UNINITIALISED",
+                    "orderedState": "UNINITIALISED",
+                    "description": "Monitoring Policy Control Loop Element for the PMSH instance 0 control loop"
+                },
+                "709c62b3-8918-41b9-a747-d21eb79c6c22": {
+                    "id": "709c62b3-8918-41b9-a747-d21eb79c6c22",
+                    "definition": {
+                        "name": "org.onap.domain.pmsh.PMSH_OperationalPolicyControlLoopElement",
+                        "version": "1.2.3"
+                    },
+                    "participantType": {
+                        "name": "org.onap.policy.controlloop.PolicyControlLoopParticipant",
+                        "version": "2.3.1"
+                    },
+                    "state": "UNINITIALISED",
+                    "orderedState": "UNINITIALISED",
+                    "description": "Operational Policy Control Loop Element for the PMSH instance 0 control loop"
+                },
+                "709c62b3-8918-41b9-a747-d21eb79c6c23": {
+                    "id": "709c62b3-8918-41b9-a747-d21eb79c6c23",
+                    "definition": {
+                        "name": "org.onap.domain.pmsh.PMSH_CDS_ControlLoopElement",
+                        "version": "1.2.3"
+                    },
+                    "participantType": {
+                        "name": "org.onap.ccsdk.cds.controlloop.CdsControlLoopParticipant",
+                        "version": "2.2.1"
+                    },
+                    "state": "UNINITIALISED",
+                    "orderedState": "UNINITIALISED",
+                    "description": "CDS Control Loop Element for the PMSH instance 0 control loop"
+                }
+            }
+        },
+        {
+            "name": "PMSHInstance1",
+            "version": "1.0.1",
+            "definition": {
+                "name": "org.onap.domain.pmsh.PMSHControlLoopDefinition",
+                "version": "1.2.3"
+            },
+            "state": "UNINITIALISED",
+            "orderedState": "UNINITIALISED",
+            "description": "PMSH control loop instance 1",
+            "elements": {
+                "709c62b3-8918-41b9-a747-d21eb79c6c24": {
+                    "id": "709c62b3-8918-41b9-a747-e21eb79c6c24",
+                    "definition": {
+                        "name": "org.onap.domain.pmsh.PMSH_DCAEMicroservice",
+                        "version": "1.0.0"
+                    },
+                    "participantType": {
+                        "name": "org.onap.dcae.controlloop.DCAEMicroserviceControlLoopParticipant",
+                        "version": "2.3.4"
+                    },
+                    "state": "UNINITIALISED",
+                    "orderedState": "UNINITIALISED",
+                    "description": "DCAE Control Loop Element for the PMSH instance 1 control loop"
+                },
+                "709c62b3-8918-41b9-a747-d21eb79c6c25": {
+                    "id": "709c62b3-8918-41b9-a747-e21eb79c6c25",
+                    "definition": {
+                        "name": "org.onap.domain.pmsh.PMSH_MonitoringPolicyControlLoopElement",
+                        "version": "1.2.3"
+                    },
+                    "participantType": {
+                        "name": "org.onap.policy.controlloop.PolicyControlLoopParticipant",
+                        "version": "2.3.1"
+                    },
+                    "state": "UNINITIALISED",
+                    "orderedState": "UNINITIALISED",
+                    "description": "Monitoring Policy Control Loop Element for the PMSH instance 1 control loop"
+                },
+                "709c62b3-8918-41b9-a747-d21eb79c6c26": {
+                    "id": "709c62b3-8918-41b9-a747-e21eb79c6c26",
+                    "definition": {
+                        "name": "org.onap.domain.pmsh.PMSH_OperationalPolicyControlLoopElement",
+                        "version": "1.2.3"
+                    },
+                    "participantType": {
+                        "name": "org.onap.policy.controlloop.PolicyControlLoopParticipant",
+                        "version": "2.3.1"
+                    },
+                    "state": "UNINITIALISED",
+                    "orderedState": "UNINITIALISED",
+                    "description": "Operational Policy Control Loop Element for the PMSH instance 1 control loop"
+                },
+                "709c62b3-8918-41b9-a747-d21eb79c6c27": {
+                    "id": "709c62b3-8918-41b9-a747-e21eb79c6c27",
+                    "definition": {
+                        "name": "org.onap.domain.pmsh.PMSH_CDS_ControlLoopElement",
+                        "version": "1.2.3"
+                    },
+                    "participantType": {
+                        "name": "org.onap.ccsdk.cds.controlloop.CdsControlLoopParticipant",
+                        "version": "2.2.1"
+                    },
+                    "state": "UNINITIALISED",
+                    "orderedState": "UNINITIALISED",
+                    "description": "CDS Control Loop Element for the PMSH instance 1 control loop"
+                }
+            }
+        }
+    ]
+}
diff --git a/runtime-controlloop/src/test/resources/rest/controlloops/PassiveCommand.json b/runtime-controlloop/src/test/resources/rest/controlloops/PassiveCommand.json
new file mode 100644
index 0000000..9c87e43
--- /dev/null
+++ b/runtime-controlloop/src/test/resources/rest/controlloops/PassiveCommand.json
@@ -0,0 +1,13 @@
+{
+    "orderedState": "PASSIVE",
+    "controlLoopIdentifierList": [
+        {
+            "name": "PMSHInstance0",
+            "version": "1.0.1"
+        },
+        {
+            "name": "PMSHInstance1",
+            "version": "1.0.1"
+        }
+    ]
+}
diff --git a/runtime-controlloop/src/test/resources/rest/monitoring/TestClElementStatistics.json b/runtime-controlloop/src/test/resources/rest/monitoring/TestClElementStatistics.json
new file mode 100644
index 0000000..21a048f
--- /dev/null
+++ b/runtime-controlloop/src/test/resources/rest/monitoring/TestClElementStatistics.json
@@ -0,0 +1,44 @@
+{
+  "clElementStatistics":[
+    {
+      "participantId":{
+        "name":"name1",
+        "version":"1.001"
+      },
+      "id": "709c62b3-8918-41b9-a747-d21eb79c6c20",
+      "timeStamp": "2021-01-10T13:45:00.000Z",
+      "controlLoopState": "UNINITIALISED",
+      "clElementUptime":250
+    },
+    {
+      "participantId":{
+        "name":"name1",
+        "version":"1.001"
+      },
+      "id": "709c62b3-8918-41b9-a747-d21eb79c6c20",
+      "timeStamp": "2021-01-10T15:45:00.000Z",
+      "controlLoopState": "UNINITIALISED",
+      "clElementUptime":450
+    },
+    {
+      "participantId":{
+        "name":"name2",
+        "version":"1.001"
+      },
+      "id": "709c62b3-8918-41b9-a747-d21eb79c6c21",
+      "timeStamp": "2021-01-10T14:25:00.000Z",
+      "controlLoopState": "UNINITIALISED",
+      "clElementUptime":330
+    },
+    {
+      "participantId":{
+        "name":"name2",
+        "version":"1.001"
+      },
+      "id": "709c62b3-8918-41b9-a747-d21eb79c6c21",
+      "timeStamp": "2021-01-10T16:35:00.000Z",
+      "controlLoopState": "UNINITIALISED",
+      "clElementUptime":650
+    }
+  ]
+}
\ No newline at end of file
diff --git a/runtime-controlloop/src/test/resources/rest/monitoring/TestClElementStatistics_Invalid.json b/runtime-controlloop/src/test/resources/rest/monitoring/TestClElementStatistics_Invalid.json
new file mode 100644
index 0000000..2cf2619
--- /dev/null
+++ b/runtime-controlloop/src/test/resources/rest/monitoring/TestClElementStatistics_Invalid.json
@@ -0,0 +1,13 @@
+{
+  "clElementStatisticsList":[
+    {
+      "participantId":{
+        "name":"name1",
+        "version":"1.001"
+      },
+      "id": "709c62b3-8918-41b9-a747-d21eb79c6c20",
+      "controlLoopState": "UNINITIALISED",
+      "clElementUptime":250
+    }
+  ]
+}
\ No newline at end of file
diff --git a/runtime-controlloop/src/test/resources/rest/monitoring/TestParticipantStatistics.json b/runtime-controlloop/src/test/resources/rest/monitoring/TestParticipantStatistics.json
new file mode 100644
index 0000000..acd88e2
--- /dev/null
+++ b/runtime-controlloop/src/test/resources/rest/monitoring/TestParticipantStatistics.json
@@ -0,0 +1,46 @@
+{
+  "statisticsList":[
+    {
+      "participantId":{
+        "name":"name1",
+        "version":"1.001"
+      },
+      "timeStamp": "2021-01-10T13:45:00.000Z",
+      "state": "PASSIVE",
+      "healthStatus": "HEALTHY",
+      "eventCount":250,
+      "lastExecutionTime":100,
+      "averageExecutionTime":90,
+      "upTime":1000,
+      "lastStart":3000
+    },
+    {
+      "participantId":{
+        "name":"name1",
+        "version":"1.001"
+      },
+      "timeStamp": "2021-01-10T15:45:00.000Z",
+      "state": "PASSIVE",
+      "healthStatus": "HEALTHY",
+      "eventCount":262,
+      "lastExecutionTime":100,
+      "averageExecutionTime":90,
+      "upTime":2000,
+      "lastStart":3000
+    },
+    {
+      "participantId":{
+        "name":"name2",
+        "version":"1.001"
+      },
+      "timeStamp": "2021-01-27T14:25:00.000Z",
+      "state": "PASSIVE",
+      "healthStatus": "HEALTHY",
+      "eventCount":245,
+      "lastExecutionTime":1020,
+      "averageExecutionTime":85,
+      "upTime":1050,
+      "lastStart":3100
+    }
+  ]
+}
\ No newline at end of file
diff --git a/runtime-controlloop/src/test/resources/rest/monitoring/TestParticipantStatistics_Invalid.json b/runtime-controlloop/src/test/resources/rest/monitoring/TestParticipantStatistics_Invalid.json
new file mode 100644
index 0000000..7281822
--- /dev/null
+++ b/runtime-controlloop/src/test/resources/rest/monitoring/TestParticipantStatistics_Invalid.json
@@ -0,0 +1,16 @@
+{
+  "participantStatisticsList":[
+    {
+      "participantId":{
+        "name":"name3",
+        "version":"1.001"
+      },
+      "state": "PASSIVE",
+      "eventCount":250,
+      "lastExecutionTime":100,
+      "averageExecutionTime":90,
+      "upTime":1000,
+      "lastStart":3000
+    }
+  ]
+}
\ No newline at end of file
diff --git a/runtime-controlloop/src/test/resources/rest/servicetemplates/PMSHMultipleCLTosca.yaml b/runtime-controlloop/src/test/resources/rest/servicetemplates/PMSHMultipleCLTosca.yaml
new file mode 100644
index 0000000..099e2e9
--- /dev/null
+++ b/runtime-controlloop/src/test/resources/rest/servicetemplates/PMSHMultipleCLTosca.yaml
@@ -0,0 +1,221 @@
+tosca_definitions_version: tosca_simple_yaml_1_3
+data_types:
+  onap.datatypes.ToscaConceptIdentifier:
+    derived_from: tosca.datatypes.Root
+    properties:
+      name:
+        type: string
+        required: true
+      version:
+        type: string
+        required: true
+node_types:
+  org.onap.policy.clamp.controlloop.Participant:
+    version: 1.0.1
+    derived_from: tosca.nodetypes.Root
+    properties:
+      provider:
+        type: string
+        requred: false
+  org.onap.policy.clamp.controlloop.ControlLoopElement:
+    version: 1.0.1
+    derived_from: tosca.nodetypes.Root
+    properties:
+      provider:
+        type: string
+        requred: false
+      participant_id:
+        type: onap.datatypes.ToscaConceptIdentifier
+        requred: true
+  org.onap.policy.clamp.controlloop.ControlLoop:
+    version: 1.0.1
+    derived_from: tosca.nodetypes.Root
+    properties:
+      provider:
+        type: string
+        requred: false
+      elements:
+        type: list
+        required: true
+        entry_schema:
+          type: onap.datatypes.ToscaConceptIdentifier
+  org.onap.policy.clamp.controlloop.DCAEMicroserviceControlLoopElement:
+    version: 1.0.1
+    derived_from: org.onap.policy.clamp.controlloop.ControlLoopElement
+    properties:
+      dcae_blueprint_id:
+        type: onap.datatypes.ToscaConceptIdentifier
+        requred: true
+  org.onap.policy.clamp.controlloop.PolicyTypeControlLoopElement:
+    version: 1.0.1
+    derived_from: org.onap.policy.clamp.controlloop.ControlLoopElement
+    properties:
+      policy_type_id:
+        type: onap.datatypes.ToscaConceptIdentifier
+        requred: true
+  org.onap.policy.clamp.controlloop.CDSControlLoopElement:
+    version: 1.0.1
+    derived_from: org.onap.policy.clamp.controlloop.ControlLoopElement
+    properties:
+      cds_blueprint_id:
+        type: onap.datatypes.ToscaConceptIdentifier
+        requred: true
+topology_template:
+  node_templates:
+    org.onap.dcae.controlloop.DCAEMicroserviceControlLoopParticipant:
+      version: 2.3.4
+      type: org.onap.policy.clamp.controlloop.Participant
+      type_version: 1.0.1
+      description: Participant for DCAE microservices
+      properties:
+        provider: ONAP
+    org.onap.policy.controlloop.PolicyControlLoopParticipant:
+      version: 2.2.1
+      type: org.onap.policy.clamp.controlloop.Participant
+      type_version: 1.0.1
+      description: Participant for DCAE microservices
+      properties:
+        provider: ONAP
+    org.onap.ccsdk.cds.controlloop.CdsControlLoopParticipant:
+      version: 2.2.1
+      type: org.onap.policy.clamp.controlloop.Participant
+      type_version: 1.0.1
+      description: Participant for DCAE microservices
+      properties:
+        provider: ONAP
+    org.onap.domain.pmsh.PMSH_DCAEMicroservice:
+      version: 1.2.3
+      type: org.onap.policy.clamp.controlloop.DCAEMicroserviceControlLoopElement
+      type_version: 1.0.0
+      description: Control loop element for the DCAE microservice for Performance Management Subscription Handling
+      properties:
+        provider: Ericsson
+        participant_id:
+          name: org.onap.dcae.controlloop.DCAEMicroserviceControlLoopParticipant
+          version: 2.3.4
+        dcae_blueprint_id:
+          name: org.onap.dcae.blueprints.PMSHBlueprint
+          version: 1.0.0
+    org.onap.domain.pmsh.PMSH_MonitoringPolicyControlLoopElement:
+      version: 1.2.3
+      type: org.onap.policy.clamp.controlloop.PolicyTypeControlLoopElement
+      type_version: 1.0.0
+      description: Control loop element for the monitoring policy for Performance Management Subscription Handling
+      properties:
+        provider: Ericsson
+        participant_id:
+          name: org.onap.policy.controlloop.PolicyControlLoopParticipant
+          version: 2.2.1
+        policy_type_id:
+          name: onap.policies.monitoring.pm-subscription-handler
+          version: 1.0.0
+    org.onap.domain.pmsh.PMSH_OperationalPolicyControlLoopElement:
+      version: 1.2.3
+      type: org.onap.policy.clamp.controlloop.PolicyTypeControlLoopElement
+      type_version: 1.0.0
+      description: Control loop element for the operational policy for Performance Management Subscription Handling
+      properties:
+        provider: Ericsson
+        participant_id:
+          name: org.onap.policy.controlloop.PolicyControlLoopParticipant
+          version: 2.2.1
+        policy_type_id:
+          name: onap.policies.operational.pm-subscription-handler
+          version: 1.0.0
+    org.onap.domain.pmsh.PMSH_CDS_ControlLoopElement:
+      version: 1.2.3
+      type: org.onap.policy.clamp.controlloop.ControlLoopElement
+      type_version: 1.0.0
+      description: Control loop element for CDS for Performance Management Subscription Handling
+      properties:
+        provider: Ericsson
+        participant_Id:
+          name: org.onap.ccsdk.cds.controlloop.CdsControlLoopParticipant
+          version: 3.2.1
+        cds_blueprint_id:
+          name: org.onap.ccsdk.cds.PMSHCdsBlueprint
+          version: 1.0.0
+    org.onap.domain.pmsh.PMSHControlLoopDefinition:
+      version: 1.2.3
+      type: org.onap.policy.clamp.controlloop.ControlLoop
+      type_version: 1.0.0
+      description: Control loop for Performance Management Subscription Handling
+      properties:
+        provider: Ericsson
+        elements:
+          - name: org.onap.domain.pmsh.PMSH_DCAEMicroservice
+            version: 1.2.3
+          - name: org.onap.domain.pmsh.PMSH_MonitoringPolicyControlLoopElement
+            version: 1.2.3
+          - name: org.onap.domain.pmsh.PMSH_OperationalPolicyControlLoopElement
+            version: 1.2.3
+          - name: org.onap.domain.pmsh.PMSH_CDS_ControlLoopElement
+            version: 1.2.3
+    org.onap.domain.pmsh.PMSD_DCAEMicroservice:
+      version: 1.2.3
+      type: org.onap.policy.clamp.controlloop.DCAEMicroserviceControlLoopElement
+      type_version: 1.0.0
+      description: Control loop element for the DCAE microservice for Performance Management Subscription Handling
+      properties:
+        provider: Ericsson
+        participant_id:
+          name: org.onap.dcae.controlloop.DCAEMicroserviceControlLoopParticipant
+          version: 2.3.4
+        dcae_blueprint_id:
+          name: org.onap.dcae.blueprints.PMSDBlueprint
+          version: 1.0.0
+    org.onap.domain.pmsh.PMSD_MonitoringPolicyControlLoopElement:
+      version: 1.2.3
+      type: org.onap.policy.clamp.controlloop.PolicyTypeControlLoopElement
+      type_version: 1.0.0
+      description: Control loop element for the monitoring policy for Performance Management Subscription Handling
+      properties:
+        provider: Ericsson
+        participant_id:
+          name: org.onap.policy.controlloop.PolicyControlLoopParticipant
+          version: 2.2.1
+        policy_type_id:
+          name: onap.policies.monitoring.pm-subscription-handler
+          version: 1.0.0
+    org.onap.domain.pmsh.PMSD_OperationalPolicyControlLoopElement:
+      version: 1.2.3
+      type: org.onap.policy.clamp.controlloop.PolicyTypeControlLoopElement
+      type_version: 1.0.0
+      description: Control loop element for the operational policy for Performance Management Subscription Handling
+      properties:
+        provider: Ericsson
+        participant_id:
+          name: org.onap.policy.controlloop.PolicyControlLoopParticipant
+          version: 2.2.1
+        policy_type_id:
+          name: onap.policies.operational.pm-subscription-handler
+          version: 1.0.0
+    org.onap.domain.pmsh.PMSD_CDS_ControlLoopElement:
+      version: 1.2.3
+      type: org.onap.policy.clamp.controlloop.ControlLoopElement
+      type_version: 1.0.0
+      description: Control loop element for CDS for Performance Management Subscription Handling
+      properties:
+        provider: Ericsson
+        participant_Id:
+          name: org.onap.ccsdk.cds.controlloop.CdsControlLoopParticipant
+          version: 3.2.1
+        cds_blueprint_id:
+          name: org.onap.ccsdk.cds.PMSDCdsBlueprint
+          version: 1.0.0
+    org.onap.domain.pmsh.PMSDControlLoopDefinition:
+      version: 1.2.3
+      type: org.onap.policy.clamp.controlloop.ControlLoop
+      type_version: 1.0.0
+      description: Control loop for Performance Management Subscription Handling
+      properties:
+        provider: Ericsson
+        elements:
+          - name: org.onap.domain.pmsh.PMSD_DCAEMicroservice
+            version: 1.2.3
+          - name: org.onap.domain.pmsh.PMSD_MonitoringPolicyControlLoopElement
+            version: 1.2.3
+          - name: org.onap.domain.pmsh.PMSD_OperationalPolicyControlLoopElement
+            version: 1.2.3
+          - name: org.onap.domain.pmsh.PMSD_CDS_ControlLoopElement
+            version: 1.2.3
diff --git a/runtime-controlloop/src/test/resources/rest/servicetemplates/pm_control_loop_tosca.yaml b/runtime-controlloop/src/test/resources/rest/servicetemplates/pm_control_loop_tosca.yaml
new file mode 100644
index 0000000..01f825f
--- /dev/null
+++ b/runtime-controlloop/src/test/resources/rest/servicetemplates/pm_control_loop_tosca.yaml
@@ -0,0 +1,452 @@
+tosca_definitions_version: tosca_simple_yaml_1_3
+capability_types:
+  org.onap.EventProducer:
+    properties:
+      carrier_protocol_type:
+        type: string
+        required: true
+        constraints:
+        - valid_values:
+          - DMAAP_message_router
+          - SOMETHING_ELSE
+          - REST
+      data_format:
+        type: string
+        required: true
+        constraints:
+        - valid_values:
+          - JSON
+          - YAML
+          - JMS
+      event_format:
+        type: string
+        required: true
+      event_format_version:
+        type: string
+        required: false
+      config_keys:
+        type: list
+        required: false
+        entry_schema:
+          type: string
+          constraints:
+          - valid_values:
+            - all valid values should be added here
+            - if not specified, events of any config key may be generated
+            - 'examples for config_key: ves-measurement, ves-syslog, tca_handle_out,
+              etc.'
+    version: 0.0.1
+    derived_from: tosca.capabilities.Root
+  org.onap.EventConsumer:
+    properties:
+      responding_capability:
+        type: string
+        required: false
+      carrier_protocol_type:
+        type: string
+        required: true
+        constraints:
+        - valid_values:
+          - DMAAP_message_router
+          - SOMETHING_ELSE
+          - REST
+      data_format:
+        type: string
+        required: true
+        constraints:
+        - valid_values:
+          - JSON
+          - YAML
+          - JMS
+          - all valid values should be added here
+      event_format:
+        type: string
+        description: 'examples for event_format: Ves_specification, LinkUp, VnfConfigured,
+          etc.'
+        required: true
+      event_format_version:
+        type: string
+        description: 'examples for event_format_version: 5.28.4, 7.30.1, etc.'
+        required: false
+      config_keys:
+        type: list
+        required: false
+        entry_schema:
+          type: string
+          constraints:
+          - valid_values:
+            - all valid values should be added here
+            - if not specified, events of any config key may be generated
+            - 'examples for config_key: ves-measurement, ves-syslog, tca_handle_out,
+              etc.'
+    version: 0.0.1
+    derived_from: tosca.capabilities.Root
+node_types:
+  org.onap.DynamicConfig:
+    properties:
+      application_name:
+        type: string
+        description: Value used to tie the config to an application ? should we be
+          using a relationship here instead?
+        required: true
+      application_version:
+        type: string
+        required: true
+      application_provider:
+        type: string
+        required: false
+      data_types:
+        type: object
+        required: false
+      schema:
+        type: object
+        required: false
+    version: 0.0.1
+    derived_from: tosca.nodes.Root
+  org.onap.APP:
+    properties:
+      application_name:
+        type: string
+        description: Human readable name for the application Product
+        required: false
+      provider:
+        type: string
+        description: Provider of the application and of the descriptor
+        required: true
+      application_version:
+        type: string
+        description: Software version of the application
+        required: true
+      blueprint_id:
+        type: string
+        description: A reference to the app blueprint
+        required: false
+      monitoring_policy:
+        type: string
+        description: A reference to the monitoring policy
+        required: false
+    requirements:
+    - receive:
+        capability: org.onap.EventProducer
+        relationship: org.onap.PropagateEvent
+        occurrences:
+        - 0.0
+        - UNBOUNDED
+        version: 0.0.0
+    - send:
+        capability: org.onap.EventConsumer
+        relationship: org.onap.PropagateEvent
+        occurrences:
+        - 0.0
+        - UNBOUNDED
+        version: 0.0.0
+    version: 0.0.1
+    derived_from: tosca.nodes.Root
+  org.onap.EventRelay:
+    properties:
+      event_format:
+        type: string
+        description: 'examples for event_format: Ves_specification, etc.'
+        required: true
+      event_format_version:
+        type: string
+        description: 'examples for event_format_version: 5.28.4, 7.30.1, etc.'
+        required: true
+      config_keys:
+        type: list
+        required: false
+        entry_schema:
+          type: string
+          constraints:
+          - valid_values:
+            - all valid values should be added here
+            - if not specified, events of any config key is relayed
+            - 'examples for config_key: ves-measurement, ves-syslog, tca_handle_out,
+              etc.'
+      supported_carrier_protocols:
+        type: map
+        description: 'A map describing supported carrier protocols and translations.
+          The tuples define what protocol combinations are supported on the producer
+          and consumer side: e.g. { REST: REST, DMAAP: REST, DMAAP: DMAAP}'
+        required: true
+        key_schema:
+          type: string
+          constraints:
+          - valid_values:
+            - DMAAP_message_router
+            - SOMETHING_ELSE
+            - REST
+            - all valid values should be added here
+        entry_schema:
+          type: string
+          constraints:
+          - valid_values:
+            - DMAAP_message_router
+            - SOMETHING_ELSE
+            - REST
+            - all valid values should be added here
+      supported_data_formats:
+        type: map
+        description: 'Is a map describing supported data formats and translation.
+          The tuples define what protocol combinations are supported on the producer
+          and consumer side: e.g. { JSON: JSON, JMS: JSON, YAML:YAML }'
+        required: true
+        key_schema:
+          type: string
+          constraints:
+          - valid_values:
+            - JSON
+            - JMS
+            - YAML
+            - etc
+            - all valid values should be added here
+        entry_schema:
+          type: string
+          constraints:
+          - valid_values:
+            - JSON
+            - JMS
+            - YAML
+            - etc
+            - all valid values should be added here
+    requirements:
+    - receive:
+        capability: org.onap.EventProducer
+        relationship: org.onap.PropagateEvent
+        occurrences:
+        - 0.0
+        - UNBOUNDED
+        version: 0.0.0
+    - send:
+        capability: org.onap.EventConsumer
+        relationship: org.onap.PropagateEvent
+        occurrences:
+        - 0.0
+        - UNBOUNDED
+        version: 0.0.0
+    version: 0.0.1
+    derived_from: tosca.nodes.Root
+relationship_types:
+  org.onap.PropagateEvent:
+    properties:
+      config_keys:
+        type: list
+        description: The relationship type used on requirements to org.onap.EventProducer
+          and org.onap.EventConsumer capabilities. Filters events by specific config_keys
+          to be transferred by this relationship. That is, any event with a specific
+          config_key found in the list is transferred. If list is not defined or is
+          empty, events with all config_keys are transferred.
+        required: false
+        entry_schema:
+          type: string
+    version: 0.0.1
+    derived_from: tosca.relationships.Root
+topology_template:
+  inputs:
+    pm_subscription_topic:
+      type: string
+    pm_subscription_response_topic:
+      type: string
+    pm_subscription_handler_blueprint_id:
+      type: string
+    pm_subscription_operational_policy_id:
+      type: string
+    pm_subscription_cds_blueprint_id:
+      type: string
+    enable_tls:
+      type: string
+  node_templates:
+    org.onap.PM_Subscription_Handler:
+      type: org.onap.APP
+      properties:
+        application_name: PM Subscription Handler
+        provider: Ericsson
+        application_version: 1.0.0
+        artifact_id:
+          get_input: pm_subscription_handler_blueprint_id
+          description: Is this a reference to the DCAE Cloudify Blueprint that is
+            already stored(or will be stored before CL configuration & instatiation)
+            in DCAE Inventory?
+        artifact_config:
+          enable_tls:
+            get_input: enable_tls
+          pmsh_publish_topic_name:
+            get_input: pm_subscription_topic
+      capabilities:
+        pm-subscription-event-publisher:
+          properties:
+            carrier_protocol_type: DMAAP_message_router
+            data_format: JSON
+            event_format: pm-subscription-event-format
+            event_format_version: 1.0.0
+          attributes:
+            type: org.onap.EventProducer
+          occurrences:
+          - 0.0
+          - UNBOUNDED
+          version: 0.0.0
+        pm-subscription-event-receiver:
+          properties:
+            carrier_protocol_type: DMAAP_message_router
+            data_format: JSON
+            event_format: pm-subscription-event-response-format
+            event_format_version: 1.0.0
+            relationships:
+            - type: tosca.relationships.DependsOn
+            - description: any ideas on a better realtionship ? or is it better to
+                just use the root realtionship ?
+            - target: org.onap.PM_Monitoring_Policy
+          attributes:
+            type: org.onap.EventConsumer
+          occurrences:
+          - 0.0
+          - UNBOUNDED
+          version: 0.0.0
+      version: 0.0.0
+    org.onap.PM_Monitoring_Policy:
+      type: org.onap.DynamicConfig
+      properties:
+        application_name: PM Subscription Handler
+        application_version: 1.0.0
+        provider: Ericsson
+        data_types:
+          measurementType:
+            type: string
+          DN:
+            type: string
+          nfFilter:
+            properties:
+              nfNames:
+                type: list
+                entry_schema: string
+              modelInvariantIDs:
+                type: list
+                entry_schema:
+                  type: string
+              modelVersionIDs:
+                type: list
+                entry_schema:
+                  type: string
+          measurementGroup:
+            properties:
+              masurementTypes:
+                type: list
+                entry_schema:
+                  type: measurementType
+              managedObjectDNsBasic:
+                type: list
+                entry_schema:
+                  type: DN
+        schema:
+          subscription:
+            subscriptionName:
+              type: string
+              required: true
+            administrativeState:
+              type: string
+              required: true
+            filebasedGP:
+              type: integer
+              required: true
+            fileLocation:
+              type: string
+              required: true
+            nfFilter:
+              type: nfFilter
+            measurementGroups:
+              type: list
+              entry_schema:
+                type: measurementGroup
+      version: 0.0.0
+      description: Should I be showing a dependency between PM Subscription Handler
+        and the PM Monitoring Policy
+    org.onap.PM_Policy:
+      type: org.onap.APP
+      properties:
+        application_name: PM Subscription Operational Policy
+        provider: Ericsson
+        application_version: 1.0.0
+        artifact_id:
+          get_input: pm_subscription_operational_policy_id
+        artifact_config: NOT_DEFINED
+      requirements:
+      - receive_0:
+          capability: pm-subscription-event-publisher
+          node: org.onap.PM_Subscription_Handler
+          relationship: NOT_DEFINED
+          properties:
+            config_keys:
+            - topic_name:
+                get_input: pm_subscription_topic
+          version: 0.0.0
+      - send_0:
+          capability: cds-rest-receive
+          node: org.onap.CDS
+          version: 0.0.0
+      - receive_1:
+          capability: cds-rest-response
+          node: org.onap.CDS
+          version: 0.0.0
+      - send_1:
+          capability: pm-subscription-event-receiver
+          node: org.onap.PM_Subscription_Handler
+          relationship: NOT_DEFINED
+          properties:
+            config_keys:
+            - topic_name:
+                get_input: pm_subscription_response_topic
+          version: 0.0.0
+      capabilities:
+        pm-subscription-response-event-publisher:
+          properties:
+            type: org.onap.EventProducer
+            carrier_protocol_type: DMAAP_message_router
+            data_format: JSON
+            event_format: pm-subscription-event-response-format
+            event_format_version: 1.0.0
+          occurrences:
+          - 0.0
+          - UNBOUNDED
+          version: 0.0.0
+      version: 0.0.0
+    org.onap.PM_CDS_Blueprint:
+      type: org.onap.APP
+      properties:
+        application_name: PM Subscription CDS Blueprint
+        provider: Ericsson
+        application_version: 1.0.0
+        artifact_id:
+          get_input: pm_subscription_cds_blueprint_id
+      capabilities:
+        cds-rest-receive:
+          properties:
+            type: org.onap.EventConsumer
+            protocol_type: REST
+            data_format: JSON
+            event_format: cds_action_format
+            event_format_version: 1.0.0
+            responding_capability: cds-rest-response
+          occurrences:
+          - 0.0
+          - UNBOUNDED
+          version: 0.0.0
+        cds-rest-response:
+          properties:
+            type: org.onap.EventProducer
+            protocol_type: REST
+            data_format: JSON
+            event_format: cds_action_response_format
+            event_format_version: 1.0.0
+          occurrences:
+          - 0.0
+          version: 0.0.0
+      version: 0.0.0
+    org.onap.controlloop0:
+      type: org.onap.APP
+      properties:
+        application_name: Test Control Loop
+        provider: Ericsson
+        application_version: 1.0.0
+        status: NOT_DEPLOYED
+      version: 0.0.0
+version: 0.0.0
diff --git a/runtime-controlloop/src/test/resources/rest/servicetemplates/pmsh_multiple_cl_tosca.yaml b/runtime-controlloop/src/test/resources/rest/servicetemplates/pmsh_multiple_cl_tosca.yaml
new file mode 100644
index 0000000..099e2e9
--- /dev/null
+++ b/runtime-controlloop/src/test/resources/rest/servicetemplates/pmsh_multiple_cl_tosca.yaml
@@ -0,0 +1,221 @@
+tosca_definitions_version: tosca_simple_yaml_1_3
+data_types:
+  onap.datatypes.ToscaConceptIdentifier:
+    derived_from: tosca.datatypes.Root
+    properties:
+      name:
+        type: string
+        required: true
+      version:
+        type: string
+        required: true
+node_types:
+  org.onap.policy.clamp.controlloop.Participant:
+    version: 1.0.1
+    derived_from: tosca.nodetypes.Root
+    properties:
+      provider:
+        type: string
+        requred: false
+  org.onap.policy.clamp.controlloop.ControlLoopElement:
+    version: 1.0.1
+    derived_from: tosca.nodetypes.Root
+    properties:
+      provider:
+        type: string
+        requred: false
+      participant_id:
+        type: onap.datatypes.ToscaConceptIdentifier
+        requred: true
+  org.onap.policy.clamp.controlloop.ControlLoop:
+    version: 1.0.1
+    derived_from: tosca.nodetypes.Root
+    properties:
+      provider:
+        type: string
+        requred: false
+      elements:
+        type: list
+        required: true
+        entry_schema:
+          type: onap.datatypes.ToscaConceptIdentifier
+  org.onap.policy.clamp.controlloop.DCAEMicroserviceControlLoopElement:
+    version: 1.0.1
+    derived_from: org.onap.policy.clamp.controlloop.ControlLoopElement
+    properties:
+      dcae_blueprint_id:
+        type: onap.datatypes.ToscaConceptIdentifier
+        requred: true
+  org.onap.policy.clamp.controlloop.PolicyTypeControlLoopElement:
+    version: 1.0.1
+    derived_from: org.onap.policy.clamp.controlloop.ControlLoopElement
+    properties:
+      policy_type_id:
+        type: onap.datatypes.ToscaConceptIdentifier
+        requred: true
+  org.onap.policy.clamp.controlloop.CDSControlLoopElement:
+    version: 1.0.1
+    derived_from: org.onap.policy.clamp.controlloop.ControlLoopElement
+    properties:
+      cds_blueprint_id:
+        type: onap.datatypes.ToscaConceptIdentifier
+        requred: true
+topology_template:
+  node_templates:
+    org.onap.dcae.controlloop.DCAEMicroserviceControlLoopParticipant:
+      version: 2.3.4
+      type: org.onap.policy.clamp.controlloop.Participant
+      type_version: 1.0.1
+      description: Participant for DCAE microservices
+      properties:
+        provider: ONAP
+    org.onap.policy.controlloop.PolicyControlLoopParticipant:
+      version: 2.2.1
+      type: org.onap.policy.clamp.controlloop.Participant
+      type_version: 1.0.1
+      description: Participant for DCAE microservices
+      properties:
+        provider: ONAP
+    org.onap.ccsdk.cds.controlloop.CdsControlLoopParticipant:
+      version: 2.2.1
+      type: org.onap.policy.clamp.controlloop.Participant
+      type_version: 1.0.1
+      description: Participant for DCAE microservices
+      properties:
+        provider: ONAP
+    org.onap.domain.pmsh.PMSH_DCAEMicroservice:
+      version: 1.2.3
+      type: org.onap.policy.clamp.controlloop.DCAEMicroserviceControlLoopElement
+      type_version: 1.0.0
+      description: Control loop element for the DCAE microservice for Performance Management Subscription Handling
+      properties:
+        provider: Ericsson
+        participant_id:
+          name: org.onap.dcae.controlloop.DCAEMicroserviceControlLoopParticipant
+          version: 2.3.4
+        dcae_blueprint_id:
+          name: org.onap.dcae.blueprints.PMSHBlueprint
+          version: 1.0.0
+    org.onap.domain.pmsh.PMSH_MonitoringPolicyControlLoopElement:
+      version: 1.2.3
+      type: org.onap.policy.clamp.controlloop.PolicyTypeControlLoopElement
+      type_version: 1.0.0
+      description: Control loop element for the monitoring policy for Performance Management Subscription Handling
+      properties:
+        provider: Ericsson
+        participant_id:
+          name: org.onap.policy.controlloop.PolicyControlLoopParticipant
+          version: 2.2.1
+        policy_type_id:
+          name: onap.policies.monitoring.pm-subscription-handler
+          version: 1.0.0
+    org.onap.domain.pmsh.PMSH_OperationalPolicyControlLoopElement:
+      version: 1.2.3
+      type: org.onap.policy.clamp.controlloop.PolicyTypeControlLoopElement
+      type_version: 1.0.0
+      description: Control loop element for the operational policy for Performance Management Subscription Handling
+      properties:
+        provider: Ericsson
+        participant_id:
+          name: org.onap.policy.controlloop.PolicyControlLoopParticipant
+          version: 2.2.1
+        policy_type_id:
+          name: onap.policies.operational.pm-subscription-handler
+          version: 1.0.0
+    org.onap.domain.pmsh.PMSH_CDS_ControlLoopElement:
+      version: 1.2.3
+      type: org.onap.policy.clamp.controlloop.ControlLoopElement
+      type_version: 1.0.0
+      description: Control loop element for CDS for Performance Management Subscription Handling
+      properties:
+        provider: Ericsson
+        participant_Id:
+          name: org.onap.ccsdk.cds.controlloop.CdsControlLoopParticipant
+          version: 3.2.1
+        cds_blueprint_id:
+          name: org.onap.ccsdk.cds.PMSHCdsBlueprint
+          version: 1.0.0
+    org.onap.domain.pmsh.PMSHControlLoopDefinition:
+      version: 1.2.3
+      type: org.onap.policy.clamp.controlloop.ControlLoop
+      type_version: 1.0.0
+      description: Control loop for Performance Management Subscription Handling
+      properties:
+        provider: Ericsson
+        elements:
+          - name: org.onap.domain.pmsh.PMSH_DCAEMicroservice
+            version: 1.2.3
+          - name: org.onap.domain.pmsh.PMSH_MonitoringPolicyControlLoopElement
+            version: 1.2.3
+          - name: org.onap.domain.pmsh.PMSH_OperationalPolicyControlLoopElement
+            version: 1.2.3
+          - name: org.onap.domain.pmsh.PMSH_CDS_ControlLoopElement
+            version: 1.2.3
+    org.onap.domain.pmsh.PMSD_DCAEMicroservice:
+      version: 1.2.3
+      type: org.onap.policy.clamp.controlloop.DCAEMicroserviceControlLoopElement
+      type_version: 1.0.0
+      description: Control loop element for the DCAE microservice for Performance Management Subscription Handling
+      properties:
+        provider: Ericsson
+        participant_id:
+          name: org.onap.dcae.controlloop.DCAEMicroserviceControlLoopParticipant
+          version: 2.3.4
+        dcae_blueprint_id:
+          name: org.onap.dcae.blueprints.PMSDBlueprint
+          version: 1.0.0
+    org.onap.domain.pmsh.PMSD_MonitoringPolicyControlLoopElement:
+      version: 1.2.3
+      type: org.onap.policy.clamp.controlloop.PolicyTypeControlLoopElement
+      type_version: 1.0.0
+      description: Control loop element for the monitoring policy for Performance Management Subscription Handling
+      properties:
+        provider: Ericsson
+        participant_id:
+          name: org.onap.policy.controlloop.PolicyControlLoopParticipant
+          version: 2.2.1
+        policy_type_id:
+          name: onap.policies.monitoring.pm-subscription-handler
+          version: 1.0.0
+    org.onap.domain.pmsh.PMSD_OperationalPolicyControlLoopElement:
+      version: 1.2.3
+      type: org.onap.policy.clamp.controlloop.PolicyTypeControlLoopElement
+      type_version: 1.0.0
+      description: Control loop element for the operational policy for Performance Management Subscription Handling
+      properties:
+        provider: Ericsson
+        participant_id:
+          name: org.onap.policy.controlloop.PolicyControlLoopParticipant
+          version: 2.2.1
+        policy_type_id:
+          name: onap.policies.operational.pm-subscription-handler
+          version: 1.0.0
+    org.onap.domain.pmsh.PMSD_CDS_ControlLoopElement:
+      version: 1.2.3
+      type: org.onap.policy.clamp.controlloop.ControlLoopElement
+      type_version: 1.0.0
+      description: Control loop element for CDS for Performance Management Subscription Handling
+      properties:
+        provider: Ericsson
+        participant_Id:
+          name: org.onap.ccsdk.cds.controlloop.CdsControlLoopParticipant
+          version: 3.2.1
+        cds_blueprint_id:
+          name: org.onap.ccsdk.cds.PMSDCdsBlueprint
+          version: 1.0.0
+    org.onap.domain.pmsh.PMSDControlLoopDefinition:
+      version: 1.2.3
+      type: org.onap.policy.clamp.controlloop.ControlLoop
+      type_version: 1.0.0
+      description: Control loop for Performance Management Subscription Handling
+      properties:
+        provider: Ericsson
+        elements:
+          - name: org.onap.domain.pmsh.PMSD_DCAEMicroservice
+            version: 1.2.3
+          - name: org.onap.domain.pmsh.PMSD_MonitoringPolicyControlLoopElement
+            version: 1.2.3
+          - name: org.onap.domain.pmsh.PMSD_OperationalPolicyControlLoopElement
+            version: 1.2.3
+          - name: org.onap.domain.pmsh.PMSD_CDS_ControlLoopElement
+            version: 1.2.3
diff --git a/runtime-controlloop/src/test/resources/testscripts/listenOnTopic.sh b/runtime-controlloop/src/test/resources/testscripts/listenOnTopic.sh
new file mode 100644
index 0000000..5e66177
--- /dev/null
+++ b/runtime-controlloop/src/test/resources/testscripts/listenOnTopic.sh
@@ -0,0 +1,31 @@
+#! /bin/bash
+#  ============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=========================================================
+
+if [ $# -ne 1 ]
+then
+    echo invalid parameters $*, specify a single parameter as the topic to listen on
+    exit 1
+fi
+
+while true
+do
+    curl "http://localhost:3904/events/$1/TEST/1?timeout=60000"
+    echo ""
+done
+