From 5988d899ddebf5d913b8785b860431d4da70a84f Mon Sep 17 00:00:00 2001 From: Sirisha_Manchikanti Date: Fri, 12 Mar 2021 16:50:56 +0000 Subject: Participant simulator Rest API This commit brings REST controllers used in participant simulator and their respective JUnits. There is a ParticipantIntermediaryApiImpl which invokes the Participant and ControlLoop Handler functions. ParticipantHandler and ControlLoopHandler functions are omitted in this commit, to keep changes small. These handlers will be presented for review in later commits. Issue-ID: POLICY-2987 Signed-off-by: Sirisha_Manchikanti Change-Id: I887d7cede8f8758aa786723f9413b79049ce4192 --- .../models/messages/rest/TypedSimpleResponse.java | 35 ++++ .../parameters/ParticipantSimulatorParameters.java | 2 + .../simulator/main/rest/RestController.java | 136 ++++++++++++ .../simulator/simulation/SimulationHandler.java | 10 +- .../simulator/simulation/SimulationProvider.java | 142 +++++++++++++ .../rest/SimulationElementController.java | 194 ++++++++++++++++++ .../rest/SimulationParticipantController.java | 192 +++++++++++++++++ .../rest/SimulationQueryElementController.java | 31 --- .../main/rest/CommonParticipantRestServer.java | 228 +++++++++++++++++++++ .../simulator/main/rest/RestControllerTest.java | 72 +++++++ .../simulator/main/rest/TestListenerUtils.java | 128 ++++++++++++ .../main/rest/TestSimulationRestController.java | 153 ++++++++++++++ .../src/test/resources/parameters/logback-test.xml | 42 ---- .../api/ParticipantIntermediaryApi.java | 119 +++++++++++ .../api/ParticipantIntermediaryFactory.java | 38 ++++ .../api/impl/ParticipantIntermediaryApiImpl.java | 88 ++++++++ 16 files changed, 1530 insertions(+), 80 deletions(-) create mode 100644 tosca-controlloop/models/src/main/java/org/onap/policy/clamp/controlloop/models/messages/rest/TypedSimpleResponse.java create mode 100644 tosca-controlloop/participant/participant-impl/participant-impl-simulator/src/main/java/org/onap/policy/clamp/controlloop/participant/simulator/main/rest/RestController.java create mode 100644 tosca-controlloop/participant/participant-impl/participant-impl-simulator/src/main/java/org/onap/policy/clamp/controlloop/participant/simulator/simulation/SimulationProvider.java create mode 100644 tosca-controlloop/participant/participant-impl/participant-impl-simulator/src/main/java/org/onap/policy/clamp/controlloop/participant/simulator/simulation/rest/SimulationElementController.java create mode 100644 tosca-controlloop/participant/participant-impl/participant-impl-simulator/src/main/java/org/onap/policy/clamp/controlloop/participant/simulator/simulation/rest/SimulationParticipantController.java delete mode 100644 tosca-controlloop/participant/participant-impl/participant-impl-simulator/src/main/java/org/onap/policy/clamp/controlloop/participant/simulator/simulation/rest/SimulationQueryElementController.java create mode 100644 tosca-controlloop/participant/participant-impl/participant-impl-simulator/src/test/java/org/onap/policy/clamp/controlloop/participant/simulator/main/rest/CommonParticipantRestServer.java create mode 100644 tosca-controlloop/participant/participant-impl/participant-impl-simulator/src/test/java/org/onap/policy/clamp/controlloop/participant/simulator/main/rest/RestControllerTest.java create mode 100644 tosca-controlloop/participant/participant-impl/participant-impl-simulator/src/test/java/org/onap/policy/clamp/controlloop/participant/simulator/main/rest/TestListenerUtils.java create mode 100644 tosca-controlloop/participant/participant-impl/participant-impl-simulator/src/test/java/org/onap/policy/clamp/controlloop/participant/simulator/main/rest/TestSimulationRestController.java delete mode 100644 tosca-controlloop/participant/participant-impl/participant-impl-simulator/src/test/resources/parameters/logback-test.xml create mode 100644 tosca-controlloop/participant/participant-intermediary/src/main/java/org/onap/policy/clamp/controlloop/participant/intermediary/api/ParticipantIntermediaryApi.java create mode 100644 tosca-controlloop/participant/participant-intermediary/src/main/java/org/onap/policy/clamp/controlloop/participant/intermediary/api/ParticipantIntermediaryFactory.java create mode 100644 tosca-controlloop/participant/participant-intermediary/src/main/java/org/onap/policy/clamp/controlloop/participant/intermediary/api/impl/ParticipantIntermediaryApiImpl.java diff --git a/tosca-controlloop/models/src/main/java/org/onap/policy/clamp/controlloop/models/messages/rest/TypedSimpleResponse.java b/tosca-controlloop/models/src/main/java/org/onap/policy/clamp/controlloop/models/messages/rest/TypedSimpleResponse.java new file mode 100644 index 000000000..199ac8ee1 --- /dev/null +++ b/tosca-controlloop/models/src/main/java/org/onap/policy/clamp/controlloop/models/messages/rest/TypedSimpleResponse.java @@ -0,0 +1,35 @@ +/*- + * ============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.models.messages.rest; + +import lombok.Getter; +import lombok.Setter; +import lombok.ToString; + +/** + * Response returned when no extra output fields are needed. + */ +@Getter +@Setter +@ToString +public class TypedSimpleResponse extends SimpleResponse { + private T response; +} diff --git a/tosca-controlloop/participant/participant-impl/participant-impl-simulator/src/main/java/org/onap/policy/clamp/controlloop/participant/simulator/main/parameters/ParticipantSimulatorParameters.java b/tosca-controlloop/participant/participant-impl/participant-impl-simulator/src/main/java/org/onap/policy/clamp/controlloop/participant/simulator/main/parameters/ParticipantSimulatorParameters.java index dd28d4e5b..a4e62b446 100644 --- a/tosca-controlloop/participant/participant-impl/participant-impl-simulator/src/main/java/org/onap/policy/clamp/controlloop/participant/simulator/main/parameters/ParticipantSimulatorParameters.java +++ b/tosca-controlloop/participant/participant-impl/participant-impl-simulator/src/main/java/org/onap/policy/clamp/controlloop/participant/simulator/main/parameters/ParticipantSimulatorParameters.java @@ -22,6 +22,7 @@ package org.onap.policy.clamp.controlloop.participant.simulator.main.parameters; import javax.validation.constraints.NotBlank; import lombok.Getter; +import org.onap.policy.clamp.controlloop.participant.intermediary.parameters.ParticipantIntermediaryParameters; import org.onap.policy.common.endpoints.parameters.RestServerParameters; import org.onap.policy.common.parameters.ParameterGroupImpl; import org.onap.policy.common.parameters.annotations.NotNull; @@ -36,6 +37,7 @@ import org.onap.policy.models.provider.PolicyModelsProviderParameters; @Getter public class ParticipantSimulatorParameters extends ParameterGroupImpl { private RestServerParameters restServerParameters; + private ParticipantIntermediaryParameters intermediaryParameters; private PolicyModelsProviderParameters databaseProviderParameters; /** diff --git a/tosca-controlloop/participant/participant-impl/participant-impl-simulator/src/main/java/org/onap/policy/clamp/controlloop/participant/simulator/main/rest/RestController.java b/tosca-controlloop/participant/participant-impl/participant-impl-simulator/src/main/java/org/onap/policy/clamp/controlloop/participant/simulator/main/rest/RestController.java new file mode 100644 index 000000000..120c52c26 --- /dev/null +++ b/tosca-controlloop/participant/participant-impl/participant-impl-simulator/src/main/java/org/onap/policy/clamp/controlloop/participant/simulator/main/rest/RestController.java @@ -0,0 +1,136 @@ +/*- + * ============LICENSE_START======================================================= + * Copyright (C) 2021 Nordix Foundation. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + * ============LICENSE_END========================================================= + */ + +package org.onap.policy.clamp.controlloop.participant.simulator.main.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; +import lombok.AccessLevel; +import lombok.Getter; +import lombok.NoArgsConstructor; +import org.onap.policy.clamp.controlloop.common.exception.ControlLoopRuntimeException; +import org.onap.policy.clamp.controlloop.participant.intermediary.parameters.ParticipantIntermediaryParameters; +import org.onap.policy.clamp.controlloop.participant.simulator.simulation.SimulationProvider; + +/** + * Common superclass to provide REST endpoints for the participant simulator. + */ +// @formatter:off +@Path("/onap/participantsim/v2") +@Api(value = "Participant Simulator API") +@Produces({MediaType.APPLICATION_JSON, RestController.APPLICATION_YAML}) +@SwaggerDefinition( + info = @Info(description = + "Participant Simulator", version = "v1.0", + title = "Participant Simulator"), + consumes = {MediaType.APPLICATION_JSON, RestController.APPLICATION_YAML}, + produces = {MediaType.APPLICATION_JSON, RestController.APPLICATION_YAML}, + schemes = {SwaggerDefinition.Scheme.HTTP, SwaggerDefinition.Scheme.HTTPS}, + tags = {@Tag(name = "participantsim", description = "Participant Simulator")}, + securityDefinition = @SecurityDefinition(basicAuthDefinitions = {@BasicAuthDefinition(key = "basicAuth")})) +// @formatter:on +@NoArgsConstructor +public class RestController { + public static final String APPLICATION_YAML = "application/yaml"; + + 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"; + @Getter(AccessLevel.PROTECTED) + // The provider for simulation requests + private static SimulationProvider simulationProvider; + + /** + * Create a participant simulation provider. + * @return + * + * @throws ControlLoopRuntimeException on errors creating the provider + */ + public static void init(ParticipantIntermediaryParameters participantParameters) + throws ControlLoopRuntimeException { + simulationProvider = new SimulationProvider(participantParameters); + } + + /** + * 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/tosca-controlloop/participant/participant-impl/participant-impl-simulator/src/main/java/org/onap/policy/clamp/controlloop/participant/simulator/simulation/SimulationHandler.java b/tosca-controlloop/participant/participant-impl/participant-impl-simulator/src/main/java/org/onap/policy/clamp/controlloop/participant/simulator/simulation/SimulationHandler.java index ab019990f..e409460c0 100644 --- a/tosca-controlloop/participant/participant-impl/participant-impl-simulator/src/main/java/org/onap/policy/clamp/controlloop/participant/simulator/simulation/SimulationHandler.java +++ b/tosca-controlloop/participant/participant-impl/participant-impl-simulator/src/main/java/org/onap/policy/clamp/controlloop/participant/simulator/simulation/SimulationHandler.java @@ -20,12 +20,12 @@ package org.onap.policy.clamp.controlloop.participant.simulator.simulation; -import java.util.HashSet; import java.util.List; import java.util.Set; import org.onap.policy.clamp.controlloop.common.handler.ControlLoopHandler; import org.onap.policy.clamp.controlloop.participant.simulator.main.parameters.ParticipantSimulatorParameters; -import org.onap.policy.clamp.controlloop.participant.simulator.simulation.rest.SimulationQueryElementController; +import org.onap.policy.clamp.controlloop.participant.simulator.simulation.rest.SimulationElementController; +import org.onap.policy.clamp.controlloop.participant.simulator.simulation.rest.SimulationParticipantController; import org.onap.policy.common.endpoints.event.comm.TopicSink; import org.onap.policy.common.endpoints.listeners.MessageTypeDispatcher; @@ -46,11 +46,7 @@ public class SimulationHandler extends ControlLoopHandler { @Override public Set> getProviderClasses() { - Set> providerClasses = new HashSet<>(); - - providerClasses.add(SimulationQueryElementController.class); - - return providerClasses; + return Set.of(SimulationElementController.class, SimulationParticipantController.class); } @Override diff --git a/tosca-controlloop/participant/participant-impl/participant-impl-simulator/src/main/java/org/onap/policy/clamp/controlloop/participant/simulator/simulation/SimulationProvider.java b/tosca-controlloop/participant/participant-impl/participant-impl-simulator/src/main/java/org/onap/policy/clamp/controlloop/participant/simulator/simulation/SimulationProvider.java new file mode 100644 index 000000000..fc0a31fcb --- /dev/null +++ b/tosca-controlloop/participant/participant-impl/participant-impl-simulator/src/main/java/org/onap/policy/clamp/controlloop/participant/simulator/simulation/SimulationProvider.java @@ -0,0 +1,142 @@ +/*- + * ============LICENSE_START======================================================= + * Copyright (C) 2021 Nordix Foundation. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + * ============LICENSE_END========================================================= + */ + +package org.onap.policy.clamp.controlloop.participant.simulator.simulation; + +import java.io.Closeable; +import java.io.IOException; +import java.util.List; +import lombok.Getter; +import org.onap.policy.clamp.controlloop.common.exception.ControlLoopException; +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.ControlLoopElement; +import org.onap.policy.clamp.controlloop.models.controlloop.concepts.ControlLoops; +import org.onap.policy.clamp.controlloop.models.controlloop.concepts.Participant; +import org.onap.policy.clamp.controlloop.models.messages.rest.TypedSimpleResponse; +import org.onap.policy.clamp.controlloop.participant.intermediary.api.ParticipantIntermediaryApi; +import org.onap.policy.clamp.controlloop.participant.intermediary.api.ParticipantIntermediaryFactory; +import org.onap.policy.clamp.controlloop.participant.intermediary.parameters.ParticipantIntermediaryParameters; + +/** + * This provider class simulation of participants and control loop elements. + */ +public class SimulationProvider implements Closeable { + @Getter + private final ParticipantIntermediaryApi intermediaryApi; + + /** + * Create a participant simulation provider. + * + * @throws ControlLoopRuntimeException on errors creating the provider + */ + public SimulationProvider(ParticipantIntermediaryParameters participantParameters) + throws ControlLoopRuntimeException { + intermediaryApi = new ParticipantIntermediaryFactory().createApiImplementation(); + intermediaryApi.init(participantParameters); + } + + @Override + public void close() throws IOException { + intermediaryApi.close(); + } + + /** + * Get the control loops. + * + * @param name the controlLoop, null to get all + * @param version the controlLoop, null to get all + * @return the control loops + * @throws ControlLoopException on errors getting the control loops + */ + public ControlLoops getControlLoops(String name, String version) throws ControlLoopException { + return intermediaryApi.getControlLoops(name, version); + } + + /** + * Update the given control loop in the simulator. + * + * @param controlLoop the control loop to update + * @return response simple response returned + * @throws ControlLoopException on errors updating the control loop + */ + public TypedSimpleResponse updateControlLoop(ControlLoop controlLoop) + throws ControlLoopException { + TypedSimpleResponse response = new TypedSimpleResponse<>(); + ControlLoop updatedControlLoop = intermediaryApi.updateControlLoopState( + controlLoop.getDefinition(), controlLoop.getOrderedState()); + response.setResponse(updatedControlLoop); + return response; + } + + /** + * Get the simulated control loop elements. + * + * @param name the controlLoopElement, null to get all + * @param version the controlLoopElement, null to get all + * @return the control loop elements + * @throws ControlLoopException on errors getting the control loop elements + */ + public List getControlLoopElements(String name, String version) throws ControlLoopException { + return intermediaryApi.getControlLoopElements(name, version); + } + + /** + * Update the given control loop element in the simulator. + * + * @param element the control loop element to update + * @return response simple response returned + * @throws ControlLoopException on errors updating the control loop element + */ + public TypedSimpleResponse updateControlLoopElement(ControlLoopElement element) + throws ControlLoopException { + TypedSimpleResponse response = new TypedSimpleResponse<>(); + response.setResponse(intermediaryApi.updateControlLoopElementState( + element.getId(), element.getOrderedState())); + return response; + } + + /** + * Get the current simulated participants. + * + * @param name the participant, null to get all + * @param version the participant, null to get all + * @return the list of participants + * @throws ControlLoopException on errors getting the participants + */ + public List getParticipants(String name, String version) throws ControlLoopException { + return intermediaryApi.getParticipants(name, version); + } + + /** + * Update a simulated participant. + * + * @param participant the participant to update + * @return TypedSimpleResponse simple response + * @throws ControlLoopException on errors updating the participant + */ + + public TypedSimpleResponse updateParticipant(Participant participant) throws ControlLoopException { + TypedSimpleResponse response = new TypedSimpleResponse<>(); + response.setResponse(intermediaryApi.updateParticipantState( + participant.getDefinition(), participant.getParticipantState())); + return response; + } +} diff --git a/tosca-controlloop/participant/participant-impl/participant-impl-simulator/src/main/java/org/onap/policy/clamp/controlloop/participant/simulator/simulation/rest/SimulationElementController.java b/tosca-controlloop/participant/participant-impl/participant-impl-simulator/src/main/java/org/onap/policy/clamp/controlloop/participant/simulator/simulation/rest/SimulationElementController.java new file mode 100644 index 000000000..f3c146352 --- /dev/null +++ b/tosca-controlloop/participant/participant-impl/participant-impl-simulator/src/main/java/org/onap/policy/clamp/controlloop/participant/simulator/simulation/rest/SimulationElementController.java @@ -0,0 +1,194 @@ +/*- + * ============LICENSE_START======================================================= + * Copyright (C) 2021 Nordix Foundation. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + * ============LICENSE_END========================================================= + */ + +package org.onap.policy.clamp.controlloop.participant.simulator.simulation.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.GET; +import javax.ws.rs.HeaderParam; +import javax.ws.rs.PUT; +import javax.ws.rs.Path; +import javax.ws.rs.PathParam; +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.ControlLoopElement; +import org.onap.policy.clamp.controlloop.models.controlloop.concepts.ControlLoops; +import org.onap.policy.clamp.controlloop.models.messages.rest.SimpleResponse; +import org.onap.policy.clamp.controlloop.models.messages.rest.TypedSimpleResponse; +import org.onap.policy.clamp.controlloop.participant.simulator.main.rest.RestController; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Class to provide REST end points for participant simulator to query/update details of controlLoopElements. + */ +public class SimulationElementController extends RestController { + private static final Logger LOGGER = LoggerFactory.getLogger(SimulationElementController.class); + + /** + * Queries details of all control loop element within the simulator. + * + * @param requestId request ID used in ONAP logging + * @param name the name of the Control Loop element to get, null to get all + * @param version the version of the Control Loop element to get, null to get all + * @return the control loop elements + */ + // @formatter:off + @GET + @Path("/elements/{name}/{version}") + @ApiOperation(value = "Query details of the requested simulated control loop elements", + notes = "Queries details of the requested simulated control loop elements, " + + "returning all control loop element details", + response = ControlLoops.class, + tags = { + "Clamp Control Loop Participant Simulator 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 elements(@HeaderParam(REQUEST_ID_NAME) @ApiParam(REQUEST_ID_PARAM_DESCRIPTION) UUID requestId, + @ApiParam(value = "Control loop element name", required = true) @PathParam("name") String name, + @ApiParam(value = "Control loop element version", required = true) @PathParam("version") String version) { + + try { + List response = getSimulationProvider().getControlLoopElements(name, version); + return addLoggingHeaders(addVersionControlHeaders(Response.status(Status.OK)), requestId).entity(response) + .build(); + + } catch (ControlLoopException cle) { + LOGGER.warn("get of control loop elements failed", cle); + SimpleResponse resp = new SimpleResponse(); + resp.setErrorDetails(cle.getErrorResponse().getErrorMessage()); + return addLoggingHeaders( + addVersionControlHeaders(Response.status(cle.getErrorResponse().getResponseCode())), requestId) + .entity(resp).build(); + } + + } + + /** + * Updates a control loop element in the simulator. + * + * @param requestId request ID used in ONAP logging + * @param body the body of a control loop element + * @return a response + */ + // @formatter:off + @PUT + @Path("/elements") + @ApiOperation( + value = "Updates simulated control loop elements", + notes = "Updates simulated control loop elements, returning the updated control loop definition IDs", + response = TypedSimpleResponse.class, + tags = { + "Clamp Control Loop Participant Simulator 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 = "Body of a control loop element", required = true) ControlLoopElement body) { + + try { + TypedSimpleResponse response = + getSimulationProvider().updateControlLoopElement(body); + return addLoggingHeaders(addVersionControlHeaders(Response.status(Status.OK)), requestId).entity(response) + .build(); + + } catch (ControlLoopException cle) { + LOGGER.warn("update of control loop element failed", cle); + TypedSimpleResponse resp = new TypedSimpleResponse<>(); + resp.setErrorDetails(cle.getErrorResponse().getErrorMessage()); + return addLoggingHeaders( + addVersionControlHeaders(Response.status(cle.getErrorResponse().getResponseCode())), requestId) + .entity(resp).build(); + } + } +} diff --git a/tosca-controlloop/participant/participant-impl/participant-impl-simulator/src/main/java/org/onap/policy/clamp/controlloop/participant/simulator/simulation/rest/SimulationParticipantController.java b/tosca-controlloop/participant/participant-impl/participant-impl-simulator/src/main/java/org/onap/policy/clamp/controlloop/participant/simulator/simulation/rest/SimulationParticipantController.java new file mode 100644 index 000000000..d6ca6d0d1 --- /dev/null +++ b/tosca-controlloop/participant/participant-impl/participant-impl-simulator/src/main/java/org/onap/policy/clamp/controlloop/participant/simulator/simulation/rest/SimulationParticipantController.java @@ -0,0 +1,192 @@ +/*- + * ============LICENSE_START======================================================= + * Copyright (C) 2021 Nordix Foundation. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + * ============LICENSE_END========================================================= + */ + +package org.onap.policy.clamp.controlloop.participant.simulator.simulation.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.GET; +import javax.ws.rs.HeaderParam; +import javax.ws.rs.PUT; +import javax.ws.rs.Path; +import javax.ws.rs.PathParam; +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.Participant; +import org.onap.policy.clamp.controlloop.models.messages.rest.SimpleResponse; +import org.onap.policy.clamp.controlloop.models.messages.rest.TypedSimpleResponse; +import org.onap.policy.clamp.controlloop.participant.simulator.main.rest.RestController; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Class to provide REST end points for participant simulator to query/update details of all participants. + */ +public class SimulationParticipantController extends RestController { + private static final Logger LOGGER = LoggerFactory.getLogger(SimulationParticipantController.class); + + /** + * Queries details of all participants within the simulator. + * + * @param requestId request ID used in ONAP logging + * @param name the name of the participant to get, null to get all + * @param version the version of the participant to get, null to get all + * @return the participants + */ + // @formatter:off + @GET + @Path("/participants/{name}/{version}") + @ApiOperation(value = "Query details of the requested simulated participants", + notes = "Queries details of the requested simulated participants, " + + "returning all participant details", + response = List.class, + tags = { + "Clamp Control Loop Participant Simulator 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 participants(@HeaderParam(REQUEST_ID_NAME) @ApiParam(REQUEST_ID_PARAM_DESCRIPTION) UUID requestId, + @ApiParam(value = "Participant name", required = true) @PathParam("name") String name, + @ApiParam(value = "Participant version", required = true) @PathParam("version") String version) { + + try { + List response = getSimulationProvider().getParticipants(name, version); + return addLoggingHeaders(addVersionControlHeaders(Response.status(Status.OK)), requestId).entity(response) + .build(); + + } catch (ControlLoopException cle) { + LOGGER.warn("get of participants failed", cle); + SimpleResponse resp = new SimpleResponse(); + resp.setErrorDetails(cle.getErrorResponse().getErrorMessage()); + return addLoggingHeaders( + addVersionControlHeaders(Response.status(cle.getErrorResponse().getResponseCode())), requestId) + .entity(resp).build(); + } + + } + + /** + * Updates a participant in the simulator. + * + * @param requestId request ID used in ONAP logging + * @param body the body of a participant + * @return a response + */ + // @formatter:off + @PUT + @Path("/participants") + @ApiOperation( + value = "Updates simulated participants", + notes = "Updates simulated participants, returning the updated control loop definition IDs", + response = TypedSimpleResponse.class, + tags = { + "Clamp Control Loop Participant Simulator 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 = "Body of a participant", required = true) Participant body) { + + try { + TypedSimpleResponse response = getSimulationProvider().updateParticipant(body); + return addLoggingHeaders(addVersionControlHeaders(Response.status(Status.OK)), requestId).entity(response) + .build(); + + } catch (ControlLoopException cle) { + LOGGER.warn("update of participant failed", cle); + TypedSimpleResponse resp = new TypedSimpleResponse<>(); + resp.setErrorDetails(cle.getErrorResponse().getErrorMessage()); + return addLoggingHeaders( + addVersionControlHeaders(Response.status(cle.getErrorResponse().getResponseCode())), requestId) + .entity(resp).build(); + } + } +} diff --git a/tosca-controlloop/participant/participant-impl/participant-impl-simulator/src/main/java/org/onap/policy/clamp/controlloop/participant/simulator/simulation/rest/SimulationQueryElementController.java b/tosca-controlloop/participant/participant-impl/participant-impl-simulator/src/main/java/org/onap/policy/clamp/controlloop/participant/simulator/simulation/rest/SimulationQueryElementController.java deleted file mode 100644 index 2165da797..000000000 --- a/tosca-controlloop/participant/participant-impl/participant-impl-simulator/src/main/java/org/onap/policy/clamp/controlloop/participant/simulator/simulation/rest/SimulationQueryElementController.java +++ /dev/null @@ -1,31 +0,0 @@ -/*- - * ============LICENSE_START======================================================= - * Copyright (C) 2021 Nordix Foundation. - * ================================================================================ - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * SPDX-License-Identifier: Apache-2.0 - * ============LICENSE_END========================================================= - */ - -package org.onap.policy.clamp.controlloop.participant.simulator.simulation.rest; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * Class to provide REST end points for participant simulator to query details of controlLoopElements. - */ -public class SimulationQueryElementController { - private static final Logger LOGGER = LoggerFactory.getLogger(SimulationQueryElementController.class); -} diff --git a/tosca-controlloop/participant/participant-impl/participant-impl-simulator/src/test/java/org/onap/policy/clamp/controlloop/participant/simulator/main/rest/CommonParticipantRestServer.java b/tosca-controlloop/participant/participant-impl/participant-impl-simulator/src/test/java/org/onap/policy/clamp/controlloop/participant/simulator/main/rest/CommonParticipantRestServer.java new file mode 100644 index 000000000..7aae32629 --- /dev/null +++ b/tosca-controlloop/participant/participant-impl/participant-impl-simulator/src/test/java/org/onap/policy/clamp/controlloop/participant/simulator/main/rest/CommonParticipantRestServer.java @@ -0,0 +1,228 @@ + +/*- + * ============LICENSE_START======================================================= + * Copyright (C) 2021 Nordix Foundation. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + * ============LICENSE_END========================================================= + */ + +package org.onap.policy.clamp.controlloop.participant.simulator.main.rest; + +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.Invocation; +import javax.ws.rs.client.WebTarget; +import javax.ws.rs.core.MediaType; +import org.glassfish.jersey.client.ClientProperties; +import org.glassfish.jersey.client.authentication.HttpAuthenticationFeature; +import org.junit.AfterClass; +import org.junit.Before; +import org.junit.BeforeClass; +import org.onap.policy.clamp.controlloop.common.exception.ControlLoopException; +import org.onap.policy.clamp.controlloop.participant.simulator.main.parameters.CommonTestData; +import org.onap.policy.clamp.controlloop.participant.simulator.main.startstop.Main; +import org.onap.policy.common.endpoints.event.comm.TopicEndpointManager; +import org.onap.policy.common.endpoints.http.server.HttpServletServerFactoryInstance; +import org.onap.policy.common.gson.GsonMessageBodyHandler; +import org.onap.policy.common.utils.network.NetworkUtil; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Class to perform Rest unit tests. + * + */ + +public class CommonParticipantRestServer { + + private static final String CONFIG_FILE = "src/test/resources/parameters/TestConfigParameters.json"; + private static final Logger LOGGER = LoggerFactory.getLogger(CommonParticipantRestServer.class); + public static final String SELF = NetworkUtil.getHostname(); + public static final String ENDPOINT_PREFIX = "onap/participantsim/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. + * + * @throws Exception if an error occurs + */ + @BeforeClass + public static void setUpBeforeClass() throws Exception { + setUpBeforeClass(true); + } + + /** + * Allocates a port for the server, writes a config file, and then starts Main, if + * specified. + * + * @param shouldStart {@code true} if Main should be started, {@code false} otherwise + * @throws Exception if an error occurs + */ + public static void setUpBeforeClass(boolean shouldStart) throws Exception { + port = NetworkUtil.allocPort(); + httpPrefix = "http://localhost:" + port + "/"; + + makeConfigFile(); + HttpServletServerFactoryInstance.getServerFactory().destroy(); + TopicEndpointManager.getManager().shutdown(); + + if (shouldStart) { + startMain(); + } + } + + /** + * Stops Main. + */ + @AfterClass + public static void teardownAfterClass() { + try { + stopMain(); + + } catch (ControlLoopException exp) { + LOGGER.error("cannot stop main", exp); + } + } + + /** + * Set up. + * + * @throws Exception if an error occurs + */ + @Before + public void setUp() throws Exception { + // restart, if not currently running + if (main == null) { + startMain(); + } + } + + /** + * 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. + * + * @throws IOException if an error occurs writing the configuration file + * @throws FileNotFoundException if an error occurs writing the configuration file + * + * @throws Exception if an error occurs + */ + private static void makeConfigFile() throws FileNotFoundException, IOException { + String json = CommonTestData.getParticipantParameterGroupAsString(port); + 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 { + // make sure port is available + if (NetworkUtil.isTcpPortOpen("localhost", port, 1, 1L)) { + throw new IllegalStateException("port " + port + " is still in use"); + } + + final String[] configParameters = { "-c", CONFIG_FILE }; + + main = new Main(configParameters); + + if (!NetworkUtil.isTcpPortOpen("localhost", 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 ControlLoopException { + if (main != null) { + main.shutdown(); + main = null; + } + } + + /** + * 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); + } +} diff --git a/tosca-controlloop/participant/participant-impl/participant-impl-simulator/src/test/java/org/onap/policy/clamp/controlloop/participant/simulator/main/rest/RestControllerTest.java b/tosca-controlloop/participant/participant-impl/participant-impl-simulator/src/test/java/org/onap/policy/clamp/controlloop/participant/simulator/main/rest/RestControllerTest.java new file mode 100644 index 000000000..c7a39c48b --- /dev/null +++ b/tosca-controlloop/participant/participant-impl/participant-impl-simulator/src/test/java/org/onap/policy/clamp/controlloop/participant/simulator/main/rest/RestControllerTest.java @@ -0,0 +1,72 @@ +/* + * ============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.participant.simulator.main.rest; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; + +import java.util.UUID; +import javax.ws.rs.Produces; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response; +import javax.ws.rs.core.Response.ResponseBuilder; +import org.junit.Before; +import org.junit.Test; + +public class RestControllerTest { + + private RestController ctlr; + private ResponseBuilder bldr; + + @Before + public void setUp() { + ctlr = new RestController(); + bldr = Response.status(Response.Status.OK); + } + + @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() { + Response resp = ctlr.addVersionControlHeaders(bldr).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() { + Response resp = ctlr.addLoggingHeaders(bldr, null).build(); + assertNotNull(resp.getHeaderString(RestController.REQUEST_ID_NAME)); + } + + @Test + public void testAddLoggingHeaders_NonNull() { + UUID uuid = UUID.randomUUID(); + Response resp = ctlr.addLoggingHeaders(bldr, uuid).build(); + assertEquals(uuid.toString(), resp.getHeaderString(RestController.REQUEST_ID_NAME)); + } +} diff --git a/tosca-controlloop/participant/participant-impl/participant-impl-simulator/src/test/java/org/onap/policy/clamp/controlloop/participant/simulator/main/rest/TestListenerUtils.java b/tosca-controlloop/participant/participant-impl/participant-impl-simulator/src/test/java/org/onap/policy/clamp/controlloop/participant/simulator/main/rest/TestListenerUtils.java new file mode 100644 index 000000000..7b7dd2d84 --- /dev/null +++ b/tosca-controlloop/participant/participant-impl/participant-impl-simulator/src/test/java/org/onap/policy/clamp/controlloop/participant/simulator/main/rest/TestListenerUtils.java @@ -0,0 +1,128 @@ +/*- + * ============LICENSE_START======================================================= + * Copyright (C) 2021 Nordix Foundation. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + * ============LICENSE_END========================================================= + */ + +package org.onap.policy.clamp.controlloop.participant.simulator.main.rest; + +import static org.junit.Assert.assertTrue; + +import java.io.FileNotFoundException; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.UUID; +import org.onap.policy.clamp.controlloop.models.controlloop.concepts.ControlLoop; +import org.onap.policy.clamp.controlloop.models.controlloop.concepts.ControlLoopElement; +import org.onap.policy.clamp.controlloop.models.controlloop.concepts.ControlLoopOrderedState; +import org.onap.policy.clamp.controlloop.models.controlloop.concepts.ControlLoopState; +import org.onap.policy.clamp.controlloop.participant.simulator.main.parameters.CommonTestData; +import org.onap.policy.common.utils.coder.Coder; +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.tosca.authorative.concepts.ToscaConceptIdentifier; +import org.onap.policy.models.tosca.authorative.concepts.ToscaNodeTemplate; +import org.onap.policy.models.tosca.authorative.concepts.ToscaServiceTemplate; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class TestListenerUtils { + + private static final YamlJsonTranslator yamlTranslator = new YamlJsonTranslator(); + private static final Coder CODER = new StandardCoder(); + static CommonTestData commonTestData = new CommonTestData(); + private static RestController restController; + private static final Logger LOGGER = LoggerFactory.getLogger(TestListenerUtils.class); + + private TestListenerUtils() {} + + /** + * Method to create a controlLoop from a yaml file. + * + * @return ControlLoop controlloop + */ + public static ControlLoop createControlLoop() { + ControlLoop controlLoop = new ControlLoop(); + List elements = new ArrayList<>(); + ToscaServiceTemplate toscaServiceTemplate = testControlLoopRead(); + Map nodeTemplatesMap = toscaServiceTemplate + .getToscaTopologyTemplate().getNodeTemplates(); + for (Map.Entry toscaInputEntry : nodeTemplatesMap.entrySet()) { + ControlLoopElement clElement = new ControlLoopElement(); + clElement.setId(UUID.randomUUID()); + + ToscaConceptIdentifier clElementParticipantId = new ToscaConceptIdentifier(); + clElementParticipantId.setName(toscaInputEntry.getKey()); + clElementParticipantId.setVersion(toscaInputEntry.getValue().getVersion()); + clElement.setParticipantId(clElementParticipantId); + + clElement.setDefinition(clElementParticipantId); + clElement.setState(ControlLoopState.UNINITIALISED); + clElement.setDescription(toscaInputEntry.getValue().getDescription()); + clElement.setOrderedState(ControlLoopOrderedState.UNINITIALISED); + elements.add(clElement); + } + controlLoop.setElements(elements); + controlLoop.setName("PMSHInstance0"); + controlLoop.setVersion("1.0.0"); + + ToscaConceptIdentifier definition = new ToscaConceptIdentifier(); + definition.setName("PMSHInstance0"); + definition.setVersion("1.0.0"); + controlLoop.setDefinition(definition); + + return controlLoop; + } + + private static ToscaServiceTemplate testControlLoopRead() { + Set controlLoopDirectoryContents = ResourceUtils + .getDirectoryContents("src/test/resources/rest/servicetemplates"); + + boolean atLeastOneControlLoopTested = false; + ToscaServiceTemplate toscaServiceTemplate = null; + + for (String controlLoopFilePath : controlLoopDirectoryContents) { + if (!controlLoopFilePath.endsWith(".yaml")) { + continue; + } + atLeastOneControlLoopTested = true; + toscaServiceTemplate = testControlLoopYamlSerialization(controlLoopFilePath); + } + + assertTrue(atLeastOneControlLoopTested); + return toscaServiceTemplate; + } + + private static ToscaServiceTemplate testControlLoopYamlSerialization(String controlLoopFilePath) { + try { + String controlLoopString = ResourceUtils.getResourceAsString(controlLoopFilePath); + if (controlLoopString == null) { + throw new FileNotFoundException(controlLoopFilePath); + } + + ToscaServiceTemplate serviceTemplate = yamlTranslator.fromYaml( + controlLoopString, ToscaServiceTemplate.class); + return serviceTemplate; + } catch (FileNotFoundException e) { + LOGGER.error("cannot find YAML file", controlLoopFilePath); + throw new IllegalArgumentException(e); + } + } +} diff --git a/tosca-controlloop/participant/participant-impl/participant-impl-simulator/src/test/java/org/onap/policy/clamp/controlloop/participant/simulator/main/rest/TestSimulationRestController.java b/tosca-controlloop/participant/participant-impl/participant-impl-simulator/src/test/java/org/onap/policy/clamp/controlloop/participant/simulator/main/rest/TestSimulationRestController.java new file mode 100644 index 000000000..7adc88d09 --- /dev/null +++ b/tosca-controlloop/participant/participant-impl/participant-impl-simulator/src/test/java/org/onap/policy/clamp/controlloop/participant/simulator/main/rest/TestSimulationRestController.java @@ -0,0 +1,153 @@ +/*- + * ============LICENSE_START======================================================= + * Copyright (C) 2019 Nordix Foundation. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + * ============LICENSE_END========================================================= + */ + +package org.onap.policy.clamp.controlloop.participant.simulator.main.rest; + +import static org.junit.Assert.assertEquals; + +import java.util.ArrayList; +import java.util.List; +import javax.ws.rs.client.Entity; +import javax.ws.rs.client.Invocation; +import javax.ws.rs.core.MediaType; +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.ControlLoopElement; +import org.onap.policy.clamp.controlloop.models.controlloop.concepts.ControlLoopOrderedState; +import org.onap.policy.clamp.controlloop.models.controlloop.concepts.Participant; +import org.onap.policy.clamp.controlloop.models.controlloop.concepts.ParticipantState; +import org.onap.policy.clamp.controlloop.models.messages.rest.TypedSimpleResponse; +import org.onap.policy.clamp.controlloop.participant.simulator.main.parameters.CommonTestData; +import org.onap.policy.common.endpoints.event.comm.Topic.CommInfrastructure; +import org.onap.policy.models.tosca.authorative.concepts.ToscaConceptIdentifier; + +/** + * Class to perform unit test of {@link TestSimulationRestController}. + */ +public class TestSimulationRestController extends CommonParticipantRestServer { + private static final String PARTICIPANTS_ENDPOINT = "participants"; + private static final String ELEMENTS_ENDPOINT = "elements"; + private static final CommInfrastructure INFRA = CommInfrastructure.NOOP; + private static final String TOPIC = "my-topic"; + static CommonTestData commonTestData = new CommonTestData(); + private static RestController restController; + + /** + * Setup before class, instantiate SimulationProvider. + * + */ + @BeforeClass + public static void setUpBeforeClass() throws Exception { + CommonParticipantRestServer.setUpBeforeClass(); + } + + @AfterClass + public static void teardownAfterClass() { + CommonParticipantRestServer.teardownAfterClass(); + } + + @Test + public void testSwagger() throws Exception { + super.testSwagger(ELEMENTS_ENDPOINT); + } + + @Test + public void testQuery_Unauthorized() throws Exception { + Invocation.Builder invocationBuilder = super.sendNoAuthRequest(ELEMENTS_ENDPOINT); + Response rawresp = invocationBuilder.buildGet().invoke(); + assertEquals(Response.Status.UNAUTHORIZED.getStatusCode(), rawresp.getStatus()); + } + + @Test + public void testQueryParticipants() throws Exception { + Participant participant = new Participant(); + ToscaConceptIdentifier participantId = CommonTestData.getParticipantId(); + participant.setDefinition(participantId); + participant.setName(participantId.getName()); + participant.setVersion(participantId.getVersion()); + + // GET REST call for querying the participants + Invocation.Builder invocationBuilder = + super.sendRequest(PARTICIPANTS_ENDPOINT + "/" + participant.getKey().getName() + + "/" + participant.getVersion()); + + Response rawresp = invocationBuilder.buildGet().invoke(); + // Response is not OK, as handling is not done + assertEquals(Response.Status.INTERNAL_SERVER_ERROR.getStatusCode(), rawresp.getStatus()); + } + + @Test + public void testQueryControlLoopElements() throws Exception { + // GET REST call for querying the controlLoop elements + Invocation.Builder invocationBuilder = + super.sendRequest(ELEMENTS_ENDPOINT + "/" + "PMSHInstance0" + "/" + "1.0.0"); + + Response rawresp = invocationBuilder.buildGet().invoke(); + // Response is not OK, as handling is not done + assertEquals(Response.Status.INTERNAL_SERVER_ERROR.getStatusCode(), rawresp.getStatus()); + } + + @Test + public void testUpdateParticipant() throws Exception { + Participant participant = new Participant(); + ToscaConceptIdentifier participantId = CommonTestData.getParticipantId(); + participant.setDefinition(participantId); + participant.setName(participantId.getName()); + participant.setVersion(participantId.getVersion()); + + List participants = new ArrayList<>(); + participants.add(participant); + assertEquals(ParticipantState.UNKNOWN, participants.get(0).getParticipantState()); + // Change the state of the participant to PASSIVE from UNKNOWN + participants.get(0).setParticipantState(ParticipantState.PASSIVE); + Entity entParticipant = Entity.entity(participants.get(0), MediaType.APPLICATION_JSON); + + // PUT REST call for updating Participant + Invocation.Builder invocationBuilder = sendRequest(PARTICIPANTS_ENDPOINT); + Response rawresp = invocationBuilder.put(entParticipant); + TypedSimpleResponse resp = rawresp.readEntity(TypedSimpleResponse.class); + // Response is not OK, as handling is not done + assertEquals(Response.Status.INTERNAL_SERVER_ERROR.getStatusCode(), rawresp.getStatus()); + } + + @Test + public void testUpdateControlLoopElement() throws Exception { + ControlLoop controlLoop = TestListenerUtils.createControlLoop(); + List controlLoopElements = controlLoop.getElements(); + + // Check the initial state on the ControlLoopElement, which is UNINITIALISED + assertEquals(ControlLoopOrderedState.UNINITIALISED, controlLoopElements.get(0).getOrderedState()); + + // Change the state of the ControlLoopElement to PASSIVE from UNINITIALISED + controlLoopElements.get(0).setOrderedState(ControlLoopOrderedState.PASSIVE); + Entity entClElement = Entity.entity(controlLoopElements.get(0), MediaType.APPLICATION_JSON); + + // PUT REST call for updating ControlLoopElement + Invocation.Builder invocationBuilder = sendRequest(ELEMENTS_ENDPOINT); + Response rawresp = invocationBuilder.put(entClElement); + TypedSimpleResponse resp = rawresp.readEntity(TypedSimpleResponse.class); + // Response is not OK, as handling is not done + assertEquals(Response.Status.INTERNAL_SERVER_ERROR.getStatusCode(), rawresp.getStatus()); + } +} + diff --git a/tosca-controlloop/participant/participant-impl/participant-impl-simulator/src/test/resources/parameters/logback-test.xml b/tosca-controlloop/participant/participant-impl/participant-impl-simulator/src/test/resources/parameters/logback-test.xml deleted file mode 100644 index 54b578653..000000000 --- a/tosca-controlloop/participant/participant-impl/participant-impl-simulator/src/test/resources/parameters/logback-test.xml +++ /dev/null @@ -1,42 +0,0 @@ - - - - - - Participant - - - - - - - %d %level %msg%n - - - - - - - - - - - diff --git a/tosca-controlloop/participant/participant-intermediary/src/main/java/org/onap/policy/clamp/controlloop/participant/intermediary/api/ParticipantIntermediaryApi.java b/tosca-controlloop/participant/participant-intermediary/src/main/java/org/onap/policy/clamp/controlloop/participant/intermediary/api/ParticipantIntermediaryApi.java new file mode 100644 index 000000000..6c3e029fe --- /dev/null +++ b/tosca-controlloop/participant/participant-intermediary/src/main/java/org/onap/policy/clamp/controlloop/participant/intermediary/api/ParticipantIntermediaryApi.java @@ -0,0 +1,119 @@ +/*- + * ============LICENSE_START======================================================= + * Copyright (C) 2021 Nordix Foundation. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + * ============LICENSE_END========================================================= + */ + +package org.onap.policy.clamp.controlloop.participant.intermediary.api; + +import java.util.List; +import java.util.UUID; +import org.onap.policy.clamp.controlloop.models.controlloop.concepts.ClElementStatistics; +import org.onap.policy.clamp.controlloop.models.controlloop.concepts.ControlLoop; +import org.onap.policy.clamp.controlloop.models.controlloop.concepts.ControlLoopElement; +import org.onap.policy.clamp.controlloop.models.controlloop.concepts.ControlLoopOrderedState; +import org.onap.policy.clamp.controlloop.models.controlloop.concepts.ControlLoops; +import org.onap.policy.clamp.controlloop.models.controlloop.concepts.Participant; +import org.onap.policy.clamp.controlloop.models.controlloop.concepts.ParticipantState; +import org.onap.policy.clamp.controlloop.models.controlloop.concepts.ParticipantStatistics; +import org.onap.policy.clamp.controlloop.participant.intermediary.parameters.ParticipantIntermediaryParameters; +import org.onap.policy.models.tosca.authorative.concepts.ToscaConceptIdentifier; + +/** + * This interface is used by participant implementations to use the participant intermediary. + */ +public interface ParticipantIntermediaryApi { + /** + * Initialise the participant intermediary. + * + * @param parameters the parameters for the intermediary + */ + public void init(ParticipantIntermediaryParameters parameters); + + /** + * Close the intermediary. + */ + public void close(); + + /** + * Get participants loops from the intermediary API. + * + * @param name the participant name, null for all + * @param version the participant version, null for all + * @return the participants + */ + public List getParticipants(String name, String version); + + /** + * Update the state of a participant. + * + * @param definition the definition of the participant to update the state on + * @param state the state of the participant + * @return updated participant + */ + public Participant updateParticipantState(ToscaConceptIdentifier definition, ParticipantState state); + + /** + * Update the statistics of a participant. + * + * @param participantStatistics the statistics of the participant + */ + public void updateParticipantStatistics(ParticipantStatistics participantStatistics); + + /** + * Get control loops from the intermediary API. + * + * @param name the control loop element name, null for all + * @param version the control loop element version, null for all + * @return the control loop elements + */ + public ControlLoops getControlLoops(String name, String version); + + /** + * Get control loop elements from the intermediary API. + * + * @param name the control loop element name, null for all + * @param version the control loop element version, null for all + * @return the control loop elements + */ + public List getControlLoopElements(String name, String version); + + /** + * Update the state of a control loop. + * + * @param definition the ID of the control loop to update the state on + * @param state the state of the control loop + * @return ControlLoop updated control loop + */ + public ControlLoop updateControlLoopState(ToscaConceptIdentifier definition, ControlLoopOrderedState state); + + /** + * Update the state of a control loop element. + * + * @param id the ID of the control loop element to update the state on + * @param state the state of the control loop element + * @return ControlLoopElement updated control loop element + */ + public ControlLoopElement updateControlLoopElementState(UUID id, ControlLoopOrderedState state); + + /** + * Update the control loop element statistics. + * + * @param elementStatistics the updated statistics + */ + public void updateControlLoopElementStatistics(ClElementStatistics elementStatistics); +} diff --git a/tosca-controlloop/participant/participant-intermediary/src/main/java/org/onap/policy/clamp/controlloop/participant/intermediary/api/ParticipantIntermediaryFactory.java b/tosca-controlloop/participant/participant-intermediary/src/main/java/org/onap/policy/clamp/controlloop/participant/intermediary/api/ParticipantIntermediaryFactory.java new file mode 100644 index 000000000..d7cc4b2ed --- /dev/null +++ b/tosca-controlloop/participant/participant-intermediary/src/main/java/org/onap/policy/clamp/controlloop/participant/intermediary/api/ParticipantIntermediaryFactory.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.participant.intermediary.api; + +import org.onap.policy.clamp.controlloop.participant.intermediary.api.impl.ParticipantIntermediaryApiImpl; + +/** + * Factory class for creating {@link ParticipantIntermediaryApi} instances. + */ +public class ParticipantIntermediaryFactory { + + /** + * Create an implementation of the {@link ParticipantIntermediaryApi} interface. + * + * @return the implementation of the API + */ + public ParticipantIntermediaryApi createApiImplementation() { + return new ParticipantIntermediaryApiImpl(); + } +} diff --git a/tosca-controlloop/participant/participant-intermediary/src/main/java/org/onap/policy/clamp/controlloop/participant/intermediary/api/impl/ParticipantIntermediaryApiImpl.java b/tosca-controlloop/participant/participant-intermediary/src/main/java/org/onap/policy/clamp/controlloop/participant/intermediary/api/impl/ParticipantIntermediaryApiImpl.java new file mode 100644 index 000000000..939f927e6 --- /dev/null +++ b/tosca-controlloop/participant/participant-intermediary/src/main/java/org/onap/policy/clamp/controlloop/participant/intermediary/api/impl/ParticipantIntermediaryApiImpl.java @@ -0,0 +1,88 @@ +/*- + * ============LICENSE_START======================================================= + * Copyright (C) 2021 Nordix Foundation. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + * ============LICENSE_END========================================================= + */ + +package org.onap.policy.clamp.controlloop.participant.intermediary.api.impl; + +import java.util.Collections; +import java.util.List; +import java.util.UUID; +import org.onap.policy.clamp.controlloop.models.controlloop.concepts.ClElementStatistics; +import org.onap.policy.clamp.controlloop.models.controlloop.concepts.ControlLoop; +import org.onap.policy.clamp.controlloop.models.controlloop.concepts.ControlLoopElement; +import org.onap.policy.clamp.controlloop.models.controlloop.concepts.ControlLoopOrderedState; +import org.onap.policy.clamp.controlloop.models.controlloop.concepts.ControlLoops; +import org.onap.policy.clamp.controlloop.models.controlloop.concepts.Participant; +import org.onap.policy.clamp.controlloop.models.controlloop.concepts.ParticipantState; +import org.onap.policy.clamp.controlloop.models.controlloop.concepts.ParticipantStatistics; +import org.onap.policy.clamp.controlloop.participant.intermediary.api.ParticipantIntermediaryApi; +import org.onap.policy.clamp.controlloop.participant.intermediary.parameters.ParticipantIntermediaryParameters; +import org.onap.policy.models.tosca.authorative.concepts.ToscaConceptIdentifier; + +/** + * This class is api implementation used by participant intermediary. + */ +public class ParticipantIntermediaryApiImpl implements ParticipantIntermediaryApi { + + @Override + public void init(ParticipantIntermediaryParameters parameters) { + } + + @Override + public void close() { + } + + @Override + public List getParticipants(String name, String version) { + return Collections.emptyList(); + } + + @Override + public Participant updateParticipantState(ToscaConceptIdentifier definition, ParticipantState state) { + return null; + } + + @Override + public void updateParticipantStatistics(ParticipantStatistics participantStatistics) { + } + + @Override + public ControlLoops getControlLoops(String name, String version) { + return null; + } + + @Override + public List getControlLoopElements(String name, String version) { + return Collections.emptyList(); + } + + @Override + public ControlLoop updateControlLoopState(ToscaConceptIdentifier definition, ControlLoopOrderedState state) { + return null; + } + + @Override + public ControlLoopElement updateControlLoopElementState(UUID id, ControlLoopOrderedState state) { + return null; + } + + @Override + public void updateControlLoopElementStatistics(ClElementStatistics elementStatistics) { + } +} -- cgit 1.2.3-korg