Merge "Include module diagram"
authorClaudio David Gasparini <claudio.gasparini@intl.att.com>
Thu, 27 May 2021 07:21:14 +0000 (07:21 +0000)
committerGerrit Code Review <gerrit@o-ran-sc.org>
Thu, 27 May 2021 07:21:14 +0000 (07:21 +0000)
33 files changed:
docs/pm/index.rst
tox.ini
version.properties [new file with mode: 0644]
ves-nf-oam-adopter/ves-nf-oam-adopter-api/pom.xml
ves-nf-oam-adopter/ves-nf-oam-adopter-api/src/main/java/org/o/ran/oam/nf/oam/adopter/spi/MapperConfigProvider.java [new file with mode: 0644]
ves-nf-oam-adopter/ves-nf-oam-adopter-app/docs/api/swagger/openapi.yaml
ves-nf-oam-adopter/ves-nf-oam-adopter-app/src/main/java/org/o/ran/oam/nf/oam/adopter/app/controller/RestExceptionHandler.java
ves-nf-oam-adopter/ves-nf-oam-adopter-app/src/main/java/org/o/ran/oam/nf/oam/adopter/app/http/HttpCientFactory.java
ves-nf-oam-adopter/ves-nf-oam-adopter-app/src/test/java/org/o/ran/oam/nf/oam/adopter/app/AdapterApplicationTest.java
ves-nf-oam-adopter/ves-nf-oam-adopter-event-notifier/src/main/java/org/o/ran/oam/nf/oam/adopter/event/notifier/NotificationProvider.java
ves-nf-oam-adopter/ves-nf-oam-adopter-mock/src/main/java/org/o/ran/oam/nf/oam/adopter/mock/app/SnmpNotifier.java
ves-nf-oam-adopter/ves-nf-oam-adopter-mock/src/main/java/org/o/ran/oam/nf/oam/adopter/mock/app/controller/RanController.java
ves-nf-oam-adopter/ves-nf-oam-adopter-parent/pom.xml
ves-nf-oam-adopter/ves-nf-oam-adopter-pm-manager/src/main/java/org/o/ran/oam/nf/oam/adopter/pm/rest/manager/AdaptersDeployer.java
ves-nf-oam-adopter/ves-nf-oam-adopter-pm-manager/src/main/java/org/o/ran/oam/nf/oam/adopter/pm/rest/manager/PerformanceManagementMapperConfigProvider.java
ves-nf-oam-adopter/ves-nf-oam-adopter-pm-manager/src/main/java/org/o/ran/oam/nf/oam/adopter/pm/rest/manager/PerformanceManagementRestAgent.java
ves-nf-oam-adopter/ves-nf-oam-adopter-pm-manager/src/main/java/org/o/ran/oam/nf/oam/adopter/pm/rest/manager/PerformanceManagementRestAgentFactory.java
ves-nf-oam-adopter/ves-nf-oam-adopter-pm-manager/src/main/java/org/o/ran/oam/nf/oam/adopter/pm/rest/manager/mapper/CommonEventHeaderHandler.java
ves-nf-oam-adopter/ves-nf-oam-adopter-pm-manager/src/main/java/org/o/ran/oam/nf/oam/adopter/pm/rest/manager/mapper/MeasurementFieldsHandler.java
ves-nf-oam-adopter/ves-nf-oam-adopter-pm-manager/src/main/java/org/o/ran/oam/nf/oam/adopter/pm/rest/manager/mapper/PerformanceManagementFile2VesMapper.java
ves-nf-oam-adopter/ves-nf-oam-adopter-pm-sb-rest-client/src/main/java/org/o/ran/oam/nf/oam/adopter/pm/sb/rest/client/DefaultHttpRestClient.java
ves-nf-oam-adopter/ves-nf-oam-adopter-pm-sb-rest-client/src/main/java/org/o/ran/oam/nf/oam/adopter/pm/sb/rest/client/http/DownloadPerformanceManagementFilesHandler.java
ves-nf-oam-adopter/ves-nf-oam-adopter-pm-sb-rest-client/src/main/java/org/o/ran/oam/nf/oam/adopter/pm/sb/rest/client/http/TokenHandler.java
ves-nf-oam-adopter/ves-nf-oam-adopter-pm-sb-rest-client/src/test/java/org/o/ran/oam/nf/oam/adopter/pm/sb/rest/client/DefaultHttpRestClientTest.java
ves-nf-oam-adopter/ves-nf-oam-adopter-snmp-manager/src/main/java/org/o/ran/oam/nf/oam/adopter/snmp/manager/SnmpCommandResponder.java [new file with mode: 0644]
ves-nf-oam-adopter/ves-nf-oam-adopter-snmp-manager/src/main/java/org/o/ran/oam/nf/oam/adopter/snmp/manager/SnmpManager.java [moved from ves-nf-oam-adopter/ves-nf-oam-adopter-snmp-manager/src/main/java/org/o/ran/oam/nf/oam/adopter/snmp/manager/SnmpManagerImpl.java with 86% similarity]
ves-nf-oam-adopter/ves-nf-oam-adopter-snmp-manager/src/main/java/org/o/ran/oam/nf/oam/adopter/snmp/manager/SnmpMappingConfigurationProvider.java
ves-nf-oam-adopter/ves-nf-oam-adopter-snmp-manager/src/main/java/org/o/ran/oam/nf/oam/adopter/snmp/manager/SnmpTrapListener.java
ves-nf-oam-adopter/ves-nf-oam-adopter-snmp-manager/src/main/java/org/o/ran/oam/nf/oam/adopter/snmp/manager/configurations/SnmpManagerConfig.java
ves-nf-oam-adopter/ves-nf-oam-adopter-snmp-manager/src/main/java/org/o/ran/oam/nf/oam/adopter/snmp/manager/mapper/CommonEventHeaderHandler.java
ves-nf-oam-adopter/ves-nf-oam-adopter-snmp-manager/src/main/java/org/o/ran/oam/nf/oam/adopter/snmp/manager/mapper/FaultFieldsHandler.java
ves-nf-oam-adopter/ves-nf-oam-adopter-snmp-manager/src/main/java/org/o/ran/oam/nf/oam/adopter/snmp/manager/mapper/SnmpMapperImpl.java
ves-nf-oam-adopter/ves-nf-oam-adopter-snmp-manager/src/test/java/org/o/ran/oam/nf/oam/adopter/snmp/manager/SnmpManagerTest.java

index 433aaa9..8088dc7 100644 (file)
@@ -181,7 +181,6 @@ REST PM Configuration
 
 Configuration file **application.yml** contains global definitions required to be consumed by PM REST adapters services.
 
-- **token-api-username** Defines the username to be used for login
 - **synchronization-time-start** Defines the time for execution of pull of PM files and forwarding as VES Message
 - **synchronization-time-frequency** Defines the time for execution of pull of PM files and forwarding as VES Message
 - **mapping-config-path** Defines the path where mapping configuration file is located
diff --git a/tox.ini b/tox.ini
index 2705e16..51d2b1b 100644 (file)
--- a/tox.ini
+++ b/tox.ini
@@ -1,5 +1,5 @@
 # ==================================================================================
-#       Copyright (c) 2020 Nordix
+#   Copyright (C) 2021 AT&T Intellectual Property
 #
 #   Licensed under the Apache License, Version 2.0 (the "License");
 #   you may not use this file except in compliance with the License.
diff --git a/version.properties b/version.properties
new file mode 100644 (file)
index 0000000..5aaf9e8
--- /dev/null
@@ -0,0 +1,12 @@
+# Note that these variables cannot be structured (e.g. : version.release or version.snapshot etc... )
+# because they are used in Jenkins, whose plug-in doesn't support this
+
+major=1
+minor=0
+patch=0
+
+base_version=${major}.${minor}.${patch}
+
+# Release must be completed with git revision # in Jenkins
+release_version=${base_version}
+snapshot_version=${base_version}-SNAPSHOT
\ No newline at end of file
index a75acbe..ce36d7a 100644 (file)
             <groupId>io.reactivex.rxjava3</groupId>
             <artifactId>rxjava</artifactId>
         </dependency>
+        <dependency>
+            <groupId>jakarta.annotation</groupId>
+            <artifactId>jakarta.annotation-api</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.slf4j</groupId>
+            <artifactId>slf4j-api</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.commons</groupId>
+            <artifactId>commons-configuration2</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>com.fasterxml.jackson.dataformat</groupId>
+            <artifactId>jackson-dataformat-yaml</artifactId>
+        </dependency>
     </dependencies>
 
     <build>
diff --git a/ves-nf-oam-adopter/ves-nf-oam-adopter-api/src/main/java/org/o/ran/oam/nf/oam/adopter/spi/MapperConfigProvider.java b/ves-nf-oam-adopter/ves-nf-oam-adopter-api/src/main/java/org/o/ran/oam/nf/oam/adopter/spi/MapperConfigProvider.java
new file mode 100644 (file)
index 0000000..d1cdbba
--- /dev/null
@@ -0,0 +1,72 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  O-RAN-SC
+ *  ================================================================================
+ *  Copyright © 2021 AT&T Intellectual Property. All rights reserved.
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *  ============LICENSE_END=========================================================
+ */
+
+package org.o.ran.oam.nf.oam.adopter.spi;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.dataformat.yaml.YAMLFactory;
+import java.io.IOException;
+import java.io.StringWriter;
+import java.nio.file.Paths;
+import javax.annotation.PostConstruct;
+import org.apache.commons.configuration2.YAMLConfiguration;
+import org.apache.commons.configuration2.builder.ConfigurationBuilderEvent;
+import org.apache.commons.configuration2.builder.ReloadingFileBasedConfigurationBuilder;
+import org.apache.commons.configuration2.builder.fluent.Parameters;
+import org.apache.commons.configuration2.ex.ConfigurationException;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public abstract class MapperConfigProvider<T> {
+
+    private static final Logger LOG = LoggerFactory.getLogger(MapperConfigProvider.class);
+
+    private static final ObjectMapper YAML_READER = new ObjectMapper(new YAMLFactory());
+    private ReloadingFileBasedConfigurationBuilder<YAMLConfiguration> builder;
+
+    /**
+     * Initialize Service.
+     */
+    @PostConstruct
+    public final void init() throws IOException, ConfigurationException {
+        final var filePath = Paths.get(getMappingFilePath()).toUri();
+        builder = new ReloadingFileBasedConfigurationBuilder<>(YAMLConfiguration.class)
+                          .configure(new Parameters().hierarchical().setURL(filePath.toURL()));
+        builder.addEventListener(ConfigurationBuilderEvent.CONFIGURATION_REQUEST, event -> {
+            builder.getReloadingController().checkForReloading(null);
+            LOG.debug("Reloading {}", filePath);
+        });
+        //Test initial configuration
+        builder.getConfiguration();
+    }
+
+    public abstract String getMappingFilePath();
+
+    /**
+     * Provide VES Mapping configuration.
+     */
+    public final T getVesMappingConfiguration() throws ConfigurationException, IOException {
+        final YAMLConfiguration configuration = builder.getConfiguration();
+        final var output = new StringWriter();
+        configuration.write(output);
+        return YAML_READER.readValue(output.toString(), getClazz());
+    }
+
+    public abstract Class<T> getClazz();
+}
index 6a02e63..d3ae8e8 100644 (file)
@@ -47,8 +47,9 @@ paths:
                 items:
                   type: string
         '400':
-          $ref: '#/components/responses/400Error'
-
+          $ref: '#/components/responses/BadRequest'
+        '401':
+          $ref: '#/components/responses/Unauthorized'
 
   /adapter/{host}:
     delete:
@@ -65,13 +66,13 @@ paths:
 
       responses:
         '200':
-          description: Successfully deleted an adapter
+          $ref: '#/components/responses/Success'
         '400':
-          description: Invalid request
+          $ref: '#/components/responses/BadRequest'
         '401':
-          description: Unauthorized
+          $ref: '#/components/responses/Unauthorized'
         '404':
-          description: adapter not found
+          $ref: '#/components/responses/NotFound'
 
   /adapter:
     post:
@@ -87,12 +88,23 @@ paths:
               $ref: '#/components/schemas/Adapter'
       responses:
         '200':
-          description: Successfully returned a list of adapters
+          $ref: '#/components/responses/Success'
         '400':
-          $ref: '#/components/responses/400Error'
+          $ref: '#/components/responses/BadRequest'
+        '401':
+          $ref: '#/components/responses/Unauthorized'
 
 components:
   schemas:
+    ErrorMessage:
+      type: object
+      title: Error
+      properties:
+        status:
+          type: string
+        message:
+          type: string
+
     Adapter:
       type: object
       properties:
@@ -113,12 +125,24 @@ components:
         - mechId
 
   responses:
-    400Error:
+    Success:
+      description: Succesfully excecuted
+    BadRequest:
       description: Invalid request
       content:
         application/json:
           schema:
-            type: object
-            properties:
-              message:
-                type: string
\ No newline at end of file
+            $ref: '#/components/schemas/ErrorMessage'
+    Unauthorized:
+      description: Unhautorized request
+      content:
+        application/json:
+          schema:
+            $ref: '#/components/schemas/ErrorMessage'
+    NotFound:
+      description: Not Found
+      content:
+        application/json:
+          schema:
+            $ref: '#/components/schemas/ErrorMessage'
+
index 4eb1625..fff799a 100644 (file)
@@ -51,10 +51,11 @@ public class RestExceptionHandler {
     /**
      * Handle Not Found Exceptions.
      */
+    @ResponseStatus(HttpStatus.NOT_FOUND)
     @ExceptionHandler({NotFoundException.class})
-    public static ResponseEntity<Object> handleNotFoundExceptions(final NotFoundException exception) {
+    public static String handleNotFoundExceptions(final NotFoundException exception) {
         LOG.error("Request failed", exception);
-        return ResponseEntity.notFound().build();
+        return exception.getMessage();
     }
 
     /**
index 7184c28..974c972 100644 (file)
@@ -53,7 +53,7 @@ public final class HttpCientFactory {
             final String trustStorePassword, final Long conectionTimeout, final Long responseTimeout)
             throws NoSuchAlgorithmException, KeyStoreException, KeyManagementException, IOException,
             CertificateException {
-        final SSLContext sslContext = getSslContext(new File(trustStore), trustStorePassword);
+        final var sslContext = getSslContext(new File(trustStore), trustStorePassword);
         return trustTrustStore(sslContext, conectionTimeout, responseTimeout);
     }
 
index 73cea18..78d036c 100644 (file)
@@ -85,24 +85,32 @@ class AdapterApplicationTest {
     void testGetAllAdapters() throws Exception {
         when(deployer.getAll()).thenReturn(Collections.singletonList("mockResult"));
 
-        mockMvc.perform(get("/adapters/").secure(true).contentType(MediaType.APPLICATION_JSON)).andDo(print())
+        mockMvc.perform(get("/adapters/").secure(true)
+                                .contentType(MediaType.APPLICATION_JSON))
+                .andDo(print())
                 .andExpect(status().isOk()).andExpect(content().string(containsString("mockResult")));
     }
 
     @Test
     @WithMockUser(username = "admin", roles = "ADMIN")
     void testDeleteAdapter() throws Exception {
-        mockMvc.perform(delete("/adapters/adapter/172.10.55.3").secure(true).contentType(MediaType.APPLICATION_JSON))
+        mockMvc.perform(delete("/adapters/adapter/172.10.55.3").secure(true)
+                                .contentType(MediaType.APPLICATION_JSON))
                 .andDo(print()).andExpect(status().isOk());
     }
 
     @Test
     @WithMockUser(username = "admin", roles = "ADMIN")
     void testNotFound() throws Exception {
-        doThrow(NotFoundException.class).when(deployer).delete(anyString());
-
-        mockMvc.perform(delete("/adapters/adapter/172.10.55.3").secure(true).contentType(MediaType.APPLICATION_JSON))
-                .andDo(print()).andExpect(status().isNotFound());
+        doThrow(new NotFoundException("172.10.55.3"))
+                .when(deployer)
+                .delete(anyString());
+
+        mockMvc.perform(delete("/adapters/adapter/172.10.55.3").secure(true)
+                                .contentType(MediaType.APPLICATION_JSON))
+                .andDo(print())
+                .andExpect(status().isNotFound())
+                .andExpect(content().string(containsString("Adapter 172.10.55.3 is not present.")));
     }
 
     @Test
@@ -117,14 +125,16 @@ class AdapterApplicationTest {
         mechId.password("somePass");
         adapter.setMechId(mechId);
 
-        mockMvc.perform(post("/adapters/adapter").secure(true).contentType(MediaType.APPLICATION_JSON)
-                                .content(GSON.toJson(adapter))).andDo(print()).andExpect(status().isOk());
+        mockMvc.perform(post("/adapters/adapter").secure(true)
+                                .contentType(MediaType.APPLICATION_JSON)
+                                .content(GSON.toJson(adapter)))
+                .andDo(print())
+                .andExpect(status().isOk());
     }
 
     @Test
     @WithMockUser(username = "admin", roles = "ADMIN")
     void testAlreadyExist() throws Exception {
-
         final Adapter adapter = new Adapter();
         adapter.setHost("172.10.55.3");
 
@@ -133,16 +143,20 @@ class AdapterApplicationTest {
         mechId.password("somePass");
         adapter.setMechId(mechId);
 
-        doThrow(AlreadyPresentException.class).when(deployer).create(anyString(), anyString(), anyString());
+        doThrow(new AlreadyPresentException("172.10.55.3"))
+                .when(deployer).create(anyString(), anyString(), anyString());
 
-        mockMvc.perform(post("/adapters/adapter").secure(true).contentType(MediaType.APPLICATION_JSON)
-                                .content(GSON.toJson(adapter))).andDo(print()).andExpect(status().isBadRequest());
+        mockMvc.perform(post("/adapters/adapter")
+                                .secure(true).contentType(MediaType.APPLICATION_JSON)
+                                .content(GSON.toJson(adapter)))
+                .andDo(print())
+                .andExpect(status().isBadRequest())
+                .andExpect(content().string(containsString("Adapter 172.10.55.3 already present.")));
     }
 
     @Test
     @WithMockUser(username = "admin", roles = "ADMIN")
     void testMissingArguments() throws Exception {
-
         final Adapter adapter = new Adapter();
         adapter.setHost("172.10.55.3");
 
@@ -150,9 +164,27 @@ class AdapterApplicationTest {
         mechId.username("admin");
         adapter.setMechId(mechId);
 
+        mockMvc.perform(post("/adapters/adapter").secure(true)
+                                .contentType(MediaType.APPLICATION_JSON)
+                                .content(GSON.toJson(adapter)))
+                .andDo(print())
+                .andExpect(status().isBadRequest());
+    }
+
+    @Test
+    void testUnauthorized() throws Exception {
+        mockMvc.perform(post("/adapters/adapter").secure(true))
+                .andDo(print())
+                .andExpect(status().isUnauthorized());
+
+        mockMvc.perform(post("/adapters/adapter").secure(true))
+            .andDo(print())
+            .andExpect(status().isUnauthorized());
+
+        mockMvc.perform(delete("/adapters/adapter/172.10.55.3").secure(true))
+                .andDo(print())
+                .andExpect(status().isUnauthorized());
 
-        mockMvc.perform(post("/adapters/adapter").secure(true).contentType(MediaType.APPLICATION_JSON)
-                                .content(GSON.toJson(adapter))).andDo(print()).andExpect(status().isBadRequest());
     }
 
     @Test
index 2814706..02980a4 100644 (file)
@@ -25,7 +25,6 @@ import com.google.gson.Gson;
 import io.reactivex.rxjava3.core.Completable;
 import io.reactivex.rxjava3.core.Single;
 import java.util.List;
-import org.apache.hc.client5.http.async.methods.SimpleHttpRequest;
 import org.apache.hc.client5.http.async.methods.SimpleHttpRequests;
 import org.apache.hc.client5.http.async.methods.SimpleHttpResponse;
 import org.apache.hc.client5.http.impl.async.CloseableHttpAsyncClient;
@@ -78,7 +77,7 @@ public final class NotificationProvider implements VesEventNotifier {
     }
 
     private Completable notify(final String url, final String payload) {
-        final SimpleHttpRequest request = SimpleHttpRequests.post(url);
+        final var request = SimpleHttpRequests.post(url);
         request.setBody(payload, ContentType.APPLICATION_JSON);
         request.setHeader(HttpHeaders.AUTHORIZATION, authHeader);
         return Single.fromFuture(httpClient.execute(request, null))
@@ -89,7 +88,7 @@ public final class NotificationProvider implements VesEventNotifier {
     }
 
     private static Completable validatePost(final SimpleHttpResponse response) {
-        final String statusLine = new StatusLine(response).toString();
+        final var statusLine = new StatusLine(response).toString();
         final String entity;
         final int code = response.getCode();
         if (code == HttpStatus.SC_OK || code == HttpStatus.SC_ACCEPTED) {
index 60961f4..e79c143 100644 (file)
@@ -76,7 +76,7 @@ public class SnmpNotifier {
 
     private static void sendTrap(final CommunityTarget<UdpAddress> target, final HashMap<String, String> trap,
             final String trapType) throws IOException {
-        final PDU pdu = new PDU();
+        final var pdu = new PDU();
         pdu.setType(PDU.TRAP);
         trap.forEach((key, value) -> {
             try {
@@ -86,7 +86,7 @@ public class SnmpNotifier {
             }
         });
 
-        try (final Snmp snmp = new Snmp(new DefaultUdpTransportMapping())) {
+        try (final var snmp = new Snmp(new DefaultUdpTransportMapping())) {
             snmp.send(pdu, target, null, null);
             LOG.info("Trap {} sent successfully.", trapType);
         }
index 3b35d94..f3b0bef 100644 (file)
@@ -53,14 +53,14 @@ public class RanController implements ControllerApi {
     @Override
     public ResponseEntity<Resource> getPerformanceManagementFiles() {
         LOG.info("Read pm files.");
-        final HttpHeaders headers = new HttpHeaders();
+        final var headers = new HttpHeaders();
         headers.setContentType(MediaType.APPLICATION_OCTET_STREAM);
         return new ResponseEntity<>(ZipUtil.read(), headers, HttpStatus.OK);
     }
 
     @Override
     public ResponseEntity<String> getTimeZone() {
-        final ZoneId zoneId = ZoneId.systemDefault();
+        final var zoneId = ZoneId.systemDefault();
         final ZoneOffset offset = zoneId.getRules().getOffset(Instant.now());
         LOG.info("ZoneId {} / Offset {}", zoneId, offset);
         return ResponseEntity.ok(GSON.toJson(new TimeZoneOffsetResponse(OFFSET_FORMATTER.format(offset))));
index 499ca0c..435210a 100644 (file)
@@ -36,7 +36,7 @@
 
     <properties>
         <!-- Code coverate & Sonar -->
-        <minimum.coverage>0.9</minimum.coverage>
+        <minimum.coverage>0.85</minimum.coverage>
         <jacoco.reportDirectory.aggregate>
             ${project.reporting.outputDirectory}/jacoco-aggregate
         </jacoco.reportDirectory.aggregate>
@@ -52,7 +52,7 @@
             ../ves-nf-oam-adopter-app/target/site/jacoco-ut/jacoco.xml,
             ../ves-nf-oam-adopter-app/target/site/jacoco-aggregate/jacoco.xml
         </sonar.coverage.jacoco.xmlReportPaths>
-        <sonar.scanner.version>4.4.0.2170</sonar.scanner.version>
+        <sonar.scanner.version>3.8.0.2131</sonar.scanner.version>
         <sonar.exclusions>
             **/api/**,
             **/model/**,
index 2cd5c5c..3fcc725 100644 (file)
@@ -54,7 +54,7 @@ public final class AdaptersDeployer implements PerformanceManagementAdaptersDepl
         if (adapters.get(hostIpAddress) != null) {
             throw new AlreadyPresentException(hostIpAddress);
         }
-        final Adapter adapter =
+        final var adapter =
                 Adapter.builder().username(username).password(password).hostIpAddress(hostIpAddress).build();
         final PerformanceManagementRestAgent pmRestAgent =
                 pmRestAgentFactory.createPerformanceManagementRestAgent(adapter).blockingGet();
index 36ff149..65d2c63 100644 (file)
 
 package org.o.ran.oam.nf.oam.adopter.pm.rest.manager;
 
-import static java.util.Objects.requireNonNull;
-
-import com.fasterxml.jackson.databind.ObjectMapper;
-import com.fasterxml.jackson.dataformat.yaml.YAMLFactory;
-import java.io.IOException;
-import java.io.StringWriter;
-import java.net.URI;
-import java.nio.file.Paths;
-import javax.annotation.PostConstruct;
-import org.apache.commons.configuration2.YAMLConfiguration;
-import org.apache.commons.configuration2.builder.ConfigurationBuilderEvent;
-import org.apache.commons.configuration2.builder.ReloadingFileBasedConfigurationBuilder;
-import org.apache.commons.configuration2.builder.fluent.Parameters;
-import org.apache.commons.configuration2.ex.ConfigurationException;
 import org.o.ran.oam.nf.oam.adopter.pm.rest.manager.pojos.VesMappingConfiguration;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
+import org.o.ran.oam.nf.oam.adopter.spi.MapperConfigProvider;
 import org.springframework.beans.factory.annotation.Value;
 import org.springframework.stereotype.Service;
 
 @Service
-public class PerformanceManagementMapperConfigProvider  {
-
-    private static final Logger LOG = LoggerFactory.getLogger(PerformanceManagementMapperConfigProvider.class);
+public class PerformanceManagementMapperConfigProvider extends MapperConfigProvider<VesMappingConfiguration> {
 
-    private static final ObjectMapper YAML_READER = new ObjectMapper(new YAMLFactory());
     @Value("${pm-rest-manager.mapping-config-path:#{null}}")
     private String mappingFilePath;
-    private ReloadingFileBasedConfigurationBuilder<YAMLConfiguration> builder;
 
-    /**
-     * Initialize Service.
-     */
-    @PostConstruct
-    public void init() throws IOException, ConfigurationException {
-        requireNonNull(mappingFilePath);
-        final URI filePath = Paths.get(mappingFilePath).toUri();
-        builder = new ReloadingFileBasedConfigurationBuilder<>(YAMLConfiguration.class)
-                          .configure(new Parameters().hierarchical().setURL(filePath.toURL()));
-        builder.addEventListener(ConfigurationBuilderEvent.CONFIGURATION_REQUEST, event -> {
-            builder.getReloadingController().checkForReloading(null);
-            LOG.debug("Reloading {}", filePath);
-        });
-        //Test initial configuration
-        builder.getConfiguration();
+    @Override
+    public String getMappingFilePath() {
+        return mappingFilePath;
     }
 
-    /**
-     * Provide VES Mapping configuration.
-     */
-    public VesMappingConfiguration getVesMappingConfiguration() throws ConfigurationException, IOException {
-        final YAMLConfiguration configuration = builder.getConfiguration();
-        final StringWriter output = new StringWriter();
-        configuration.write(output);
-        return YAML_READER.readValue(output.toString(), VesMappingConfiguration.class);
+    @Override
+    public Class<VesMappingConfiguration> getClazz() {
+        return VesMappingConfiguration.class;
     }
 }
index 66693fc..c8133f4 100644 (file)
@@ -56,7 +56,7 @@ public final class PerformanceManagementRestAgent implements AutoCloseable {
     }
 
     private long initialDelay() {
-        final ZonedDateTime now = ZonedDateTime.now(zoneId);
+        final var now = ZonedDateTime.now(zoneId);
 
         ZonedDateTime nextRun = now
                 .withHour(synchronizationTimeStart.getHour())
@@ -65,8 +65,7 @@ public final class PerformanceManagementRestAgent implements AutoCloseable {
         if (now.compareTo(nextRun) > 0) {
             nextRun = nextRun.plusSeconds(synchronizationTimeFrequency);
         }
-        final Duration duration = Duration.between(now, nextRun);
-        return duration.getSeconds();
+        return Duration.between(now, nextRun).getSeconds();
     }
 
     public ZoneId getTimeZone() {
index 0ebaa6c..b6c9860 100644 (file)
@@ -58,8 +58,8 @@ public class PerformanceManagementRestAgentFactory {
      */
     public final Single<PerformanceManagementRestAgent> createPerformanceManagementRestAgent(final Adapter adapter) {
         return httpRestClient.getTimeZone(adapter).map(timeZone -> {
-            final PerformanceManagementAgentRunnable pmAgentRunnable =
-                    new PerformanceManagementAgentRunnable(httpRestClient, eventListener, pmFileMapper, adapter);
+            final var pmAgentRunnable = new PerformanceManagementAgentRunnable(httpRestClient, eventListener,
+                pmFileMapper, adapter);
             return new PerformanceManagementRestAgent(pmAgentRunnable, properties.getSynchronizationTimeStart(),
                     properties.getSynchronizationTimeFrequency(), timeZone);
         });
index b2375ec..920f9e2 100644 (file)
@@ -37,7 +37,7 @@ final class CommonEventHeaderHandler {
 
     static CommonEventHeader toCommonEventHeader(final VesMappingConfiguration config, final String hostIp,
             final CsvConfiguration csv, final Map<String, String> recordMap, final int sequence) {
-        final CommonEventHeader header = new CommonEventHeader();
+        final var header = new CommonEventHeader();
         setMandatoryFields(config, hostIp, csv, header, recordMap, sequence);
         setOptionalFields(config, header);
         return header;
index 166af50..3b28d31 100644 (file)
@@ -39,7 +39,7 @@ final class MeasurementFieldsHandler {
                 .stream().filter(records::containsKey)
                 .collect(Collectors.toMap(Function.identity(), records::get)));
 
-        final NamedHashMap namedHashMap = new NamedHashMap();
+        final var namedHashMap = new NamedHashMap();
         namedHashMap.setName(csv.getAdditionalMeasurementsName());
         namedHashMap.setHashMap(csv.getAdditionalMeasurements().stream()
                 .filter(records::containsKey)
@@ -68,7 +68,7 @@ final class MeasurementFieldsHandler {
 
     static MeasurementFields toMeasurementFields(final VesMappingConfiguration config,
             final Map<String, String> records) {
-        final MeasurementFields measurementFields = new MeasurementFields();
+        final var measurementFields = new MeasurementFields();
         setMandatoryFields(measurementFields, config);
         setOptionalsFields(measurementFields, records, config);
         return measurementFields;
index 1f5bedf..8c0c5bb 100644 (file)
 
 package org.o.ran.oam.nf.oam.adopter.pm.rest.manager.mapper;
 
-import com.fasterxml.jackson.core.JsonParser;
 import com.fasterxml.jackson.dataformat.csv.CsvMapper;
 import com.fasterxml.jackson.dataformat.csv.CsvSchema;
 import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
 import io.reactivex.rxjava3.core.Single;
+import java.io.BufferedReader;
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
 import java.io.IOException;
+import java.io.InputStreamReader;
+import java.nio.charset.StandardCharsets;
 import java.util.ArrayList;
 import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
+import java.util.concurrent.atomic.AtomicInteger;
 import java.util.zip.ZipEntry;
 import java.util.zip.ZipInputStream;
 import org.o.ran.oam.nf.oam.adopter.api.CommonEventFormat302ONAP;
 import org.o.ran.oam.nf.oam.adopter.api.Event;
 import org.o.ran.oam.nf.oam.adopter.pm.rest.manager.PerformanceManagementMapperConfigProvider;
+import org.o.ran.oam.nf.oam.adopter.pm.rest.manager.exceptions.PerformanceManagementException;
 import org.o.ran.oam.nf.oam.adopter.pm.rest.manager.pojos.CsvConfiguration;
 import org.o.ran.oam.nf.oam.adopter.pm.rest.manager.pojos.VesMappingConfiguration;
 import org.slf4j.Logger;
@@ -46,12 +52,21 @@ public class PerformanceManagementFile2VesMapper {
     private static final Logger LOG = LoggerFactory.getLogger(PerformanceManagementFile2VesMapper.class);
 
     private static final String CSV_EXTENSION = ".csv";
+    private static final CsvSchema schema = CsvSchema.emptySchema().withHeader();
     private final PerformanceManagementMapperConfigProvider pmConfigProvider;
     private static final int THRESHOLD_SIZE  = 1000000000; // 1 GB
+    private static final double THRESHOLD_RATIO = 40;
+    private static final int THRESHOLD_ENTRIES = 10000;
+    private static final int READ_BUFFER_SIZE = 2048;
+    private final CsvMapper mapper;
 
+    /**
+     * Default constructor.
+     */
     @Autowired
     public PerformanceManagementFile2VesMapper(final PerformanceManagementMapperConfigProvider pmConfigProvider) {
         this.pmConfigProvider = pmConfigProvider;
+        this.mapper = new CsvMapper();
     }
 
     /**
@@ -65,31 +80,36 @@ public class PerformanceManagementFile2VesMapper {
     public Single<List<CommonEventFormat302ONAP>> map(final ZipInputStream zipInputStream, final String hostIp) {
         LOG.info("Converting ZIP files to VES Message started");
         final List<CommonEventFormat302ONAP> listOfNotifications = new ArrayList<>();
-        final CsvSchema schema = CsvSchema.emptySchema().withHeader();
-        final CsvMapper mapper = new CsvMapper();
-        mapper.configure(JsonParser.Feature.AUTO_CLOSE_SOURCE, false);
+
         try {
+            var totalEntryArchive = 0;
+            final var totalSizeEntry = new AtomicInteger();
+
             ZipEntry entry;
-            final VesMappingConfiguration mappingConfiguration = pmConfigProvider.getVesMappingConfiguration();
+            final List<List<Event>> mappedEvents = new ArrayList<>();
             while ((entry = zipInputStream.getNextEntry()) != null) {
-                if (entry.getSize() > THRESHOLD_SIZE  || entry.getSize() == -1) {
-                    throw new IllegalStateException("File to be unzipped too big.");
-                }
                 final String entryName = entry.getName();
                 if (!entryName.endsWith(CSV_EXTENSION)) {
-                    return Single.error(new Exception("Wrong file type :" + entryName));
+                    throw new PerformanceManagementException("Wrong file type :" + entryName);
                 }
 
+                totalEntryArchive++;
+                if (totalEntryArchive > THRESHOLD_ENTRIES) {
+                    throw new PerformanceManagementException("Too many files: " + totalSizeEntry);
+                }
+
+                final BufferedReader reader = extract(zipInputStream, totalSizeEntry, entry.getCompressedSize());
                 final Iterator<Map<String, String>> iterator =
-                        mapper.readerFor(Map.class).with(schema).readValues(zipInputStream);
-                final List<List<Event>> mappedEvents = toEvent(mappingConfiguration, hostIp, iterator);
-
-                mappedEvents.forEach(mapped -> {
-                    final CommonEventFormat302ONAP eventFormat = new CommonEventFormat302ONAP();
-                    eventFormat.setEventList(mapped);
-                    listOfNotifications.add(eventFormat);
-                });
+                        mapper.readerFor(Map.class).with(schema).readValues(reader);
+                final var mappingConfiguration = pmConfigProvider.getVesMappingConfiguration();
+                mappedEvents.addAll(toEvent(mappingConfiguration, hostIp, iterator));
             }
+
+            mappedEvents.forEach(mapped -> {
+                final var eventFormat = new CommonEventFormat302ONAP();
+                eventFormat.setEventList(mapped);
+                listOfNotifications.add(eventFormat);
+            });
         } catch (final Exception e) {
             return Single.error(new Exception("Failed to process file", e));
         } finally {
@@ -103,15 +123,43 @@ public class PerformanceManagementFile2VesMapper {
         return Single.just(listOfNotifications);
     }
 
+    private BufferedReader extract(final ZipInputStream zis, final AtomicInteger totalSizeEntry,
+            final long compressedSize) throws PerformanceManagementException, IOException {
+        final var out = new ByteArrayOutputStream();
+        final var buffer = new byte[READ_BUFFER_SIZE];
+        int len;
+
+        while (zis.available() > 0) {
+            len = zis.read(buffer);
+            final int currentSize = totalSizeEntry.addAndGet(len);
+
+            if (currentSize > THRESHOLD_SIZE) {
+                throw new PerformanceManagementException("ZIP file too big.");
+            }
+
+            final double compressionRatio = (double) currentSize / compressedSize;
+            if (compressionRatio > THRESHOLD_RATIO) {
+                throw new PerformanceManagementException("Wrong file type, threshold to high " + compressionRatio);
+            }
+
+            if (len > 0) {
+                out.write(buffer, 0, len);
+            }
+        }
+
+        return new BufferedReader(
+                new InputStreamReader(new ByteArrayInputStream(out.toByteArray()), StandardCharsets.UTF_8));
+    }
+
     private static List<List<Event>> toEvent(final VesMappingConfiguration mappingConfiguration, final String hostIp,
             final Iterator<Map<String, String>> iterator) {
         final List<List<Event>> globalList = new ArrayList<>();
         final int batchSize = mappingConfiguration.getBatchSize();
-        int sequence = 0;
+        var sequence = 0;
         List<Event> events = new ArrayList<>();
         final CsvConfiguration csv = mappingConfiguration.getCsv();
         while (iterator.hasNext()) {
-            final Event event = new Event();
+            final var event = new Event();
             final Map<String, String> recordMap = iterator.next();
             event.setCommonEventHeader(CommonEventHeaderHandler.toCommonEventHeader(mappingConfiguration, hostIp, csv,
                 recordMap,  sequence));
index 2c0cab7..cbea02f 100644 (file)
@@ -34,7 +34,6 @@ import java.time.format.DateTimeFormatter;
 import java.util.concurrent.ExecutionException;
 import java.util.concurrent.TimeUnit;
 import java.util.zip.ZipInputStream;
-import org.apache.hc.client5.http.async.methods.SimpleHttpRequest;
 import org.apache.hc.client5.http.async.methods.SimpleHttpRequests;
 import org.apache.hc.client5.http.async.methods.SimpleHttpResponse;
 import org.apache.hc.client5.http.impl.async.CloseableHttpAsyncClient;
@@ -105,7 +104,7 @@ public final class DefaultHttpRestClient implements HttpRestClient {
     @Override
     public Single<ZoneId> getTimeZone(final Adapter adapter) {
         try {
-            final ZoneId zoneId = zoneIdCache.get(adapter);
+            final var zoneId = zoneIdCache.get(adapter);
             final String offset = OFFSET_FORMATTER.format(zoneId.getRules().getOffset(Instant.now()));
             LOG.info("Adapter {} has offset {}", adapter.getHostIpAddress(), offset);
             return Single.just(zoneId);
@@ -126,8 +125,7 @@ public final class DefaultHttpRestClient implements HttpRestClient {
      */
     public Single<SimpleHttpResponse> get(final Adapter adapter, final String url) {
         return getToken(adapter).flatMap(token -> {
-            final SimpleHttpRequest request =
-                SimpleHttpRequests.get(HTTPS + adapter.getHostIpAddress() + url);
+            final var request = SimpleHttpRequests.get(HTTPS + adapter.getHostIpAddress() + url);
             request.addHeader(HttpHeaders.CONTENT_TYPE, APPLICATION_JSON_VALUE);
             request.addHeader(HttpHeaders.AUTHORIZATION, BEARER + token);
             return Single.fromFuture(client.execute(request, null))
index a9fae30..5a47591 100644 (file)
@@ -53,8 +53,8 @@ public final class DownloadPerformanceManagementFilesHandler {
     }
 
     private static Single<SimpleBody> validateGetZipFile(final Adapter adapter, final SimpleHttpResponse response) {
-        final String statusLine = new StatusLine(response).toString();
-        final ContentType contentType = response.getContentType();
+        final var statusLine = new StatusLine(response).toString();
+        final var contentType = response.getContentType();
         final SimpleBody entity = response.getBody();
         if (response.getCode() == HttpStatus.SC_OK && entity != null && ContentType.APPLICATION_OCTET_STREAM
             .getMimeType().equals(contentType.getMimeType())) {
index 26c62b5..a154d11 100644 (file)
@@ -8,7 +8,6 @@ import java.util.Base64;
 import java.util.concurrent.ExecutionException;
 import lombok.AccessLevel;
 import lombok.NoArgsConstructor;
-import org.apache.hc.client5.http.async.methods.SimpleHttpRequest;
 import org.apache.hc.client5.http.async.methods.SimpleHttpRequests;
 import org.apache.hc.client5.http.async.methods.SimpleHttpResponse;
 import org.apache.hc.client5.http.impl.async.CloseableHttpAsyncClient;
@@ -31,15 +30,15 @@ public final class TokenHandler {
     public static synchronized String returnToken(final CloseableHttpAsyncClient client, final String tokenEndpoint,
             final Adapter adapter) throws ExecutionException, InterruptedException {
         final String host = HTTPS + adapter.getHostIpAddress();
-        final SimpleHttpRequest request = SimpleHttpRequests.post(host + tokenEndpoint);
-        final String basicAuth = Base64.getEncoder().encodeToString(
+        final var request = SimpleHttpRequests.post(host + tokenEndpoint);
+        final var basicAuth = Base64.getEncoder().encodeToString(
                 (adapter.getUsername() + ":" + adapter.getPassword()).getBytes(StandardCharsets.UTF_8));
         request.setHeader(HttpHeaders.AUTHORIZATION, "Basic " + basicAuth);
         request.addHeader(HttpHeaders.CONTENT_TYPE, APPLICATION_JSON_VALUE);
         request.addHeader(HttpHeaders.ACCEPT, APPLICATION_JSON_VALUE);
 
         final SimpleHttpResponse response = client.execute(request, null).get();
-        final String statusLine = new StatusLine(response).toString();
+        final var statusLine = new StatusLine(response).toString();
         if (response.getCode() != HttpStatus.SC_OK) {
             throw new TokenGenerationException("Failed to obtain a token for host " + host + ": " + statusLine);
         }
index 4088e05..8285a0b 100644 (file)
@@ -177,4 +177,10 @@ class DefaultHttpRestClientTest {
         observer.assertError(throwable -> throwable.getMessage()
             .equals("Get Zone offset failed for 150.62.25.26 . Empty output received"));
     }
+
+    @Test
+    void testGetTimeOffsetFailExecutionException() {
+        final TestObserver<ZoneId> observer = restClient.getTimeZone(ADAPTER).test();
+        observer.assertError(throwable -> throwable.getMessage().equals("Failed to get Zone ID for 150.62.25.26"));
+    }
 }
\ No newline at end of file
diff --git a/ves-nf-oam-adopter/ves-nf-oam-adopter-snmp-manager/src/main/java/org/o/ran/oam/nf/oam/adopter/snmp/manager/SnmpCommandResponder.java b/ves-nf-oam-adopter/ves-nf-oam-adopter-snmp-manager/src/main/java/org/o/ran/oam/nf/oam/adopter/snmp/manager/SnmpCommandResponder.java
new file mode 100644 (file)
index 0000000..3e4d462
--- /dev/null
@@ -0,0 +1,71 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  O-RAN-SC
+ *  ================================================================================
+ *  Copyright © 2021 AT&T Intellectual Property. All rights reserved.
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *  ============LICENSE_END=========================================================
+ */
+
+package org.o.ran.oam.nf.oam.adopter.snmp.manager;
+
+import java.time.LocalDateTime;
+import java.util.Optional;
+import org.o.ran.oam.nf.oam.adopter.api.VesEventNotifier;
+import org.o.ran.oam.nf.oam.adopter.snmp.manager.api.TimeZoneOffsetService;
+import org.o.ran.oam.nf.oam.adopter.snmp.manager.mapper.SnmpMapper;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.snmp4j.CommandResponder;
+import org.snmp4j.CommandResponderEvent;
+import org.snmp4j.smi.UdpAddress;
+
+class SnmpCommandResponder implements CommandResponder {
+
+    private static final Logger LOG = LoggerFactory.getLogger(SnmpCommandResponder.class);
+    private final TimeZoneOffsetService timeZoneOffsetService;
+    private final SnmpMapper mapper;
+    private final VesEventNotifier vesEventNotifier;
+
+    public SnmpCommandResponder(final TimeZoneOffsetService timeZoneOffsetService, final SnmpMapper mapper,
+            final VesEventNotifier vesEventNotifier) {
+        this.timeZoneOffsetService = timeZoneOffsetService;
+        this.mapper = mapper;
+        this.vesEventNotifier = vesEventNotifier;
+    }
+
+    /**
+     * This method will be called whenever a pdu is received on the given port
+     * specified in the listen() method.
+     */
+    @Override
+    public synchronized void processPdu(final CommandResponderEvent cmdRespEvent) {
+        LOG.info("Received PDU");
+        final var pdu = cmdRespEvent.getPDU();
+        if (pdu == null) {
+            LOG.warn("Ignoring PDU.");
+            return;
+        }
+
+        final UdpAddress address = (UdpAddress) cmdRespEvent.getPeerAddress();
+        final var optZoneId = timeZoneOffsetService.getTimeZone(address.getInetAddress().getHostAddress());
+        final String timeZone = Optional.ofNullable(optZoneId)
+                                        .map(zoneId -> "UTC" + LocalDateTime.now().atZone(zoneId).getOffset()
+                                                                       .toString()).orElse(null);
+
+        mapper.toEvent(address, timeZone, pdu).flatMapCompletable(vesEventNotifier::notifyEvents)
+                .doOnSubscribe(result -> LOG.debug("SNMP Trap processing started"))
+                .doOnComplete(() -> LOG.debug("SNMP Trap processed successfully"))
+                .doOnError(error -> LOG.error("Failed to process SNMP Trap", error)).subscribe();
+    }
+}
@@ -24,17 +24,16 @@ import org.o.ran.oam.nf.oam.adopter.api.VesEventNotifier;
 import org.o.ran.oam.nf.oam.adopter.snmp.manager.api.TimeZoneOffsetService;
 import org.o.ran.oam.nf.oam.adopter.snmp.manager.mapper.SnmpMapper;
 
-public class SnmpManagerImpl implements AutoCloseable {
+public class SnmpManager implements AutoCloseable {
     private static final String SNMP_MANAGER_THREAD = "SnmpManager";
     private final Thread snmpThread;
 
     /**
      * Default constructor.
      */
-    public SnmpManagerImpl(final String host, final int port, final SnmpMapper mapper,
+    public SnmpManager(final String host, final int port, final SnmpMapper mapper,
             final VesEventNotifier vesEventNotifier, final TimeZoneOffsetService timeZoneOffsetService) {
-        final SnmpTrapListener trapListener =
-                new SnmpTrapListener(host, port, mapper, vesEventNotifier, timeZoneOffsetService);
+        final var trapListener = new SnmpTrapListener(host, port, mapper, vesEventNotifier, timeZoneOffsetService);
         this.snmpThread = new Thread(trapListener, SNMP_MANAGER_THREAD);
     }
 
index 9797e5c..54b92e8 100644 (file)
 
 package org.o.ran.oam.nf.oam.adopter.snmp.manager;
 
-import static java.util.Objects.requireNonNull;
-
-import com.fasterxml.jackson.databind.ObjectMapper;
-import com.fasterxml.jackson.dataformat.yaml.YAMLFactory;
-import java.io.IOException;
-import java.io.StringWriter;
-import java.net.URI;
-import java.nio.file.Paths;
-import javax.annotation.PostConstruct;
-import org.apache.commons.configuration2.YAMLConfiguration;
-import org.apache.commons.configuration2.builder.ConfigurationBuilderEvent;
-import org.apache.commons.configuration2.builder.ReloadingFileBasedConfigurationBuilder;
-import org.apache.commons.configuration2.builder.fluent.Parameters;
-import org.apache.commons.configuration2.ex.ConfigurationException;
 import org.o.ran.oam.nf.oam.adopter.snmp.manager.pojos.VesMappingConfiguration;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
+import org.o.ran.oam.nf.oam.adopter.spi.MapperConfigProvider;
 import org.springframework.beans.factory.annotation.Value;
 import org.springframework.stereotype.Service;
 
@@ -43,41 +28,18 @@ import org.springframework.stereotype.Service;
  * Reads and listens for changes on snmp mapping configuration.
  */
 @Service
-public class SnmpMappingConfigurationProvider {
-    private static final Logger LOG = LoggerFactory.getLogger(SnmpMappingConfigurationProvider.class);
+public class SnmpMappingConfigurationProvider extends MapperConfigProvider<VesMappingConfiguration> {
 
-    private static final ObjectMapper YAML_READER = new ObjectMapper(new YAMLFactory());
     @Value("${snmp-manager.mapping-config-path:#{null}}")
     private String mappingFilePath;
-    private ReloadingFileBasedConfigurationBuilder<YAMLConfiguration> builder;
 
-    /**
-     * Initialize service.
-     * @throws IOException on error
-     */
-    @PostConstruct
-    public void init() throws IOException, ConfigurationException {
-        requireNonNull(mappingFilePath);
-        final URI filePath = Paths.get(mappingFilePath).toUri();
-        builder = new ReloadingFileBasedConfigurationBuilder<>(YAMLConfiguration.class)
-                .configure(new Parameters().hierarchical().setURL(filePath.toURL()));
-        builder.addEventListener(ConfigurationBuilderEvent.CONFIGURATION_REQUEST, event -> {
-            builder.getReloadingController().checkForReloading(null);
-            LOG.info("Reloading {}", filePath);
-        });
-        //Test initial configuration
-        builder.getConfiguration();
+    @Override
+    public String getMappingFilePath() {
+        return mappingFilePath;
     }
 
-    /**
-     * Reads VesMappingConfiguration from yaml file.
-     *
-     * @return Ves Mapping Configuration
-     */
-    public VesMappingConfiguration getVesMappingConfiguration() throws ConfigurationException, IOException {
-        final YAMLConfiguration configuration = builder.getConfiguration();
-        final StringWriter output = new StringWriter();
-        configuration.write(output);
-        return YAML_READER.readValue(output.toString(), VesMappingConfiguration.class);
+    @Override
+    public Class<VesMappingConfiguration> getClazz() {
+        return VesMappingConfiguration.class;
     }
 }
index eead114..6c75680 100644 (file)
 
 package org.o.ran.oam.nf.oam.adopter.snmp.manager;
 
-import com.google.gson.Gson;
-import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
 import java.io.IOException;
-import java.time.LocalDateTime;
-import java.time.ZoneId;
-import java.util.Optional;
 import org.o.ran.oam.nf.oam.adopter.api.VesEventNotifier;
 import org.o.ran.oam.nf.oam.adopter.snmp.manager.api.TimeZoneOffsetService;
 import org.o.ran.oam.nf.oam.adopter.snmp.manager.mapper.SnmpMapper;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
-import org.snmp4j.CommandResponder;
-import org.snmp4j.CommandResponderEvent;
 import org.snmp4j.MessageDispatcher;
 import org.snmp4j.MessageDispatcherImpl;
-import org.snmp4j.PDU;
 import org.snmp4j.Snmp;
 import org.snmp4j.mp.MPv2c;
 import org.snmp4j.smi.UdpAddress;
@@ -42,32 +34,25 @@ import org.snmp4j.transport.DefaultUdpTransportMapping;
 import org.snmp4j.util.MultiThreadedMessageDispatcher;
 import org.snmp4j.util.ThreadPool;
 
-final class SnmpTrapListener implements CommandResponder, Runnable {
+final class SnmpTrapListener implements Runnable {
 
     private static final Logger LOG = LoggerFactory.getLogger(SnmpTrapListener.class);
     private static final int THREADS_SIZE = 2;
     private final String hostPortAddress;
-    private final SnmpMapper mapper;
-    private final VesEventNotifier vesEventNotifier;
-    private final Gson gson = new Gson();
-    private final TimeZoneOffsetService timeZoneOffsetService;
+    private final SnmpCommandResponder commandResponder;
 
     public SnmpTrapListener(final String host, final Integer port, final SnmpMapper mapper,
             final VesEventNotifier vesEventNotifier, final TimeZoneOffsetService timeZoneOffsetService) {
         LOG.info("SnmpTrapListener listening on {}:{}", host, port);
         this.hostPortAddress = host + "/" + port;
-        this.mapper = mapper;
-        this.vesEventNotifier = vesEventNotifier;
-        this.timeZoneOffsetService = timeZoneOffsetService;
+        this.commandResponder = new SnmpCommandResponder(timeZoneOffsetService, mapper, vesEventNotifier);
     }
 
     @Override
     public synchronized void run() {
-        try (final DefaultUdpTransportMapping snmpTarget = new DefaultUdpTransportMapping(
-                new UdpAddress(hostPortAddress))) {
-            final ThreadPool threadPool = ThreadPool.create("SNMP_V2_Listener", THREADS_SIZE);
-            final MessageDispatcher dispatcher =
-                    new MultiThreadedMessageDispatcher(threadPool, new MessageDispatcherImpl());
+        try (final var snmpTarget = new DefaultUdpTransportMapping(new UdpAddress(hostPortAddress))) {
+            final var threadPool = ThreadPool.create("SNMP_V2_Listener", THREADS_SIZE);
+            final var dispatcher = new MultiThreadedMessageDispatcher(threadPool, new MessageDispatcherImpl());
             dispatcher.addMessageProcessingModel(new MPv2c());
             listenSnmp(dispatcher, snmpTarget);
         } catch (final IOException e) {
@@ -75,42 +60,17 @@ final class SnmpTrapListener implements CommandResponder, Runnable {
         }
     }
 
-    @SuppressFBWarnings("WA_NOT_IN_LOOP")
     private synchronized void listenSnmp(final MessageDispatcher dispatcher,
             final DefaultUdpTransportMapping snmpTarget) {
-        try (final Snmp snmp = new Snmp(dispatcher, snmpTarget)) {
-            snmp.addCommandResponder(this);
-            snmpTarget.listen();
-            LOG.debug("Listening on {}", snmpTarget);
-            wait();
-        } catch (final InterruptedException | IOException ex) {
-            Thread.currentThread().interrupt();
-        }
-    }
-
-    /**
-     * This method will be called whenever a pdu is received on the given port
-     * specified in the listen() method.
-     */
-    @Override
-    public synchronized void processPdu(final CommandResponderEvent cmdRespEvent) {
-        LOG.info("Received PDU");
-        final PDU pdu = cmdRespEvent.getPDU();
-        if (pdu == null) {
-            LOG.warn("Ignoring PDU.");
-            return;
-        }
-
-        final UdpAddress address = (UdpAddress) cmdRespEvent.getPeerAddress();
-        final ZoneId optZoneId = timeZoneOffsetService.getTimeZone(address.getInetAddress().getHostAddress());
-        final String timeZone = Optional.ofNullable(optZoneId)
-            .map(zoneId -> "UTC" + LocalDateTime.now().atZone(zoneId).getOffset().toString()).orElse(null);
-
-        mapper.toEvent(address, timeZone, pdu)
-                .flatMapCompletable(vesEventNotifier::notifyEvents)
-                .doOnSubscribe(result -> LOG.debug("SNMP Trap processing started"))
-                .doOnComplete(() -> LOG.debug("SNMP Trap processed successfully"))
-                .doOnError(error -> LOG.error("Failed to process SNMP Trap", error))
-                .subscribe();
+        do {
+            try (final var snmp = new Snmp(dispatcher, snmpTarget)) {
+                snmp.addCommandResponder(commandResponder);
+                snmpTarget.listen();
+                LOG.debug("Listening on {}", snmpTarget);
+                wait();
+            } catch (final InterruptedException | IOException ex) {
+                Thread.currentThread().interrupt();
+            }
+        } while (snmpTarget.isListening());
     }
 }
index a39a52f..88409e9 100644 (file)
@@ -20,7 +20,7 @@
 package org.o.ran.oam.nf.oam.adopter.snmp.manager.configurations;
 
 import org.o.ran.oam.nf.oam.adopter.api.VesEventNotifier;
-import org.o.ran.oam.nf.oam.adopter.snmp.manager.SnmpManagerImpl;
+import org.o.ran.oam.nf.oam.adopter.snmp.manager.SnmpManager;
 import org.o.ran.oam.nf.oam.adopter.snmp.manager.api.TimeZoneOffsetService;
 import org.o.ran.oam.nf.oam.adopter.snmp.manager.mapper.SnmpMapper;
 import org.o.ran.oam.nf.oam.adopter.snmp.manager.properties.SnmpManagerProperties;
@@ -50,8 +50,8 @@ public class SnmpManagerConfig {
     }
 
     @Bean
-    public SnmpManagerImpl getSnmpManagerService() {
-        return new SnmpManagerImpl(snmpManagerProperties.getHost(), snmpManagerProperties.getPort(), snmpMapper,
+    public SnmpManager getSnmpManagerService() {
+        return new SnmpManager(snmpManagerProperties.getHost(), snmpManagerProperties.getPort(), snmpMapper,
                 vesEventNotifier, timeZoneOffsetService);
     }
 }
index c2d052c..cd34be8 100644 (file)
@@ -39,7 +39,7 @@ final class CommonEventHeaderHandler {
     static CommonEventHeader toCommonEventHeader(final UdpAddress peerAddress,
             final VesMappingConfiguration vesMappingConfig, final TrapsMappingConfiguration mappingConfiguration,
             final PDU pdu, final String timeZone) {
-        final CommonEventHeader header = new CommonEventHeader();
+        final var header = new CommonEventHeader();
         setMandatoryFields(header, peerAddress, vesMappingConfig, mappingConfiguration, pdu);
         setOptionalFields(header, vesMappingConfig, mappingConfiguration, pdu, timeZone);
         return header;
@@ -51,7 +51,7 @@ final class CommonEventHeaderHandler {
         header.setNfVendorName(vesMappingConfig.getNfVendorName());
         final String oidEntityId = mappingConfiguration.getOidReportingEntityID();
         if (oidEntityId != null) {
-            final Variable uuid = pdu.getVariable(new OID(oidEntityId));
+            final var uuid = pdu.getVariable(new OID(oidEntityId));
             header.setReportingEntityId(uuid == null ? null : uuid.toString());
         }
         header.setNfNamingCode(null); //NOP
@@ -76,7 +76,7 @@ final class CommonEventHeaderHandler {
 
         final String oidStartEpoch = mappingConfiguration.getEventStartEpochMicrosec();
         if (oidStartEpoch != null) {
-            final Variable uuid = pdu.getVariable(new OID(oidStartEpoch));
+            final var uuid = pdu.getVariable(new OID(oidStartEpoch));
             header.setStartEpochMicrosec(uuid == null ? null : Long.valueOf(uuid.toString()));
         } else {
             header.setStartEpochMicrosec(System.currentTimeMillis());
@@ -84,7 +84,7 @@ final class CommonEventHeaderHandler {
 
         final String oidLastEpoch = mappingConfiguration.getEventLastEpochMicrosec();
         if (oidLastEpoch != null) {
-            final Variable uuid = pdu.getVariable(new OID(oidLastEpoch));
+            final var uuid = pdu.getVariable(new OID(oidLastEpoch));
             header.setLastEpochMicrosec(uuid == null ? null : Long.valueOf(uuid.toString()));
         } else {
             header.setLastEpochMicrosec(System.currentTimeMillis());
@@ -95,7 +95,7 @@ final class CommonEventHeaderHandler {
         header.setSequence(extractEventSequence(mappingConfiguration, pdu));
         final String oidSourceName = mappingConfiguration.getOidSourceName();
         if (oidSourceName != null) {
-            final Variable sourceName = pdu.getVariable(new OID(oidSourceName));
+            final var sourceName = pdu.getVariable(new OID(oidSourceName));
             header.setSourceName(sourceName.toString());
         } else {
             header.setSourceName(peerAddress.getInetAddress().getHostAddress());
index 600f503..acec2d8 100644 (file)
@@ -31,7 +31,6 @@ import org.o.ran.oam.nf.oam.adopter.api.FaultFields;
 import org.o.ran.oam.nf.oam.adopter.snmp.manager.pojos.TrapsMappingConfiguration;
 import org.snmp4j.PDU;
 import org.snmp4j.smi.OID;
-import org.snmp4j.smi.Variable;
 import org.snmp4j.smi.VariableBinding;
 
 @NoArgsConstructor(access = AccessLevel.PRIVATE)
@@ -40,7 +39,7 @@ final class FaultFieldsHandler {
     private static final String SNMP_UNKNOWN = "Unknown";
 
     public static FaultFields toFaultFields(final TrapsMappingConfiguration trapsDescription, final PDU pdu) {
-        final FaultFields faultFields = new FaultFields();
+        final var faultFields = new FaultFields();
         setMandatoryFields(faultFields, trapsDescription, pdu);
         setOptionalFields(faultFields, trapsDescription, pdu);
         return faultFields;
@@ -55,7 +54,7 @@ final class FaultFieldsHandler {
         final String descOid = trapsDescription.getOidSpecificProblemDesc();
         faultFields.setSpecificProblem(SNMP_FAULT);
         if (descOid != null && !DEFAULT.equals(descOid)) {
-            final Variable desc = pdu.getVariable(new OID(descOid));
+            final var desc = pdu.getVariable(new OID(descOid));
             faultFields.setSpecificProblem(desc == null ? SNMP_FAULT : desc.toString());
         }
         faultFields.setVfStatus(FaultFields.VfStatus.ACTIVE);
@@ -70,7 +69,7 @@ final class FaultFieldsHandler {
         faultFields.setAlarmAdditionalInformation(map.isEmpty() ? null : map);
         final String interfaceOid = trapsDescription.getOidAlarmInterfaceName();
         if (interfaceOid != null) {
-            final Variable desc = pdu.getVariable(new OID(interfaceOid));
+            final var desc = pdu.getVariable(new OID(interfaceOid));
             faultFields.setAlarmInterfaceA(desc == null ? SNMP_FAULT : desc.toString());
         }
         final String eCategory = trapsDescription.getEventCategory();
index 901ac2f..b777d79 100644 (file)
@@ -28,7 +28,6 @@ import org.o.ran.oam.nf.oam.adopter.api.CommonEventFormat302ONAP;
 import org.o.ran.oam.nf.oam.adopter.api.Event;
 import org.o.ran.oam.nf.oam.adopter.snmp.manager.SnmpMappingConfigurationProvider;
 import org.o.ran.oam.nf.oam.adopter.snmp.manager.pojos.TrapsMappingConfiguration;
-import org.o.ran.oam.nf.oam.adopter.snmp.manager.pojos.VesMappingConfiguration;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.snmp4j.PDU;
@@ -60,10 +59,9 @@ public class SnmpMapperImpl implements SnmpMapper {
             }
             LOG.info("Starting Mapping of SNMP Event.");
             LOG.trace("Pdu received {}.", pdu);
-            final Event event = new Event();
-            final String trapOidVariable = pdu.getVariable(SNMP_TRAP_OID).toString();
-            final VesMappingConfiguration vesMappingConfig =
-                    snmpMappingConfigurationProvider.getVesMappingConfiguration();
+            final var event = new Event();
+            final var trapOidVariable = pdu.getVariable(SNMP_TRAP_OID).toString();
+            final var vesMappingConfig = snmpMappingConfigurationProvider.getVesMappingConfiguration();
             final Map<String, TrapsMappingConfiguration> trapsDescriptions = vesMappingConfig.getTraps().stream()
                     .collect(Collectors.toMap(TrapsMappingConfiguration::getOid, trapsDescription -> trapsDescription));
             final TrapsMappingConfiguration trapsDescription =
@@ -71,7 +69,7 @@ public class SnmpMapperImpl implements SnmpMapper {
             event.setCommonEventHeader(CommonEventHeaderHandler.toCommonEventHeader(peerAddress, vesMappingConfig,
                     trapsDescription, pdu, timeZone));
             event.setFaultFields(FaultFieldsHandler.toFaultFields(trapsDescription, pdu));
-            final CommonEventFormat302ONAP eventFormat = new CommonEventFormat302ONAP();
+            final var eventFormat = new CommonEventFormat302ONAP();
             eventFormat.setEvent(event);
             eventFormat.setEventList(null);
             LOG.info("Mapping of SNMP Event type {} finished.", eventType);
index 913c3b6..091c783 100644 (file)
@@ -47,7 +47,7 @@ class SnmpManagerTest {
     @Autowired
     private SnmpManagerProperties snmpManagerProperties;
     @Autowired
-    private SnmpManagerImpl snmpManager;
+    private SnmpManager snmpManager;
     @MockBean
     private TimeZoneOffsetService timeZoneOffsetService;