Merge changes from topic "nbinotification"
authorGuillaume Lambert <guillaume.lambert@orange.com>
Mon, 15 Mar 2021 09:15:15 +0000 (09:15 +0000)
committerGerrit Code Review <gerrit@opendaylight.org>
Mon, 15 Mar 2021 09:15:15 +0000 (09:15 +0000)
* changes:
  Dmaap client as a karaf feature
  Dmaap client
  Add tests for service Notifications
  Update ServiceHandler to send service notification
  Improve lighty format message
  Fix a few typo in lighty main
  NBI Notifications as karaf feature
  Add new Maven module to manage NBI Notifications

68 files changed:
api/src/main/yang/nbi-notifications@2020-11-30.yang [new file with mode: 0644]
dmaap-client/pom.xml [new file with mode: 0644]
dmaap-client/src/main/java/org/opendaylight/transportpce/dmaap/client/impl/DmaapClientProvider.java [new file with mode: 0644]
dmaap-client/src/main/java/org/opendaylight/transportpce/dmaap/client/listener/NbiNotificationsListenerImpl.java [new file with mode: 0644]
dmaap-client/src/main/java/org/opendaylight/transportpce/dmaap/client/resource/EventsApi.java [new file with mode: 0644]
dmaap-client/src/main/java/org/opendaylight/transportpce/dmaap/client/resource/config/JsonConfigurator.java [new file with mode: 0644]
dmaap-client/src/main/java/org/opendaylight/transportpce/dmaap/client/resource/config/LgxSerializer.java [new file with mode: 0644]
dmaap-client/src/main/java/org/opendaylight/transportpce/dmaap/client/resource/config/PortSerializer.java [new file with mode: 0644]
dmaap-client/src/main/java/org/opendaylight/transportpce/dmaap/client/resource/config/PublishNotificationServiceModule.java [new file with mode: 0644]
dmaap-client/src/main/java/org/opendaylight/transportpce/dmaap/client/resource/config/PublishNotificationServiceSerializer.java [new file with mode: 0644]
dmaap-client/src/main/java/org/opendaylight/transportpce/dmaap/client/resource/config/RxDirectionSerializer.java [new file with mode: 0644]
dmaap-client/src/main/java/org/opendaylight/transportpce/dmaap/client/resource/config/ServiceAEndSerializer.java [new file with mode: 0644]
dmaap-client/src/main/java/org/opendaylight/transportpce/dmaap/client/resource/config/ServiceZEndSerializer.java [new file with mode: 0644]
dmaap-client/src/main/java/org/opendaylight/transportpce/dmaap/client/resource/config/TxDirectionSerializer.java [new file with mode: 0644]
dmaap-client/src/main/java/org/opendaylight/transportpce/dmaap/client/resource/model/CreatedEvent.java [new file with mode: 0644]
dmaap-client/src/main/resources/OSGI-INF/blueprint/dmaap-blueprint.xml [new file with mode: 0644]
dmaap-client/src/test/java/org/opendaylight/transportpce/dmaap/client/impl/DmaapClientProviderTest.java [new file with mode: 0644]
dmaap-client/src/test/java/org/opendaylight/transportpce/dmaap/client/listener/NbiNotificationsListenerImplTest.java [new file with mode: 0644]
dmaap-client/src/test/java/org/opendaylight/transportpce/dmaap/client/resource/EventsApiStub.java [new file with mode: 0644]
features/odl-transportpce-dmaap-client/pom.xml [new file with mode: 0644]
features/odl-transportpce-dmaap-client/src/main/feature/feature.xml [new file with mode: 0644]
features/odl-transportpce-dmaap-client/src/main/resources/org.opendaylight.transportpce.dmaap.cfg [new file with mode: 0644]
features/odl-transportpce-nbinotifications/pom.xml [new file with mode: 0644]
features/odl-transportpce-nbinotifications/src/main/feature/feature.xml [new file with mode: 0644]
features/odl-transportpce-nbinotifications/src/main/resources/org.opendaylight.transportpce.nbinotifications.cfg [new file with mode: 0644]
features/pom.xml
karaf/pom.xml
lighty/pom.xml
lighty/src/main/java/io/lighty/controllers/tpce/Main.java
lighty/src/main/java/io/lighty/controllers/tpce/module/TransportPCEImpl.java
lighty/src/main/java/io/lighty/controllers/tpce/utils/TPCEUtils.java
lighty/src/test/java/io/lighty/controllers/tpce/MaintTest.java
nbinotifications/pom.xml [new file with mode: 0644]
nbinotifications/src/main/java/org/opendaylight/transportpce/nbinotifications/consumer/Subscriber.java [new file with mode: 0644]
nbinotifications/src/main/java/org/opendaylight/transportpce/nbinotifications/impl/NbiNotificationsImpl.java [new file with mode: 0644]
nbinotifications/src/main/java/org/opendaylight/transportpce/nbinotifications/impl/NbiNotificationsProvider.java [new file with mode: 0644]
nbinotifications/src/main/java/org/opendaylight/transportpce/nbinotifications/listener/NbiNotificationsListenerImpl.java [new file with mode: 0644]
nbinotifications/src/main/java/org/opendaylight/transportpce/nbinotifications/producer/Publisher.java [new file with mode: 0644]
nbinotifications/src/main/java/org/opendaylight/transportpce/nbinotifications/serialization/ConfigConstants.java [new file with mode: 0644]
nbinotifications/src/main/java/org/opendaylight/transportpce/nbinotifications/serialization/NotificationServiceDeserializer.java [new file with mode: 0644]
nbinotifications/src/main/java/org/opendaylight/transportpce/nbinotifications/serialization/NotificationServiceSerializer.java [new file with mode: 0644]
nbinotifications/src/main/java/org/opendaylight/transportpce/nbinotifications/utils/NbiNotificationsUtils.java [new file with mode: 0644]
nbinotifications/src/main/resources/OSGI-INF/blueprint/nobinotifications-blueprint.xml [new file with mode: 0644]
nbinotifications/src/main/resources/publisher.properties [new file with mode: 0644]
nbinotifications/src/main/resources/subscriber.properties [new file with mode: 0644]
nbinotifications/src/test/java/org/opendaylight/transportpce/nbinotifications/consumer/SubscriberTest.java [new file with mode: 0644]
nbinotifications/src/test/java/org/opendaylight/transportpce/nbinotifications/impl/NbiNotificationsImplTest.java [new file with mode: 0644]
nbinotifications/src/test/java/org/opendaylight/transportpce/nbinotifications/impl/NbiNotificationsProviderTest.java [new file with mode: 0644]
nbinotifications/src/test/java/org/opendaylight/transportpce/nbinotifications/listener/NbiNotificationsListenerImplTest.java [new file with mode: 0644]
nbinotifications/src/test/java/org/opendaylight/transportpce/nbinotifications/producer/PublisherTest.java [new file with mode: 0644]
nbinotifications/src/test/java/org/opendaylight/transportpce/nbinotifications/serialization/NotificationServiceDeserializerTest.java [new file with mode: 0644]
nbinotifications/src/test/java/org/opendaylight/transportpce/nbinotifications/serialization/NotificationServiceSerializerTest.java [new file with mode: 0644]
nbinotifications/src/test/java/org/opendaylight/transportpce/nbinotifications/utils/NotificationServiceDataUtils.java [new file with mode: 0644]
nbinotifications/src/test/resources/event.json [new file with mode: 0644]
nbinotifications/src/test/resources/expected_event.json [new file with mode: 0644]
nbinotifications/src/test/resources/publisher.properties [new file with mode: 0644]
nbinotifications/src/test/resources/subscriber.properties [new file with mode: 0644]
pom.xml
servicehandler/src/main/java/org/opendaylight/transportpce/servicehandler/impl/ServicehandlerImpl.java
servicehandler/src/main/java/org/opendaylight/transportpce/servicehandler/impl/ServicehandlerProvider.java
servicehandler/src/main/java/org/opendaylight/transportpce/servicehandler/listeners/PceListenerImpl.java
servicehandler/src/main/java/org/opendaylight/transportpce/servicehandler/listeners/RendererListenerImpl.java
servicehandler/src/main/resources/OSGI-INF/blueprint/servicehandler-blueprint.xml
servicehandler/src/test/java/org/opendaylight/transportpce/servicehandler/impl/ServicehandlerImplTest.java
tests/nbinotifications/docker-compose.yml [new file with mode: 0644]
tests/transportpce_tests/2.2.1/test_nbinotifications.py [new file with mode: 0644]
tests/transportpce_tests/common/test_utils.py
tox.ini

diff --git a/api/src/main/yang/nbi-notifications@2020-11-30.yang b/api/src/main/yang/nbi-notifications@2020-11-30.yang
new file mode 100644 (file)
index 0000000..aa068cd
--- /dev/null
@@ -0,0 +1,120 @@
+module nbi-notifications {
+  yang-version 1;
+  namespace "nbi-notifications";
+  prefix nbinotifications;
+
+  import org-openroadm-service {
+    prefix oor-service;
+    revision-date 2019-05-31;
+  }
+  import org-openroadm-common-service-types {
+    prefix org-openroadm-common-service-types;
+    revision-date 2019-05-31;
+  }
+  import org-openroadm-common-state-types {
+    prefix org-openroadm-common-state-types;
+    revision-date 2018-11-30;
+  }
+
+  organization
+    "transportPCE";
+  contact
+    "transportPCE committers - ODL";
+  description
+    "YANG definitions for using REST API in NBI notifications module. Copyright
+     (c) 2020 ORANGE and others. All rights reserved.";
+
+  revision 2020-11-30 {
+    description
+      "Initial revision of NBI notifications";
+  }
+
+  grouping notification-service {
+    leaf message {
+      type string;
+      mandatory true;
+      description
+        "Message for the specified service";
+    }
+    leaf service-name {
+      type string;
+      mandatory true;
+      description
+        "Identifier for the service to be created in the ROADM network, e.g., CLFI, CLCI, etc.
+        This is reported against the service, but may not get reflected in the service in the network.";
+    }
+    leaf common-id {
+      type string;
+      description
+        "To be used by the ROADM controller to identify the routing constraints
+        received from planning application (PED).";
+    }
+    leaf connection-type {
+      type org-openroadm-common-service-types:connection-type;
+      mandatory true;
+    }
+    container service-a-end {
+      uses org-openroadm-common-service-types:service-endpoint;
+    }
+    container service-z-end {
+      uses org-openroadm-common-service-types:service-endpoint;
+    }
+    leaf response-failed {
+      type string;
+      description
+        "Response of the error if the service request encountered an anomaly";
+    }
+    leaf operational-state {
+      type org-openroadm-common-state-types:state;
+      config false;
+      description
+        "Operational State: Actual state of service";
+    }
+  }
+
+  container notification-service {
+    description
+      "Model used to send a notification from a service request";
+    uses notification-service;
+  }
+
+  rpc get-notifications-service {
+    description "Get the notifications service send by ServiceHandler by filtering through connection type";
+    input {
+      leaf connection-type {
+        type org-openroadm-common-service-types:connection-type;
+        mandatory true;
+        description
+          "Type connection of the service ";
+      }
+      leaf id-consumer {
+        type string;
+        mandatory true;
+        description
+          "Unique ID for the consumer";
+      }
+      leaf group-id {
+        type string;
+        mandatory true;
+        description
+          "ID Group for the consumer";
+      }
+    }
+    output {
+      list notification-service {
+        uses notification-service;
+      }
+    }
+  }
+
+  notification publish-notification-service {
+    description "Publish the notifications service for topic";
+    leaf topic {
+      type string;
+      mandatory true;
+      description
+        "Topic where to send the notification service";
+     }
+     uses notification-service;
+  }
+}
diff --git a/dmaap-client/pom.xml b/dmaap-client/pom.xml
new file mode 100644 (file)
index 0000000..0560fbc
--- /dev/null
@@ -0,0 +1,77 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright © 2021 Orange and others. All rights reserved. This program and the accompanying materials
+    are made available under the terms of the Eclipse Public License v1.0 which accompanies this distribution,
+    and is available at http://www.eclipse.org/legal/epl-v10.html -->
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+    <parent>
+        <groupId>org.opendaylight.mdsal</groupId>
+        <artifactId>binding-parent</artifactId>
+        <version>7.0.5</version>
+        <relativePath />
+    </parent>
+    <groupId>org.opendaylight.transportpce</groupId>
+    <artifactId>transportpce-dmaap-client</artifactId>
+    <version>3.0.0-SNAPSHOT</version>
+    <packaging>bundle</packaging>
+    <description>client to send message to Dmaap message router</description>
+
+    <properties>
+        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+    </properties>
+    <dependencies>
+        <dependency>
+            <groupId>${project.groupId}</groupId>
+            <artifactId>transportpce-api</artifactId>
+            <version>${project.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.opendaylight.mdsal</groupId>
+            <artifactId>mdsal-binding-api</artifactId>
+            <scope>compile</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.glassfish.jersey.core</groupId>
+            <artifactId>jersey-client</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.glassfish.jersey.ext</groupId>
+            <artifactId>jersey-proxy-client</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.glassfish.jersey.inject</groupId>
+            <artifactId>jersey-hk2</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.glassfish.jersey.media</groupId>
+            <artifactId>jersey-media-json-jackson</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>com.fasterxml.jackson.datatype</groupId>
+            <artifactId>jackson-datatype-jsr310</artifactId>
+        </dependency>
+        <!-- Testing dependencies -->
+        <dependency>
+            <groupId>org.glassfish.jersey.test-framework</groupId>
+            <artifactId>jersey-test-framework-core</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.glassfish.jersey.test-framework.providers</groupId>
+            <artifactId>jersey-test-framework-provider-grizzly2</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.mockito</groupId>
+            <artifactId>mockito-core</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>ch.qos.logback</groupId>
+            <artifactId>logback-classic</artifactId>
+            <scope>test</scope>
+        </dependency>
+    </dependencies>
+</project>
\ No newline at end of file
diff --git a/dmaap-client/src/main/java/org/opendaylight/transportpce/dmaap/client/impl/DmaapClientProvider.java b/dmaap-client/src/main/java/org/opendaylight/transportpce/dmaap/client/impl/DmaapClientProvider.java
new file mode 100644 (file)
index 0000000..adc4d06
--- /dev/null
@@ -0,0 +1,50 @@
+/*
+ * Copyright © 2021 Orange, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.transportpce.dmaap.client.impl;
+
+import org.opendaylight.mdsal.binding.api.NotificationService;
+import org.opendaylight.transportpce.dmaap.client.listener.NbiNotificationsListenerImpl;
+import org.opendaylight.yang.gen.v1.nbi.notifications.rev201130.NbiNotificationsListener;
+import org.opendaylight.yangtools.concepts.ListenerRegistration;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class DmaapClientProvider {
+    private static final Logger LOG = LoggerFactory.getLogger(DmaapClientProvider.class);
+    private ListenerRegistration<NbiNotificationsListener> listenerRegistration;
+    private NotificationService notificationService;
+    private final String baseUrl;
+    private final String username;
+    private final String password;
+
+    public DmaapClientProvider(NotificationService notificationService, String baseUrl,
+            String username, String password) {
+        this.notificationService = notificationService;
+        this.baseUrl = baseUrl;
+        this.username = username;
+        this.password = password;
+    }
+
+    /**
+     * Method called when the blueprint container is created.
+     */
+    public void init() {
+        LOG.info("DmaapClientProvider Session Initiated");
+        listenerRegistration = notificationService.registerNotificationListener(
+                new NbiNotificationsListenerImpl(baseUrl, username, password));
+    }
+
+    /**
+     * Method called when the blueprint container is destroyed.
+     */
+    public void close() {
+        listenerRegistration.close();
+        LOG.info("DmaapClientProvider Closed");
+    }
+
+}
diff --git a/dmaap-client/src/main/java/org/opendaylight/transportpce/dmaap/client/listener/NbiNotificationsListenerImpl.java b/dmaap-client/src/main/java/org/opendaylight/transportpce/dmaap/client/listener/NbiNotificationsListenerImpl.java
new file mode 100644 (file)
index 0000000..ed84dae
--- /dev/null
@@ -0,0 +1,55 @@
+/*
+ * Copyright © 2021 Orange, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.transportpce.dmaap.client.listener;
+
+import javax.ws.rs.WebApplicationException;
+import javax.ws.rs.client.Client;
+import javax.ws.rs.client.ClientBuilder;
+import org.glassfish.jersey.client.authentication.HttpAuthenticationFeature;
+import org.glassfish.jersey.client.proxy.WebResourceFactory;
+import org.glassfish.jersey.jackson.JacksonFeature;
+import org.glassfish.jersey.logging.LoggingFeature;
+import org.opendaylight.transportpce.dmaap.client.resource.EventsApi;
+import org.opendaylight.transportpce.dmaap.client.resource.config.JsonConfigurator;
+import org.opendaylight.transportpce.dmaap.client.resource.model.CreatedEvent;
+import org.opendaylight.yang.gen.v1.nbi.notifications.rev201130.NbiNotificationsListener;
+import org.opendaylight.yang.gen.v1.nbi.notifications.rev201130.PublishNotificationService;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class NbiNotificationsListenerImpl implements NbiNotificationsListener {
+    private static final Logger LOG = LoggerFactory.getLogger(NbiNotificationsListenerImpl.class);
+    private String topic = "unauthenticated.TPCE";
+    private EventsApi api;
+
+    public NbiNotificationsListenerImpl(String baseUrl, String username, String password) {
+        LOG.info("Dmaap server {} for user {}", baseUrl, username);
+        Client client = ClientBuilder.newClient();
+        if (username != null && username.isBlank() && password != null && !password.isBlank()) {
+            HttpAuthenticationFeature authFeature = HttpAuthenticationFeature.basic(username, password);
+            client.register(authFeature);
+            topic = "authenticated.TPCE";
+        }
+        client.register(new LoggingFeature(java.util.logging.Logger.getLogger(this.getClass().getName())))
+        .register(JacksonFeature.class).register(JsonConfigurator.class);
+        api = WebResourceFactory.newResource(EventsApi.class, client.target(baseUrl));
+
+    }
+
+    @Override
+    public void onPublishNotificationService(PublishNotificationService notification) {
+        try {
+            CreatedEvent response = api.sendEvent(topic, notification);
+            LOG.info("Response received {}", response);
+        } catch (WebApplicationException e) {
+            LOG.warn("Cannot send event {}", notification, e);
+        }
+
+    }
+
+}
diff --git a/dmaap-client/src/main/java/org/opendaylight/transportpce/dmaap/client/resource/EventsApi.java b/dmaap-client/src/main/java/org/opendaylight/transportpce/dmaap/client/resource/EventsApi.java
new file mode 100644 (file)
index 0000000..e9d936c
--- /dev/null
@@ -0,0 +1,28 @@
+/*
+ * Copyright © 2021 Orange, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.transportpce.dmaap.client.resource;
+
+import javax.ws.rs.Consumes;
+import javax.ws.rs.POST;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.MediaType;
+import org.opendaylight.transportpce.dmaap.client.resource.model.CreatedEvent;
+import org.opendaylight.yang.gen.v1.nbi.notifications.rev201130.PublishNotificationService;
+
+@Path("/events")
+public interface EventsApi {
+
+    @POST
+    @Consumes(MediaType.APPLICATION_JSON)
+    @Produces(MediaType.APPLICATION_JSON)
+    @Path("/{topic}")
+    CreatedEvent sendEvent(@PathParam("topic") String topic, PublishNotificationService event);
+
+}
diff --git a/dmaap-client/src/main/java/org/opendaylight/transportpce/dmaap/client/resource/config/JsonConfigurator.java b/dmaap-client/src/main/java/org/opendaylight/transportpce/dmaap/client/resource/config/JsonConfigurator.java
new file mode 100644 (file)
index 0000000..62676c0
--- /dev/null
@@ -0,0 +1,33 @@
+/*
+ * Copyright © 2021 Orange, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.transportpce.dmaap.client.resource.config;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.SerializationFeature;
+import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
+import javax.ws.rs.ext.ContextResolver;
+
+public class JsonConfigurator implements ContextResolver<ObjectMapper> {
+
+    private final ObjectMapper mapper;
+
+    public JsonConfigurator() {
+        mapper = new ObjectMapper();
+        mapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
+        mapper.disable(SerializationFeature.FAIL_ON_EMPTY_BEANS);
+        mapper.enable(SerializationFeature.INDENT_OUTPUT);
+        mapper.registerModule(new JavaTimeModule());
+        mapper.registerModule(new PublishNotificationServiceModule());
+    }
+
+    @Override
+    public ObjectMapper getContext(Class<?> type) {
+        return mapper;
+    }
+
+}
diff --git a/dmaap-client/src/main/java/org/opendaylight/transportpce/dmaap/client/resource/config/LgxSerializer.java b/dmaap-client/src/main/java/org/opendaylight/transportpce/dmaap/client/resource/config/LgxSerializer.java
new file mode 100644 (file)
index 0000000..8f847a9
--- /dev/null
@@ -0,0 +1,36 @@
+/*
+ * Copyright © 2021 Orange, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.transportpce.dmaap.client.resource.config;
+
+import com.fasterxml.jackson.core.JsonGenerator;
+import com.fasterxml.jackson.databind.SerializerProvider;
+import com.fasterxml.jackson.databind.ser.std.StdSerializer;
+import java.io.IOException;
+import org.opendaylight.yang.gen.v1.http.org.openroadm.common.service.types.rev190531.service.lgx.Lgx;
+
+// This class is a temporary workaround while waiting jackson
+// support in yang tools https://git.opendaylight.org/gerrit/c/yangtools/+/94852
+public class LgxSerializer extends StdSerializer<Lgx> {
+    private static final long serialVersionUID = 1L;
+
+    public LgxSerializer() {
+        super(Lgx.class);
+    }
+
+    @Override
+    public void serialize(Lgx value, JsonGenerator gen, SerializerProvider provider) throws IOException {
+        if (value != null) {
+            gen.writeStartObject();
+            gen.writeStringField("lgx-port-rack", value.getLgxPortRack());
+            gen.writeStringField("lgx-port-shelf", value.getLgxPortShelf());
+            gen.writeStringField("lgx-device-name", value.getLgxDeviceName());
+            gen.writeStringField("lgx-port-name", value.getLgxPortName());
+            gen.writeEndObject();
+        }
+    }
+}
diff --git a/dmaap-client/src/main/java/org/opendaylight/transportpce/dmaap/client/resource/config/PortSerializer.java b/dmaap-client/src/main/java/org/opendaylight/transportpce/dmaap/client/resource/config/PortSerializer.java
new file mode 100644 (file)
index 0000000..bdce081
--- /dev/null
@@ -0,0 +1,37 @@
+/*
+ * Copyright © 2021 Orange, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.transportpce.dmaap.client.resource.config;
+
+import com.fasterxml.jackson.core.JsonGenerator;
+import com.fasterxml.jackson.databind.SerializerProvider;
+import com.fasterxml.jackson.databind.ser.std.StdSerializer;
+import java.io.IOException;
+import org.opendaylight.yang.gen.v1.http.org.openroadm.common.service.types.rev190531.service.port.Port;
+
+// This class is a temporary workaround while waiting jackson
+// support in yang tools https://git.opendaylight.org/gerrit/c/yangtools/+/94852
+public class PortSerializer extends StdSerializer<Port> {
+    private static final long serialVersionUID = 1L;
+
+    public PortSerializer() {
+        super(Port.class);
+    }
+
+    @Override
+    public void serialize(Port value, JsonGenerator gen, SerializerProvider provider) throws IOException {
+        if (value != null) {
+            gen.writeStartObject();
+            gen.writeStringField("port-rack", value.getPortRack());
+            gen.writeStringField("port-shelf", value.getPortShelf());
+            gen.writeStringField("port-device-name", value.getPortDeviceName());
+            gen.writeStringField("port-name", value.getPortName());
+            gen.writeStringField("port-type", value.getPortType());
+            gen.writeEndObject();
+        }
+    }
+}
diff --git a/dmaap-client/src/main/java/org/opendaylight/transportpce/dmaap/client/resource/config/PublishNotificationServiceModule.java b/dmaap-client/src/main/java/org/opendaylight/transportpce/dmaap/client/resource/config/PublishNotificationServiceModule.java
new file mode 100644 (file)
index 0000000..6b61557
--- /dev/null
@@ -0,0 +1,37 @@
+/*
+ * Copyright © 2021 Orange, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.transportpce.dmaap.client.resource.config;
+
+import com.fasterxml.jackson.databind.module.SimpleModule;
+import com.fasterxml.jackson.datatype.jsr310.PackageVersion;
+import org.opendaylight.yang.gen.v1.http.org.openroadm.common.service.types.rev190531.service.endpoint.RxDirection;
+import org.opendaylight.yang.gen.v1.http.org.openroadm.common.service.types.rev190531.service.endpoint.TxDirection;
+import org.opendaylight.yang.gen.v1.http.org.openroadm.common.service.types.rev190531.service.lgx.Lgx;
+import org.opendaylight.yang.gen.v1.http.org.openroadm.common.service.types.rev190531.service.port.Port;
+import org.opendaylight.yang.gen.v1.nbi.notifications.rev201130.PublishNotificationService;
+import org.opendaylight.yang.gen.v1.nbi.notifications.rev201130.notification.service.ServiceAEnd;
+import org.opendaylight.yang.gen.v1.nbi.notifications.rev201130.notification.service.ServiceZEnd;
+
+//This class is a temporary workaround while waiting jackson
+//support in yang tools https://git.opendaylight.org/gerrit/c/yangtools/+/94852
+public class PublishNotificationServiceModule extends SimpleModule {
+
+    private static final long serialVersionUID = 1L;
+
+    public PublishNotificationServiceModule() {
+        super(PackageVersion.VERSION);
+        addSerializer(PublishNotificationService.class, new PublishNotificationServiceSerializer());
+        addSerializer(Lgx.class, new LgxSerializer());
+        addSerializer(Port.class, new PortSerializer());
+        addSerializer(RxDirection.class, new RxDirectionSerializer());
+        addSerializer(TxDirection.class, new TxDirectionSerializer());
+        addSerializer(ServiceAEnd.class, new ServiceAEndSerializer());
+        addSerializer(ServiceZEnd.class, new ServiceZEndSerializer());
+    }
+
+}
diff --git a/dmaap-client/src/main/java/org/opendaylight/transportpce/dmaap/client/resource/config/PublishNotificationServiceSerializer.java b/dmaap-client/src/main/java/org/opendaylight/transportpce/dmaap/client/resource/config/PublishNotificationServiceSerializer.java
new file mode 100644 (file)
index 0000000..0ed9b7b
--- /dev/null
@@ -0,0 +1,44 @@
+/*
+ * Copyright © 2021 Orange, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.transportpce.dmaap.client.resource.config;
+
+import com.fasterxml.jackson.core.JsonGenerator;
+import com.fasterxml.jackson.databind.SerializerProvider;
+import com.fasterxml.jackson.databind.ser.std.StdSerializer;
+import java.io.IOException;
+import org.opendaylight.yang.gen.v1.nbi.notifications.rev201130.PublishNotificationService;
+
+// This class is a temporary workaround while waiting jackson
+// support in yang tools https://git.opendaylight.org/gerrit/c/yangtools/+/94852
+public class PublishNotificationServiceSerializer extends StdSerializer<PublishNotificationService> {
+    private static final long serialVersionUID = 1L;
+
+    public PublishNotificationServiceSerializer() {
+        super(PublishNotificationService.class);
+    }
+
+    @Override
+    public void serialize(PublishNotificationService value, JsonGenerator gen, SerializerProvider provider)
+            throws IOException {
+        if (value != null) {
+            gen.writeStartObject();
+            gen.writeStringField("common-id", value.getCommonId());
+            gen.writeStringField("message", value.getMessage());
+            gen.writeStringField("response-failed", value.getResponseFailed());
+            gen.writeStringField("service-name", value.getServiceName());
+            gen.writeStringField("topic", value.getTopic());
+            if (value.getOperationalState() != null) {
+                gen.writeStringField("operational-state", value.getOperationalState().getName());
+            }
+            gen.writeObjectField("service-a-end", value.getServiceAEnd());
+            gen.writeObjectField("service-z-end", value.getServiceZEnd());
+            gen.writeEndObject();
+        }
+    }
+
+}
diff --git a/dmaap-client/src/main/java/org/opendaylight/transportpce/dmaap/client/resource/config/RxDirectionSerializer.java b/dmaap-client/src/main/java/org/opendaylight/transportpce/dmaap/client/resource/config/RxDirectionSerializer.java
new file mode 100644 (file)
index 0000000..376b6be
--- /dev/null
@@ -0,0 +1,39 @@
+/*
+ * Copyright © 2021 Orange, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.transportpce.dmaap.client.resource.config;
+
+import com.fasterxml.jackson.core.JsonGenerator;
+import com.fasterxml.jackson.databind.SerializerProvider;
+import com.fasterxml.jackson.databind.ser.std.StdSerializer;
+import java.io.IOException;
+import org.opendaylight.yang.gen.v1.http.org.openroadm.common.service.types.rev190531.service.endpoint.RxDirection;
+
+// This class is a temporary workaround while waiting jackson
+// support in yang tools https://git.opendaylight.org/gerrit/c/yangtools/+/94852
+public class RxDirectionSerializer extends StdSerializer<RxDirection> {
+    private static final long serialVersionUID = 1L;
+
+    public RxDirectionSerializer() {
+        super(RxDirection.class);
+    }
+
+    @Override
+    public void serialize(RxDirection value, JsonGenerator gen, SerializerProvider provider) throws IOException {
+        if (value != null) {
+            gen.writeStartObject();
+            if (value.getPort() != null) {
+                gen.writeObjectField("port", value.getPort());
+            }
+            if (value.getLgx() != null) {
+                gen.writeObjectField("lgx", value.getLgx());
+            }
+            gen.writeEndObject();
+        }
+    }
+
+}
diff --git a/dmaap-client/src/main/java/org/opendaylight/transportpce/dmaap/client/resource/config/ServiceAEndSerializer.java b/dmaap-client/src/main/java/org/opendaylight/transportpce/dmaap/client/resource/config/ServiceAEndSerializer.java
new file mode 100644 (file)
index 0000000..55bfaea
--- /dev/null
@@ -0,0 +1,51 @@
+/*
+ * Copyright © 2021 Orange, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.transportpce.dmaap.client.resource.config;
+
+import com.fasterxml.jackson.core.JsonGenerator;
+import com.fasterxml.jackson.databind.SerializerProvider;
+import com.fasterxml.jackson.databind.ser.std.StdSerializer;
+import java.io.IOException;
+import org.opendaylight.yang.gen.v1.nbi.notifications.rev201130.notification.service.ServiceAEnd;
+
+// This class is a temporary workaround while waiting jackson
+// support in yang tools https://git.opendaylight.org/gerrit/c/yangtools/+/94852
+public class ServiceAEndSerializer extends StdSerializer<ServiceAEnd> {
+    private static final long serialVersionUID = 1L;
+
+    public ServiceAEndSerializer() {
+        super(ServiceAEnd.class);
+    }
+
+    @Override
+    public void serialize(ServiceAEnd value, JsonGenerator gen, SerializerProvider provider) throws IOException {
+        if (value != null) {
+            gen.writeStartObject();
+            gen.writeStringField("clli", value.getClli());
+            if (value.getServiceFormat() != null) {
+                gen.writeStringField("service-format", value.getServiceFormat().getName());
+            }
+            if (value.getNodeId() != null) {
+                gen.writeStringField("node-id", value.getNodeId().getValue());
+            }
+            if (value.getServiceRate() != null) {
+                gen.writeNumberField("service-rate", value.getServiceRate().intValue());
+            }
+            if (value.getOpticType() != null) {
+                gen.writeStringField("optic-type", value.getOpticType().getName());
+            }
+            if (value.getTxDirection() != null) {
+                gen.writeObjectField("tx-direction", value.getTxDirection());
+            }
+            if (value.getRxDirection() != null) {
+                gen.writeObjectField("rx-direction", value.getRxDirection());
+            }
+            gen.writeEndObject();
+        }
+    }
+}
diff --git a/dmaap-client/src/main/java/org/opendaylight/transportpce/dmaap/client/resource/config/ServiceZEndSerializer.java b/dmaap-client/src/main/java/org/opendaylight/transportpce/dmaap/client/resource/config/ServiceZEndSerializer.java
new file mode 100644 (file)
index 0000000..1d65b11
--- /dev/null
@@ -0,0 +1,51 @@
+/*
+ * Copyright © 2021 Orange, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.transportpce.dmaap.client.resource.config;
+
+import com.fasterxml.jackson.core.JsonGenerator;
+import com.fasterxml.jackson.databind.SerializerProvider;
+import com.fasterxml.jackson.databind.ser.std.StdSerializer;
+import java.io.IOException;
+import org.opendaylight.yang.gen.v1.nbi.notifications.rev201130.notification.service.ServiceZEnd;
+
+// This class is a temporary workaround while waiting jackson
+// support in yang tools https://git.opendaylight.org/gerrit/c/yangtools/+/94852
+public class ServiceZEndSerializer extends StdSerializer<ServiceZEnd> {
+    private static final long serialVersionUID = 1L;
+
+    public ServiceZEndSerializer() {
+        super(ServiceZEnd.class);
+    }
+
+    @Override
+    public void serialize(ServiceZEnd value, JsonGenerator gen, SerializerProvider provider) throws IOException {
+        if (value != null) {
+            gen.writeStartObject();
+            gen.writeStringField("clli", value.getClli());
+            if (value.getServiceFormat() != null) {
+                gen.writeStringField("service-format", value.getServiceFormat().getName());
+            }
+            if (value.getNodeId() != null) {
+                gen.writeStringField("node-id", value.getNodeId().getValue());
+            }
+            if (value.getServiceRate() != null) {
+                gen.writeNumberField("service-rate", value.getServiceRate().intValue());
+            }
+            if (value.getOpticType() != null) {
+                gen.writeStringField("optic-type", value.getOpticType().getName());
+            }
+            if (value.getTxDirection() != null) {
+                gen.writeObjectField("tx-direction", value.getTxDirection());
+            }
+            if (value.getRxDirection() != null) {
+                gen.writeObjectField("rx-direction", value.getRxDirection());
+            }
+            gen.writeEndObject();
+        }
+    }
+}
diff --git a/dmaap-client/src/main/java/org/opendaylight/transportpce/dmaap/client/resource/config/TxDirectionSerializer.java b/dmaap-client/src/main/java/org/opendaylight/transportpce/dmaap/client/resource/config/TxDirectionSerializer.java
new file mode 100644 (file)
index 0000000..90942a8
--- /dev/null
@@ -0,0 +1,38 @@
+/*
+ * Copyright © 2021 Orange, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.transportpce.dmaap.client.resource.config;
+
+import com.fasterxml.jackson.core.JsonGenerator;
+import com.fasterxml.jackson.databind.SerializerProvider;
+import com.fasterxml.jackson.databind.ser.std.StdSerializer;
+import java.io.IOException;
+import org.opendaylight.yang.gen.v1.http.org.openroadm.common.service.types.rev190531.service.endpoint.TxDirection;
+
+// This class is a temporary workaround while waiting jackson
+// support in yang tools https://git.opendaylight.org/gerrit/c/yangtools/+/94852
+public class TxDirectionSerializer extends StdSerializer<TxDirection> {
+    private static final long serialVersionUID = 1L;
+
+    public TxDirectionSerializer() {
+        super(TxDirection.class);
+    }
+
+    @Override
+    public void serialize(TxDirection value, JsonGenerator gen, SerializerProvider provider) throws IOException {
+        if (value != null) {
+            gen.writeStartObject();
+            if (value.getPort() != null) {
+                gen.writeObjectField("port", value.getPort());
+            }
+            if (value.getLgx() != null) {
+                gen.writeObjectField("lgx", value.getLgx());
+            }
+            gen.writeEndObject();
+        }
+    }
+}
diff --git a/dmaap-client/src/main/java/org/opendaylight/transportpce/dmaap/client/resource/model/CreatedEvent.java b/dmaap-client/src/main/java/org/opendaylight/transportpce/dmaap/client/resource/model/CreatedEvent.java
new file mode 100644 (file)
index 0000000..aa39efc
--- /dev/null
@@ -0,0 +1,44 @@
+/*
+ * Copyright © 2021 Orange, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.transportpce.dmaap.client.resource.model;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+
+public class CreatedEvent {
+
+    @JsonProperty("serverTimeMs")
+    private Integer serverTimeMs;
+
+    @JsonProperty("count")
+    private Integer count;
+
+    public Integer getServerTimeMs() {
+        return serverTimeMs;
+    }
+
+    public void setServerTimeMs(Integer serverTimeMs) {
+        this.serverTimeMs = serverTimeMs;
+    }
+
+    public Integer getCount() {
+        return count;
+    }
+
+    public void setCount(Integer count) {
+        this.count = count;
+    }
+
+    @Override
+    public String toString() {
+        return new StringBuilder()
+                .append("CreatedEvent [serverTimeMs=")
+                .append(serverTimeMs).append(", count=")
+                .append(count).append("]")
+                .toString();
+    }
+}
diff --git a/dmaap-client/src/main/resources/OSGI-INF/blueprint/dmaap-blueprint.xml b/dmaap-client/src/main/resources/OSGI-INF/blueprint/dmaap-blueprint.xml
new file mode 100644 (file)
index 0000000..459848e
--- /dev/null
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- vi: set et smarttab sw=4 tabstop=4: -->
+<!-- Copyright © 2021 Orange and others. All rights reserved. This program and the accompanying materials
+    are made available under the terms of the Eclipse Public License v1.0 which accompanies this distribution,
+    and is available at http://www.eclipse.org/legal/epl-v10.html -->
+<blueprint xmlns="http://www.osgi.org/xmlns/blueprint/v1.0.0" xmlns:odl="http://opendaylight.org/xmlns/blueprint/v1.0.0"
+ xmlns:cm="http://aries.apache.org/blueprint/xmlns/blueprint-cm/v1.1.0"
+    odl:use-default-for-reference-types="true">
+    <cm:property-placeholder persistent-id="org.opendaylight.transportpce.dmaap" update-strategy="reload">
+        <cm:default-properties>
+            <cm:property name="dmaap.baseUrl" value="http://localhost:8080" />
+            <cm:property name="dmaap.username" value="" />
+             <cm:property name="dmaap.password" value="" />
+        </cm:default-properties>
+    </cm:property-placeholder>
+    <reference id="notificationService" interface="org.opendaylight.mdsal.binding.api.NotificationService"/>
+
+    <bean id="provider"
+        class="org.opendaylight.transportpce.dmaap.client.impl.DmaapClientProvider"
+        init-method="init" destroy-method="close">
+        <argument ref="notificationService" />
+        <argument value="${dmaap.baseUrl}"></argument>
+        <argument value="${dmaap.username}"></argument>
+        <argument value="${dmaap.password}"></argument>
+    </bean>
+</blueprint>
diff --git a/dmaap-client/src/test/java/org/opendaylight/transportpce/dmaap/client/impl/DmaapClientProviderTest.java b/dmaap-client/src/test/java/org/opendaylight/transportpce/dmaap/client/impl/DmaapClientProviderTest.java
new file mode 100644 (file)
index 0000000..1ebfade
--- /dev/null
@@ -0,0 +1,41 @@
+/*
+ * Copyright © 2021 Orange, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.transportpce.dmaap.client.impl;
+
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.Mock;
+import org.mockito.Mockito;
+import org.mockito.MockitoAnnotations;
+import org.opendaylight.mdsal.binding.api.NotificationService;
+import org.opendaylight.transportpce.dmaap.client.listener.NbiNotificationsListenerImpl;
+
+
+public class DmaapClientProviderTest {
+
+    @Mock
+    private NotificationService notificationService;
+
+    @Before
+    public void init() {
+        MockitoAnnotations.openMocks(this);
+
+    }
+
+    @Test
+    public void testInitRegisterNbiNotificationsToRpcRegistry() {
+        DmaapClientProvider provider =  new DmaapClientProvider(notificationService, "http://localhost", "username", "password");
+        provider.init();
+        (verify(notificationService, times(1)))
+                .registerNotificationListener(Mockito.any(NbiNotificationsListenerImpl.class));
+    }
+
+}
diff --git a/dmaap-client/src/test/java/org/opendaylight/transportpce/dmaap/client/listener/NbiNotificationsListenerImplTest.java b/dmaap-client/src/test/java/org/opendaylight/transportpce/dmaap/client/listener/NbiNotificationsListenerImplTest.java
new file mode 100644 (file)
index 0000000..710bf1b
--- /dev/null
@@ -0,0 +1,80 @@
+/*
+ * Copyright © 2021 Orange, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.transportpce.dmaap.client.listener;
+
+import static org.junit.Assert.assertEquals;
+
+import ch.qos.logback.classic.Logger;
+import ch.qos.logback.classic.spi.ILoggingEvent;
+import ch.qos.logback.core.read.ListAppender;
+import java.util.List;
+import javax.ws.rs.core.Application;
+import org.glassfish.jersey.server.ResourceConfig;
+import org.glassfish.jersey.test.JerseyTest;
+import org.glassfish.jersey.test.TestProperties;
+import org.junit.Test;
+import org.opendaylight.transportpce.dmaap.client.resource.EventsApiStub;
+import org.opendaylight.yang.gen.v1.http.org.openroadm.common.service.types.rev190531.ConnectionType;
+import org.opendaylight.yang.gen.v1.http.org.openroadm.common.service.types.rev190531.service.endpoint.RxDirectionBuilder;
+import org.opendaylight.yang.gen.v1.http.org.openroadm.common.service.types.rev190531.service.endpoint.TxDirectionBuilder;
+import org.opendaylight.yang.gen.v1.http.org.openroadm.common.state.types.rev181130.State;
+import org.opendaylight.yang.gen.v1.http.org.openroadm.service.format.rev190531.ServiceFormat;
+import org.opendaylight.yang.gen.v1.nbi.notifications.rev201130.NbiNotificationsListener;
+import org.opendaylight.yang.gen.v1.nbi.notifications.rev201130.PublishNotificationService;
+import org.opendaylight.yang.gen.v1.nbi.notifications.rev201130.PublishNotificationServiceBuilder;
+import org.opendaylight.yang.gen.v1.nbi.notifications.rev201130.notification.service.ServiceAEndBuilder;
+import org.opendaylight.yang.gen.v1.nbi.notifications.rev201130.notification.service.ServiceZEndBuilder;
+import org.opendaylight.yangtools.yang.common.Uint32;
+import org.slf4j.LoggerFactory;
+
+public class NbiNotificationsListenerImplTest extends JerseyTest {
+    @Override
+    protected Application configure() {
+        enable(TestProperties.LOG_TRAFFIC);
+        enable(TestProperties.DUMP_ENTITY);
+        return new ResourceConfig(EventsApiStub.class);
+    }
+
+    @Test
+    public void onPublishNotificationServiceTest() {
+        Logger logger = (Logger) LoggerFactory.getLogger(NbiNotificationsListenerImpl.class);
+        ListAppender<ILoggingEvent> listAppender = new ListAppender<>();
+        listAppender.start();
+        logger.addAppender(listAppender);
+        NbiNotificationsListener listener = new NbiNotificationsListenerImpl("http://localhost:9998", null, null);
+        PublishNotificationService notification = new PublishNotificationServiceBuilder().setCommonId("CommonId")
+                .setMessage("Service implemented")
+                .setOperationalState(State.InService)
+                .setTopic("topic")
+                .setConnectionType(ConnectionType.Service)
+                .setServiceAEnd(new ServiceAEndBuilder()
+                        .setClli("clli")
+                        .setNodeId(new org.opendaylight.yang.gen.v1.http
+                                .org.openroadm.common.node.types.rev181130.NodeIdType("nodeidtype"))
+                        .setServiceFormat(ServiceFormat.Ethernet)
+                        .setServiceRate(Uint32.valueOf(100))
+                        .setRxDirection(new RxDirectionBuilder().build())
+                        .setTxDirection(new TxDirectionBuilder().build())
+                        .build())
+                .setServiceZEnd(new ServiceZEndBuilder()
+                        .setClli("clli")
+                        .setNodeId(new org.opendaylight.yang.gen.v1.http
+                                .org.openroadm.common.node.types.rev181130.NodeIdType("nodeidtype"))
+                        .setServiceFormat(ServiceFormat.Ethernet)
+                        .setServiceRate(Uint32.valueOf(100))
+                        .setRxDirection(new RxDirectionBuilder().build())
+                        .setTxDirection(new TxDirectionBuilder().build())
+                        .build())
+                .build();
+        listener.onPublishNotificationService(notification);
+        // as onPublishNotificationService is a void method, we check log message to be sur everything went well
+        List<ILoggingEvent> logsList = listAppender.list;
+        assertEquals("Response received CreatedEvent [serverTimeMs=1, count=1]", logsList.get(1).getFormattedMessage());
+
+    }
+}
diff --git a/dmaap-client/src/test/java/org/opendaylight/transportpce/dmaap/client/resource/EventsApiStub.java b/dmaap-client/src/test/java/org/opendaylight/transportpce/dmaap/client/resource/EventsApiStub.java
new file mode 100644 (file)
index 0000000..c71e0a9
--- /dev/null
@@ -0,0 +1,32 @@
+/*
+ * Copyright © 2021 Orange, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.transportpce.dmaap.client.resource;
+
+import javax.ws.rs.Consumes;
+import javax.ws.rs.POST;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.MediaType;
+import org.opendaylight.transportpce.dmaap.client.resource.model.CreatedEvent;
+
+@Path("/events")
+public class EventsApiStub {
+
+    @POST
+    @Consumes(MediaType.APPLICATION_JSON)
+    @Produces(MediaType.APPLICATION_JSON)
+    @Path("/{topic}")
+    public CreatedEvent sendEvent(@PathParam("topic") String topic, String event) {
+        CreatedEvent response = new CreatedEvent();
+        response.setCount(1);
+        response.setServerTimeMs(1);
+        return response;
+    }
+
+}
diff --git a/features/odl-transportpce-dmaap-client/pom.xml b/features/odl-transportpce-dmaap-client/pom.xml
new file mode 100644 (file)
index 0000000..1095400
--- /dev/null
@@ -0,0 +1,78 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright © 2021 Orange and others. All rights reserved. This program
+    and the accompanying materials are made available under the terms of the
+    Eclipse Public License v1.0 which accompanies this distribution, and is available
+    at http://www.eclipse.org/legal/epl-v10.html INTERNAL -->
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+    <parent>
+        <groupId>org.opendaylight.odlparent</groupId>
+        <artifactId>single-feature-parent</artifactId>
+        <version>8.1.0</version>
+        <relativePath />
+    </parent>
+    <groupId>org.opendaylight.transportpce</groupId>
+    <artifactId>odl-transportpce-dmaap-client</artifactId>
+    <version>3.0.0-SNAPSHOT</version>
+    <packaging>feature</packaging>
+
+    <name>OpenDaylight :: transportpce :: dmaap-client</name>
+    <properties>
+    <!-- skipped because we are using config file as artifact and it is not installed before running test -->
+        <skip.karaf.featureTest>true</skip.karaf.featureTest>
+    </properties>
+    <dependencies>
+        <dependency>
+            <groupId>org.opendaylight.transportpce</groupId>
+            <artifactId>odl-transportpce</artifactId>
+            <version>${project.version}</version>
+            <classifier>features</classifier>
+            <type>xml</type>
+            <exclusions>
+                <exclusion>
+                    <groupId>org.glassfish.jersey.inject</groupId>
+                    <artifactId>jersey-hk2</artifactId>
+                </exclusion>
+            </exclusions>
+        </dependency>
+        <dependency>
+            <groupId>org.opendaylight.transportpce</groupId>
+            <artifactId>transportpce-dmaap-client</artifactId>
+            <version>${project.version}</version>
+            <exclusions>
+                <exclusion>
+                    <groupId>org.glassfish.jersey.inject</groupId>
+                    <artifactId>jersey-hk2</artifactId>
+                </exclusion>
+            </exclusions>
+        </dependency>
+    </dependencies>
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.codehaus.mojo</groupId>
+                <artifactId>build-helper-maven-plugin</artifactId>
+                <executions>
+                    <execution>
+                        <id>attach-dmaap-artifact</id>
+                        <phase>test</phase>
+                        <goals>
+                            <goal>attach-artifact</goal>
+                        </goals>
+                        <configuration>
+                            <artifacts>
+                                <artifact>
+                                    <file>${basedir}/src/main/resources/org.opendaylight.transportpce.dmaap.cfg</file>
+                                    <type>cfg</type>
+                                    <classifier>config</classifier>
+                                </artifact>
+                            </artifacts>
+                        </configuration>
+                    </execution>
+                </executions>
+            </plugin>
+        </plugins>
+    </build>
+</project>
\ No newline at end of file
diff --git a/features/odl-transportpce-dmaap-client/src/main/feature/feature.xml b/features/odl-transportpce-dmaap-client/src/main/feature/feature.xml
new file mode 100644 (file)
index 0000000..0031ef8
--- /dev/null
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+<!-- Copyright © 2021 Orange and others. All rights reserved. This program
+    and the accompanying materials are made available under the terms of the
+    Eclipse Public License v1.0 which accompanies this distribution, and is available
+    at http://www.eclipse.org/legal/epl-v10.html INTERNAL -->
+<features xmlns="http://karaf.apache.org/xmlns/features/v1.4.0" name="odl-transportpce-dmaap-client">
+    <feature name="odl-transportpce-dmaap-client">
+        <configfile finalname="etc/org.opendaylight.transportpce.dmaap.cfg" override="false">
+            mvn:${project.groupId}/${project.artifactId}/${project.version}/cfg/config
+        </configfile>
+    </feature>
+</features>
\ No newline at end of file
diff --git a/features/odl-transportpce-dmaap-client/src/main/resources/org.opendaylight.transportpce.dmaap.cfg b/features/odl-transportpce-dmaap-client/src/main/resources/org.opendaylight.transportpce.dmaap.cfg
new file mode 100644 (file)
index 0000000..db11068
--- /dev/null
@@ -0,0 +1,3 @@
+dmaap.baseUrl=${env:DMAAP_BASE_URL:-http://localhost:8080}
+dmaap.username=${env:DMAAP_USERNAME:+username}
+dmaap.password=${env:DMAAP_PASSWORD:+password}
\ No newline at end of file
diff --git a/features/odl-transportpce-nbinotifications/pom.xml b/features/odl-transportpce-nbinotifications/pom.xml
new file mode 100644 (file)
index 0000000..29469b1
--- /dev/null
@@ -0,0 +1,68 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright © 2021 Orange and others. All rights reserved. This program
+    and the accompanying materials are made available under the terms of the
+    Eclipse Public License v1.0 which accompanies this distribution, and is available
+    at http://www.eclipse.org/legal/epl-v10.html INTERNAL -->
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+
+    <parent>
+        <groupId>org.opendaylight.odlparent</groupId>
+        <artifactId>single-feature-parent</artifactId>
+        <version>8.1.0</version>
+        <relativePath />
+    </parent>
+
+    <groupId>org.opendaylight.transportpce</groupId>
+    <artifactId>odl-transportpce-nbinotifications</artifactId>
+    <version>3.0.0-SNAPSHOT</version>
+    <packaging>feature</packaging>
+
+    <name>OpenDaylight :: transportpce :: nbinotifications</name>
+    <properties>
+    <!-- skipped because we are using config file as artifact and it is not installed before running test -->
+        <skip.karaf.featureTest>true</skip.karaf.featureTest>
+    </properties>
+    <dependencies>
+        <dependency>
+            <groupId>org.opendaylight.transportpce</groupId>
+            <artifactId>odl-transportpce</artifactId>
+            <version>${project.version}</version>
+            <classifier>features</classifier>
+            <type>xml</type>
+        </dependency>
+        <dependency>
+            <groupId>${project.groupId}</groupId>
+            <artifactId>transportpce-nbinotifications</artifactId>
+            <version>${project.version}</version>
+        </dependency>
+    </dependencies>
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.codehaus.mojo</groupId>
+                <artifactId>build-helper-maven-plugin</artifactId>
+                <executions>
+                    <execution>
+                        <id>attach-dmaap-artifact</id>
+                        <phase>package</phase>
+                        <goals>
+                            <goal>attach-artifact</goal>
+                        </goals>
+                        <configuration>
+                            <artifacts>
+                                <artifact>
+                                    <file>${basedir}/src/main/resources/org.opendaylight.transportpce.nbinotifications.cfg</file>
+                                    <type>cfg</type>
+                                    <classifier>config</classifier>
+                                </artifact>
+                            </artifacts>
+                        </configuration>
+                    </execution>
+                </executions>
+            </plugin>
+        </plugins>
+    </build>
+</project>
diff --git a/features/odl-transportpce-nbinotifications/src/main/feature/feature.xml b/features/odl-transportpce-nbinotifications/src/main/feature/feature.xml
new file mode 100644 (file)
index 0000000..5e99a52
--- /dev/null
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+<!-- Copyright © 2021 Orange and others. All rights reserved. This program
+    and the accompanying materials are made available under the terms of the
+    Eclipse Public License v1.0 which accompanies this distribution, and is available
+    at http://www.eclipse.org/legal/epl-v10.html INTERNAL -->
+<features xmlns="http://karaf.apache.org/xmlns/features/v1.4.0" name="odl-transportpce-nbinotifications">
+    <feature name="odl-transportpce-nbinotifications">
+        <configfile finalname="etc/org.opendaylight.transportpce.nbinotififications.cfg" override="false">
+            mvn:${project.groupId}/${project.artifactId}/${project.version}/cfg/config
+        </configfile>
+    </feature>
+</features>
\ No newline at end of file
diff --git a/features/odl-transportpce-nbinotifications/src/main/resources/org.opendaylight.transportpce.nbinotifications.cfg b/features/odl-transportpce-nbinotifications/src/main/resources/org.opendaylight.transportpce.nbinotifications.cfg
new file mode 100644 (file)
index 0000000..ea5c7c0
--- /dev/null
@@ -0,0 +1,2 @@
+suscriber.server=${env:KAFKA_SERVER:-localhost:9092}
+publisher.server=${env:KAFKA_SERVER:-localhost:9092}
index 95532599fb9766e0aa6a1858f6b1ee20defdf109..8434611e9244eacf9e80eadcf22a943c692e0a64 100644 (file)
@@ -26,5 +26,7 @@ and is available at http://www.eclipse.org/legal/epl-v10.html INTERNAL
     <module>odl-transportpce</module>
     <module>odl-transportpce-tapi</module>
     <module>odl-transportpce-inventory</module>
+    <module>odl-transportpce-nbinotifications</module>
+    <module>odl-transportpce-dmaap-client</module>
   </modules>
 </project>
index f71a9d80b0da30cf16cb030d6756a12820f26348..570926de42da0721d9f5699bd9b3130186c09249 100644 (file)
@@ -66,7 +66,22 @@ and is available at http://www.eclipse.org/legal/epl-v10.html INTERNAL
       <type>xml</type>
       <scope>runtime</scope>
     </dependency>
-
+    <dependency>
+      <groupId>${project.groupId}</groupId>
+      <artifactId>odl-transportpce-nbinotifications</artifactId>
+      <version>${project.version}</version>
+      <classifier>features</classifier>
+      <type>xml</type>
+      <scope>runtime</scope>
+    </dependency>
+    <dependency>
+      <groupId>${project.groupId}</groupId>
+      <artifactId>odl-transportpce-dmaap-client</artifactId>
+      <version>${project.version}</version>
+      <classifier>features</classifier>
+      <type>xml</type>
+      <scope>runtime</scope>
+    </dependency>
   </dependencies>
 
   <build>
index 8ee8a1275341ed380a2efdae2f9186ac5779192c..891b72caf049dcbb0e4195bd60f2f4c4f9a2f43a 100644 (file)
     </properties>
 
     <dependencies>
+        <!-- for parsing command line arguments -->
+        <dependency>
+            <groupId>commons-cli</groupId>
+            <artifactId>commons-cli</artifactId>
+            <version>1.4</version>
+        </dependency>
 
         <!-- TPCE Models - BEGIN -->
         <dependency>
             <artifactId>transportpce-tapi</artifactId>
             <version>${transportpce.version}</version>
         </dependency>
+        <dependency>
+            <groupId>org.opendaylight.transportpce</groupId>
+            <artifactId>transportpce-nbinotifications</artifactId>
+            <version>${transportpce.version}</version>
+        </dependency>
         <!-- TPCE bundles - END -->
 
         <dependency>
index 9cba68c009e353678721847f44d3f422c18f1df0..b979e08477de27bcd9b9171215b74d531d88caa5 100644 (file)
@@ -34,21 +34,32 @@ import java.nio.file.Files;
 import java.nio.file.Path;
 import java.nio.file.Paths;
 import java.util.concurrent.ExecutionException;
+
+import org.apache.commons.cli.CommandLine;
+import org.apache.commons.cli.DefaultParser;
+import org.apache.commons.cli.HelpFormatter;
+import org.apache.commons.cli.Option;
+import org.apache.commons.cli.Options;
+import org.apache.commons.cli.ParseException;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 public class Main {
 
+    private static final String RESTCONF_OPTION_NAME = "restconf";
+
+    private static final String NBINOTIFICATION_OPTION_NAME = "nbinotification";
+
     private static final Logger LOG = LoggerFactory.getLogger(Main.class);
 
     private ShutdownHook shutdownHook;
 
     public void start() {
-        start(new String[] {}, false);
+        start(null, false, false);
     }
 
     @SuppressWarnings("checkstyle:Illegalcatch")
-    public void start(String[] args, boolean registerShutdownHook) {
+    public void start(String restConfConfigurationFile, boolean activateNbiNotification, boolean registerShutdownHook) {
         long startTime = System.nanoTime();
         TpceBanner.print();
         RestConfConfiguration restConfConfig = null;
@@ -57,8 +68,8 @@ public class Main {
             ControllerConfiguration singleNodeConfiguration = ControllerConfigUtils
                     .getDefaultSingleNodeConfiguration(TPCEUtils.getYangModels());
             // 2. get RESTCONF NBP configuration
-            if (args.length == 1) {
-                Path configPath = Paths.get(args[0]);
+            if (restConfConfigurationFile != null) {
+                Path configPath = Paths.get(restConfConfigurationFile);
                 LOG.info("Using restconf configuration from file {} ...", configPath);
                 restConfConfig = RestConfConfigUtils.getRestConfConfiguration(Files.newInputStream(configPath));
 
@@ -72,7 +83,7 @@ public class Main {
             restConfConfig.setJsonRestconfServiceType(JsonRestConfServiceType.DRAFT_02);
             // 3. NETCONF SBP configuration
             NetconfConfiguration netconfSBPConfig = NetconfConfigUtils.createDefaultNetconfConfiguration();
-            startLighty(singleNodeConfiguration, restConfConfig, netconfSBPConfig, registerShutdownHook);
+            startLighty(singleNodeConfiguration, restConfConfig, netconfSBPConfig, registerShutdownHook, activateNbiNotification);
             float duration = (System.nanoTime() - startTime) / 1_000_000f;
             LOG.info("lighty.io and RESTCONF-NETCONF started in {}ms", duration);
         } catch (ConfigurationException | ExecutionException | IOException e) {
@@ -91,9 +102,33 @@ public class Main {
         }
     }
 
+    /**
+     * Build options for command line arguments
+     * @return
+     */
+    private static Options buildOptions() {
+        Option restconfFileOption = Option.builder(RESTCONF_OPTION_NAME)
+                .desc("Restconf configuration file")
+                .argName(RESTCONF_OPTION_NAME)
+                .hasArg(true)
+                .required(false)
+                .build();
+        Option useNbiNotificationsOption = Option.builder(NBINOTIFICATION_OPTION_NAME)
+                .desc("Activate NBI notifications feature")
+                .argName(NBINOTIFICATION_OPTION_NAME)
+                .hasArg(false)
+                .required(false)
+                .build();
+        Options options = new Options();
+        options.addOption(restconfFileOption);
+        options.addOption(useNbiNotificationsOption);
+        return options;
+    }
+
     private void startLighty(ControllerConfiguration controllerConfiguration,
             RestConfConfiguration restConfConfiguration, NetconfConfiguration netconfSBPConfiguration,
-            boolean registerShutdownHook) throws ConfigurationException, ExecutionException, InterruptedException {
+            boolean registerShutdownHook, boolean activateNbiNotification)
+                    throws ConfigurationException, ExecutionException, InterruptedException {
 
         // 1. initialize and start Lighty controller (MD-SAL, Controller, YangTools,
         // Akka)
@@ -121,7 +156,7 @@ public class Main {
         netconfSouthboundPlugin.start().get();
 
         // 4. start TransportPCE beans
-        TransportPCE transportPCE = new TransportPCEImpl(lightyController.getServices());
+        TransportPCE transportPCE = new TransportPCEImpl(lightyController.getServices(), activateNbiNotification);
         transportPCE.start().get();
 
         // 5. Register shutdown hook for graceful shutdown.
@@ -136,8 +171,23 @@ public class Main {
     }
 
     public static void main(String[] args) {
-        Main app = new Main();
-        app.start(args, true);
+        Options options = buildOptions();
+        try {
+            CommandLine commandLine = new DefaultParser().parse(options, args);
+            String restConfConfigurationFile = commandLine.getOptionValue(RESTCONF_OPTION_NAME, null);
+            boolean useNbiNotifications = commandLine.hasOption(NBINOTIFICATION_OPTION_NAME);
+            Main app = new Main();
+            app.start(restConfConfigurationFile, useNbiNotifications, true);
+        } catch (ParseException e) {
+            HelpFormatter formatter = new HelpFormatter();
+            formatter.printHelp(
+                    "java -ms<size> -mx<size> -XX:MaxMetaspaceSize=<size> -jar tpce.jar "
+                    + "[-restconf <restconfConfigurationFile>] [-nbinotification]"
+                    +" e.g. java -ms128m -mx512m -XX:MaxMetaspaceSize=128m -jar tpce.jar"
+                    + "-restconf ../src/test/resources/config.json -nbinotification",
+                    options);
+            System.exit(1);
+        }
     }
 
     private static class ShutdownHook extends Thread {
index fe1c59fa6c152f9bc100c09f1a632bedb9881c49..f2542536c1d8fe5bb0b624d683357dba30e9ae54 100644 (file)
@@ -9,6 +9,10 @@ package io.lighty.controllers.tpce.module;
 
 import io.lighty.core.controller.api.AbstractLightyModule;
 import io.lighty.core.controller.api.LightyServices;
+
+import java.util.Arrays;
+import java.util.List;
+
 import org.opendaylight.transportpce.common.crossconnect.CrossConnect;
 import org.opendaylight.transportpce.common.crossconnect.CrossConnectImpl;
 import org.opendaylight.transportpce.common.crossconnect.CrossConnectImpl121;
@@ -29,6 +33,7 @@ import org.opendaylight.transportpce.common.openroadminterfaces.OpenRoadmInterfa
 import org.opendaylight.transportpce.common.openroadminterfaces.OpenRoadmInterfacesImpl121;
 import org.opendaylight.transportpce.common.openroadminterfaces.OpenRoadmInterfacesImpl221;
 import org.opendaylight.transportpce.common.openroadminterfaces.OpenRoadmInterfacesImpl710;
+import org.opendaylight.transportpce.nbinotifications.impl.NbiNotificationsProvider;
 import org.opendaylight.transportpce.networkmodel.NetConfTopologyListener;
 import org.opendaylight.transportpce.networkmodel.NetworkModelProvider;
 import org.opendaylight.transportpce.networkmodel.NetworkUtilsImpl;
@@ -98,8 +103,15 @@ public class TransportPCEImpl extends AbstractLightyModule implements TransportP
     private final TapiProvider tapiProvider;
     // service-handler beans
     private final ServicehandlerProvider servicehandlerProvider;
+    // nbi-notifications beans
+    private NbiNotificationsProvider nbiNotificationsProvider;
+    /**
+     * List of publisher topics.
+     */
+    private final List<String> publisherTopicList =
+            Arrays.asList("PceListener", "ServiceHandlerOperations", "ServiceHandler", "RendererListener");
 
-    public TransportPCEImpl(LightyServices lightyServices) {
+    public TransportPCEImpl(LightyServices lightyServices, boolean activateNbiNotification) {
         LOG.info("Initializing transaction providers ...");
         deviceTransactionManager = new DeviceTransactionManagerImpl(lightyServices.getBindingMountPointService(),
                 MAX_DURATION_TO_SUBMIT_TRANSACTION);
@@ -175,6 +187,12 @@ public class TransportPCEImpl extends AbstractLightyModule implements TransportP
                 serviceDataStoreOperations, pceListenerImpl, rendererListenerImpl, networkModelListenerImpl,
                 servicehandler);
         tapiProvider = initTapi(lightyServices, servicehandler);
+        if(activateNbiNotification) {
+            LOG.info("Creating nbi-notifications beans ...");
+            nbiNotificationsProvider = new NbiNotificationsProvider(
+                    publisherTopicList, null, null, lightyServices.getRpcProviderService(),
+                    lightyServices.getNotificationService(), lightyServices.getAdapterContext().currentSerializer());
+        }
     }
 
     @Override
@@ -191,12 +209,16 @@ public class TransportPCEImpl extends AbstractLightyModule implements TransportP
         servicehandlerProvider.init();
         LOG.info("Initializing tapi provider ...");
         tapiProvider.init();
+        LOG.info("Initializing nbi-notifications provider ...");
+        nbiNotificationsProvider.init();
         LOG.info("Init done.");
         return true;
     }
 
     @Override
     protected boolean stopProcedure() {
+        nbiNotificationsProvider.close();
+        LOG.info("Shutting down nbi-notifications provider ...");
         tapiProvider.close();
         LOG.info("Shutting down service-handler provider ...");
         servicehandlerProvider.close();
index d97f525cf35bdfe16f848563883443ae5e238d43..9c2cfc1a615d69aba53f593fefeb9de2d62817aa 100644 (file)
@@ -255,6 +255,8 @@ public final class TPCEUtils {
             org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.restconf.rev131019.$YangModuleInfoImpl
                     .getInstance(),
             org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.tapi.rev180928.$YangModuleInfoImpl
+                    .getInstance(),
+            org.opendaylight.yang.gen.v1.nbi.notifications.rev201130.$YangModuleInfoImpl
                     .getInstance());
 
     private static final Set<YangModuleInfo> TPCE_YANG_MODEL = Stream.concat(
index 096c25d34a1bfad0b1dbc4800e7361f5d582b5eb..de130a4db56548b2e51af3d34c31aa2051ea95b0 100644 (file)
@@ -48,7 +48,7 @@ public class MaintTest {
 
     @Test
     public void startNoConfigFileTest() throws Exception {
-        main.start(new String[0], true);
+        main.start(null, false, true);
         ContentResponse response = client.GET("http://localhost:8181/restconf/config/ietf-network:networks/network/openroadm-topology");
         assertEquals("Response code should be 200", 200, response.getStatus());
     }
@@ -56,8 +56,7 @@ public class MaintTest {
     @Test
     public void startConfigFileTest() throws Exception {
         File configFile = new File("src/test/resources/config.json");
-        String[] args = {configFile.getAbsolutePath()};
-        main.start(args, true);
+        main.start(configFile.getAbsolutePath(), false, true);
         ContentResponse response = client.GET("http://localhost:8888/restconfCustom/config/ietf-network:networks/network/openroadm-topology");
         assertEquals("Response code should be 200", 200, response.getStatus());
     }
diff --git a/nbinotifications/pom.xml b/nbinotifications/pom.xml
new file mode 100644 (file)
index 0000000..a1b0d9e
--- /dev/null
@@ -0,0 +1,69 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright © 2020 Orange and others. All rights reserved. This program
+    and the accompanying materials are made available under the terms of the
+    Eclipse Public License v1.0 which accompanies this distribution, and is available
+    at http://www.eclipse.org/legal/epl-v10.html INTERNAL -->
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+
+    <parent>
+        <groupId>org.opendaylight.mdsal</groupId>
+        <artifactId>binding-parent</artifactId>
+        <version>7.0.5</version>
+        <relativePath />
+    </parent>
+
+    <groupId>org.opendaylight.transportpce</groupId>
+    <artifactId>transportpce-nbinotifications</artifactId>
+    <version>3.0.0-SNAPSHOT</version>
+    <packaging>bundle</packaging>
+
+    <properties>
+        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+        <kafka.version>2.6.0</kafka.version>
+    </properties>
+    <dependencies>
+        <dependency>
+            <groupId>${project.groupId}</groupId>
+            <artifactId>transportpce-common</artifactId>
+            <version>${project.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>${project.groupId}</groupId>
+            <artifactId>transportpce-api</artifactId>
+            <version>${project.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>${project.groupId}.ordmodels</groupId>
+            <artifactId>transportpce-ordmodels-service</artifactId>
+            <version>${project.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.kafka</groupId>
+            <artifactId>kafka-clients</artifactId>
+            <version>${kafka.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.opendaylight.mdsal</groupId>
+            <artifactId>mdsal-binding-api</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.opendaylight.mdsal</groupId>
+            <artifactId>mdsal-binding-dom-adapter</artifactId>
+        </dependency>
+        <!-- Testing Dependencies -->
+        <dependency>
+            <groupId>${project.groupId}</groupId>
+            <artifactId>test-common</artifactId>
+            <version>${project.version}</version>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>com.fasterxml.jackson.core</groupId>
+            <artifactId>jackson-databind</artifactId>
+            <scope>test</scope>
+        </dependency>
+    </dependencies>
+</project>
diff --git a/nbinotifications/src/main/java/org/opendaylight/transportpce/nbinotifications/consumer/Subscriber.java b/nbinotifications/src/main/java/org/opendaylight/transportpce/nbinotifications/consumer/Subscriber.java
new file mode 100644 (file)
index 0000000..cb044b1
--- /dev/null
@@ -0,0 +1,72 @@
+/*
+ * Copyright © 2020 Orange, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.transportpce.nbinotifications.consumer;
+
+import com.google.common.annotations.VisibleForTesting;
+import java.time.Duration;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Properties;
+import org.apache.kafka.clients.consumer.Consumer;
+import org.apache.kafka.clients.consumer.ConsumerConfig;
+import org.apache.kafka.clients.consumer.ConsumerRecord;
+import org.apache.kafka.clients.consumer.ConsumerRecords;
+import org.apache.kafka.clients.consumer.KafkaConsumer;
+import org.apache.kafka.common.serialization.StringDeserializer;
+import org.opendaylight.transportpce.common.converter.JsonStringConverter;
+import org.opendaylight.transportpce.nbinotifications.serialization.ConfigConstants;
+import org.opendaylight.transportpce.nbinotifications.serialization.NotificationServiceDeserializer;
+import org.opendaylight.transportpce.nbinotifications.utils.NbiNotificationsUtils;
+import org.opendaylight.yang.gen.v1.nbi.notifications.rev201130.get.notifications.service.output.NotificationService;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class Subscriber {
+    private static final Logger LOG = LoggerFactory.getLogger(Subscriber.class);
+
+    private final Consumer<String, NotificationService> consumer;
+
+    public Subscriber(String id, String groupId, String suscriberServer,
+            JsonStringConverter<org.opendaylight.yang.gen.v1
+                .nbi.notifications.rev201130.NotificationService> deserializer) {
+        Properties propsConsumer = NbiNotificationsUtils.loadProperties("subscriber.properties");
+        propsConsumer.put(ConsumerConfig.GROUP_ID_CONFIG, groupId);
+        propsConsumer.put(ConsumerConfig.CLIENT_ID_CONFIG, id);
+        propsConsumer.put(ConsumerConfig.KEY_DESERIALIZER_CLASS_CONFIG, StringDeserializer.class);
+        propsConsumer.put(ConsumerConfig.VALUE_DESERIALIZER_CLASS_CONFIG , NotificationServiceDeserializer.class);
+        propsConsumer.put(ConfigConstants.CONVERTER , deserializer);
+        if (suscriberServer != null && !suscriberServer.isBlank()) {
+            propsConsumer.put(ConsumerConfig.BOOTSTRAP_SERVERS_CONFIG, suscriberServer);
+        }
+        LOG.info("Suscribing for group id {}, client config id {} with properties {}", groupId, id, propsConsumer);
+        consumer = new KafkaConsumer<>(propsConsumer);
+    }
+
+    public List<NotificationService> subscribeService(String topicName) {
+        LOG.info("Subscribe request to topic '{}' ", topicName);
+        consumer.subscribe(Collections.singleton(topicName));
+        final ConsumerRecords<String, NotificationService> consumerRecords = consumer.poll(Duration.ofMillis(1000));
+        List<NotificationService> notificationServiceList = new ArrayList<>();
+        YangInstanceIdentifier.of(NotificationService.QNAME);
+        for (ConsumerRecord<String, NotificationService> record : consumerRecords) {
+            if (record.value() != null) {
+                notificationServiceList.add(record.value());
+            }
+        }
+        LOG.info("Getting records '{}' ", notificationServiceList);
+        consumer.unsubscribe();
+        consumer.close();
+        return notificationServiceList;
+    }
+
+    @VisibleForTesting public Subscriber(Consumer<String, NotificationService> consumer) {
+        this.consumer = consumer;
+    }
+}
diff --git a/nbinotifications/src/main/java/org/opendaylight/transportpce/nbinotifications/impl/NbiNotificationsImpl.java b/nbinotifications/src/main/java/org/opendaylight/transportpce/nbinotifications/impl/NbiNotificationsImpl.java
new file mode 100644 (file)
index 0000000..073ce49
--- /dev/null
@@ -0,0 +1,51 @@
+/*
+ * Copyright © 2020 Orange, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.transportpce.nbinotifications.impl;
+
+import com.google.common.util.concurrent.ListenableFuture;
+import java.util.List;
+import org.opendaylight.transportpce.common.converter.JsonStringConverter;
+import org.opendaylight.transportpce.nbinotifications.consumer.Subscriber;
+import org.opendaylight.yang.gen.v1.nbi.notifications.rev201130.GetNotificationsServiceInput;
+import org.opendaylight.yang.gen.v1.nbi.notifications.rev201130.GetNotificationsServiceOutput;
+import org.opendaylight.yang.gen.v1.nbi.notifications.rev201130.GetNotificationsServiceOutputBuilder;
+import org.opendaylight.yang.gen.v1.nbi.notifications.rev201130.NbiNotificationsService;
+import org.opendaylight.yang.gen.v1.nbi.notifications.rev201130.get.notifications.service.output.NotificationService;
+import org.opendaylight.yangtools.yang.common.RpcResult;
+import org.opendaylight.yangtools.yang.common.RpcResultBuilder;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class NbiNotificationsImpl implements NbiNotificationsService {
+    private static final Logger LOG = LoggerFactory.getLogger(NbiNotificationsImpl.class);
+    private final JsonStringConverter<org.opendaylight.yang.gen.v1
+        .nbi.notifications.rev201130.NotificationService> converter;
+    private final String server;
+
+    public NbiNotificationsImpl(JsonStringConverter<org.opendaylight.yang.gen.v1
+            .nbi.notifications.rev201130.NotificationService> converter, String server) {
+        this.converter = converter;
+        this.server = server;
+    }
+
+    @Override
+    public ListenableFuture<RpcResult<GetNotificationsServiceOutput>> getNotificationsService(
+            GetNotificationsServiceInput input) {
+        LOG.info("RPC getNotificationsService received");
+        if (input == null || input.getIdConsumer() == null || input.getGroupId() == null) {
+            LOG.warn("Missing mandatory params for input {}", input);
+            return RpcResultBuilder.success(new GetNotificationsServiceOutputBuilder().build()).buildFuture();
+        }
+        Subscriber subscriber = new Subscriber(input.getIdConsumer(), input.getGroupId(), server, converter);
+        List<NotificationService> notificationServiceList = subscriber
+                .subscribeService(input.getConnectionType().getName());
+        GetNotificationsServiceOutputBuilder output = new GetNotificationsServiceOutputBuilder()
+                .setNotificationService(notificationServiceList);
+        return RpcResultBuilder.success(output.build()).buildFuture();
+    }
+}
diff --git a/nbinotifications/src/main/java/org/opendaylight/transportpce/nbinotifications/impl/NbiNotificationsProvider.java b/nbinotifications/src/main/java/org/opendaylight/transportpce/nbinotifications/impl/NbiNotificationsProvider.java
new file mode 100644 (file)
index 0000000..5f41034
--- /dev/null
@@ -0,0 +1,77 @@
+/*
+ * Copyright © 2020 Orange, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.transportpce.nbinotifications.impl;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import org.opendaylight.mdsal.binding.api.NotificationService;
+import org.opendaylight.mdsal.binding.api.RpcProviderService;
+import org.opendaylight.mdsal.binding.dom.codec.spi.BindingDOMCodecServices;
+import org.opendaylight.transportpce.common.converter.JsonStringConverter;
+import org.opendaylight.transportpce.nbinotifications.listener.NbiNotificationsListenerImpl;
+import org.opendaylight.transportpce.nbinotifications.producer.Publisher;
+import org.opendaylight.yang.gen.v1.nbi.notifications.rev201130.NbiNotificationsListener;
+import org.opendaylight.yang.gen.v1.nbi.notifications.rev201130.NbiNotificationsService;
+import org.opendaylight.yangtools.concepts.ListenerRegistration;
+import org.opendaylight.yangtools.concepts.ObjectRegistration;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class NbiNotificationsProvider {
+
+    private static final Logger LOG = LoggerFactory.getLogger(NbiNotificationsProvider.class);
+    private static Map<String, Publisher> publishersMap =  new HashMap<>();
+
+    private final RpcProviderService rpcService;
+    private ObjectRegistration<NbiNotificationsService> rpcRegistration;
+    private ListenerRegistration<NbiNotificationsListener> listenerRegistration;
+    private NotificationService notificationService;
+    private final JsonStringConverter<org.opendaylight.yang.gen.v1
+        .nbi.notifications.rev201130.NotificationService> converter;
+    private final String suscriberServer;
+
+
+    public NbiNotificationsProvider(List<String> topics,
+            String suscriberServer, String publisherServer,
+            RpcProviderService rpcProviderService, NotificationService notificationService,
+            BindingDOMCodecServices bindingDOMCodecServices) {
+        this.rpcService = rpcProviderService;
+        this.notificationService = notificationService;
+        converter =  new JsonStringConverter<>(bindingDOMCodecServices);
+        for (String topic: topics) {
+            LOG.info("Creating publisher for topic {}", topic);
+            publishersMap.put(topic, new Publisher(topic, publisherServer, converter));
+        }
+        this.suscriberServer = suscriberServer;
+    }
+
+    /**
+     * Method called when the blueprint container is created.
+     */
+    public void init() {
+        LOG.info("NbiNotificationsProvider Session Initiated");
+        rpcRegistration = rpcService.registerRpcImplementation(NbiNotificationsService.class,
+                new NbiNotificationsImpl(converter, suscriberServer));
+        listenerRegistration = notificationService.registerNotificationListener(
+                new NbiNotificationsListenerImpl(publishersMap));
+    }
+
+    /**
+     * Method called when the blueprint container is destroyed.
+     */
+    public void close() {
+        for (Publisher publisher : publishersMap.values()) {
+            publisher.close();
+        }
+        rpcRegistration.close();
+        listenerRegistration.close();
+        LOG.info("NbiNotificationsProvider Closed");
+    }
+
+}
diff --git a/nbinotifications/src/main/java/org/opendaylight/transportpce/nbinotifications/listener/NbiNotificationsListenerImpl.java b/nbinotifications/src/main/java/org/opendaylight/transportpce/nbinotifications/listener/NbiNotificationsListenerImpl.java
new file mode 100644 (file)
index 0000000..0bcdf6b
--- /dev/null
@@ -0,0 +1,45 @@
+/*
+ * Copyright © 2020 Orange, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.transportpce.nbinotifications.listener;
+
+import java.util.HashMap;
+import java.util.Map;
+import org.opendaylight.transportpce.nbinotifications.producer.Publisher;
+import org.opendaylight.yang.gen.v1.nbi.notifications.rev201130.NbiNotificationsListener;
+import org.opendaylight.yang.gen.v1.nbi.notifications.rev201130.NotificationServiceBuilder;
+import org.opendaylight.yang.gen.v1.nbi.notifications.rev201130.PublishNotificationService;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class NbiNotificationsListenerImpl implements NbiNotificationsListener {
+    private static final Logger LOG = LoggerFactory.getLogger(NbiNotificationsListenerImpl.class);
+    private Map<String, Publisher> publishersMap =  new HashMap<>();
+
+    public NbiNotificationsListenerImpl(Map<String, Publisher> publishersMap) {
+        this.publishersMap = publishersMap;
+    }
+
+    @Override
+    public void onPublishNotificationService(PublishNotificationService notification) {
+        LOG.info("Receiving request for publishing notification service");
+        String topic = notification.getTopic();
+        if (!publishersMap.containsKey(topic)) {
+            LOG.error("Unknown topic {}", topic);
+            return;
+        }
+        Publisher publisher = publishersMap.get(topic);
+        publisher.sendEvent(new NotificationServiceBuilder().setCommonId(notification.getCommonId())
+                .setConnectionType(notification.getConnectionType()).setMessage(notification.getMessage())
+                .setOperationalState(notification.getOperationalState())
+                .setResponseFailed(notification.getResponseFailed())
+                .setServiceAEnd(notification.getServiceAEnd()).setServiceName(notification.getServiceName())
+                .setServiceZEnd(notification.getServiceZEnd()).build());
+
+    }
+
+}
diff --git a/nbinotifications/src/main/java/org/opendaylight/transportpce/nbinotifications/producer/Publisher.java b/nbinotifications/src/main/java/org/opendaylight/transportpce/nbinotifications/producer/Publisher.java
new file mode 100644 (file)
index 0000000..21295a9
--- /dev/null
@@ -0,0 +1,59 @@
+/*
+ * Copyright © 2020 Orange, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.transportpce.nbinotifications.producer;
+
+import com.google.common.annotations.VisibleForTesting;
+import java.util.Properties;
+import org.apache.kafka.clients.producer.KafkaProducer;
+import org.apache.kafka.clients.producer.Producer;
+import org.apache.kafka.clients.producer.ProducerConfig;
+import org.apache.kafka.clients.producer.ProducerRecord;
+import org.apache.kafka.common.serialization.StringSerializer;
+import org.opendaylight.transportpce.common.converter.JsonStringConverter;
+import org.opendaylight.transportpce.nbinotifications.serialization.ConfigConstants;
+import org.opendaylight.transportpce.nbinotifications.serialization.NotificationServiceSerializer;
+import org.opendaylight.transportpce.nbinotifications.utils.NbiNotificationsUtils;
+import org.opendaylight.yang.gen.v1.nbi.notifications.rev201130.NotificationService;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class Publisher {
+    private static final Logger LOG = LoggerFactory.getLogger(Publisher.class);
+
+    private final String id;
+    private final Producer<String, NotificationService> producer;
+
+    public Publisher(String id, String publisherServer, JsonStringConverter<NotificationService> serializer) {
+        Properties properties = NbiNotificationsUtils.loadProperties("publisher.properties");
+        properties.put(ProducerConfig.CLIENT_ID_CONFIG, id);
+        if (publisherServer != null && !publisherServer.isBlank()) {
+            properties.put(ProducerConfig.BOOTSTRAP_SERVERS_CONFIG, publisherServer);
+        }
+        properties.put(ProducerConfig.KEY_SERIALIZER_CLASS_CONFIG, StringSerializer.class);
+        properties.put(ProducerConfig.VALUE_SERIALIZER_CLASS_CONFIG , NotificationServiceSerializer.class);
+        properties.put(ConfigConstants.CONVERTER , serializer);
+        LOG.info("Creationg publisher for id {} with properties {}", id, properties);
+        producer = new KafkaProducer<>(properties);
+        this.id = id;
+    }
+
+    @VisibleForTesting Publisher(String id, Producer<String, NotificationService> producer) {
+        this.producer = producer;
+        this.id = id;
+    }
+
+    public void close() {
+        producer.close();
+    }
+
+    public void sendEvent(NotificationService notificationService) {
+        LOG.info("SendEvent request to topic '{}' ", notificationService.getConnectionType().getName());
+        producer.send(new ProducerRecord<>(notificationService.getConnectionType().getName(), id, notificationService));
+        producer.flush();
+    }
+}
diff --git a/nbinotifications/src/main/java/org/opendaylight/transportpce/nbinotifications/serialization/ConfigConstants.java b/nbinotifications/src/main/java/org/opendaylight/transportpce/nbinotifications/serialization/ConfigConstants.java
new file mode 100644 (file)
index 0000000..b10b016
--- /dev/null
@@ -0,0 +1,16 @@
+/*
+ * Copyright © 2021 Orange, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.transportpce.nbinotifications.serialization;
+
+public final class ConfigConstants {
+    private ConfigConstants() {
+    }
+
+    public static final String CONVERTER = "converter";
+
+}
diff --git a/nbinotifications/src/main/java/org/opendaylight/transportpce/nbinotifications/serialization/NotificationServiceDeserializer.java b/nbinotifications/src/main/java/org/opendaylight/transportpce/nbinotifications/serialization/NotificationServiceDeserializer.java
new file mode 100644 (file)
index 0000000..95f10fb
--- /dev/null
@@ -0,0 +1,67 @@
+/*
+ * Copyright © 2021 Orange, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.transportpce.nbinotifications.serialization;
+
+import java.nio.charset.StandardCharsets;
+import java.util.Map;
+import org.apache.kafka.common.serialization.Deserializer;
+import org.opendaylight.transportpce.common.converter.JsonStringConverter;
+import org.opendaylight.yang.gen.v1.nbi.notifications.rev201130.get.notifications.service.output.NotificationService;
+import org.opendaylight.yang.gen.v1.nbi.notifications.rev201130.get.notifications.service.output.NotificationServiceBuilder;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.codec.gson.JSONCodecFactorySupplier;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class NotificationServiceDeserializer implements Deserializer<NotificationService> {
+    private static final Logger LOG = LoggerFactory.getLogger(NotificationServiceDeserializer.class);
+    private JsonStringConverter<org.opendaylight.yang.gen.v1
+        .nbi.notifications.rev201130.NotificationService> converter;
+
+    @SuppressWarnings("unchecked")
+    @Override
+    public void configure(Map<String, ?> configs, boolean isKey) {
+        LOG.info("Deserializer configuration {}", configs);
+        if (configs.containsKey(ConfigConstants.CONVERTER)
+                && configs.get(ConfigConstants.CONVERTER) instanceof JsonStringConverter<?>) {
+            converter = (JsonStringConverter<org.opendaylight.yang.gen.v1
+                    .nbi.notifications.rev201130.NotificationService>) configs
+                    .get(ConfigConstants.CONVERTER);
+        }
+    }
+
+    @Override
+    public NotificationService deserialize(String topic, byte[] data) {
+        if (converter == null) {
+            throw new IllegalArgumentException(
+                    "Converter should be configured through configure method of deserializer");
+        }
+        String value = new String(data, StandardCharsets.UTF_8);
+        // The message published is
+        // org.opendaylight.yang.gen.v1.nbi.notifications.rev201130.NotificationService
+        // we have to map it to
+        // org.opendaylight.yang.gen
+        // .v1.nbi.notifications.rev201130.get.notifications.service.output.NotificationService
+        org.opendaylight.yang.gen.v1.nbi.notifications.rev201130.NotificationService mappedString = converter
+                .createDataObjectFromJsonString(YangInstanceIdentifier.of(
+                        org.opendaylight.yang.gen.v1.nbi.notifications.rev201130.NotificationService.QNAME),
+                        value,
+                        JSONCodecFactorySupplier.RFC7951);
+        if (mappedString != null) {
+            LOG.info("Reading event {}", mappedString);
+            return new NotificationServiceBuilder().setCommonId(mappedString.getCommonId())
+                    .setConnectionType(mappedString.getConnectionType()).setMessage(mappedString.getMessage())
+                    .setOperationalState(mappedString.getOperationalState())
+                    .setResponseFailed(mappedString.getResponseFailed()).setServiceName(mappedString.getServiceName())
+                    .setServiceAEnd(mappedString.getServiceAEnd()).setServiceZEnd(mappedString.getServiceZEnd())
+                    .build();
+        }
+        return null;
+    }
+
+}
diff --git a/nbinotifications/src/main/java/org/opendaylight/transportpce/nbinotifications/serialization/NotificationServiceSerializer.java b/nbinotifications/src/main/java/org/opendaylight/transportpce/nbinotifications/serialization/NotificationServiceSerializer.java
new file mode 100644 (file)
index 0000000..eb99874
--- /dev/null
@@ -0,0 +1,53 @@
+/*
+ * Copyright © 2021 Orange, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.transportpce.nbinotifications.serialization;
+
+import java.io.IOException;
+import java.nio.charset.StandardCharsets;
+import java.util.Map;
+import org.apache.kafka.common.serialization.Serializer;
+import org.opendaylight.transportpce.common.converter.JsonStringConverter;
+import org.opendaylight.yang.gen.v1.nbi.notifications.rev201130.NotificationService;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.codec.gson.JSONCodecFactorySupplier;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class NotificationServiceSerializer implements Serializer<NotificationService> {
+    private static final Logger LOG = LoggerFactory.getLogger(NotificationServiceSerializer.class);
+    private JsonStringConverter<NotificationService> converter;
+
+    @SuppressWarnings("unchecked")
+    @Override
+    public void configure(Map<String, ?> configs, boolean isKey) {
+        LOG.info("Deserializer configuration {}", configs);
+        if (configs.containsKey(ConfigConstants.CONVERTER)
+                && configs.get(ConfigConstants.CONVERTER) instanceof JsonStringConverter<?>) {
+            converter = (JsonStringConverter<NotificationService>) configs.get(ConfigConstants.CONVERTER);
+        }
+    }
+
+    @Override
+    public byte[] serialize(String topic, NotificationService data) {
+        if (converter == null) {
+            throw new IllegalArgumentException(
+                    "Converter should be" + "configured through configure method of serializer");
+        }
+        if (data == null) {
+            return new byte[0];
+        }
+        try {
+            InstanceIdentifier<NotificationService> iid = InstanceIdentifier.builder(NotificationService.class).build();
+            String serialized = converter.createJsonStringFromDataObject(iid, data, JSONCodecFactorySupplier.RFC7951);
+            LOG.info("Serialized event {}", serialized);
+            return serialized.getBytes(StandardCharsets.UTF_8);
+        } catch (IOException e) {
+            return new byte[0];
+        }
+    }
+}
diff --git a/nbinotifications/src/main/java/org/opendaylight/transportpce/nbinotifications/utils/NbiNotificationsUtils.java b/nbinotifications/src/main/java/org/opendaylight/transportpce/nbinotifications/utils/NbiNotificationsUtils.java
new file mode 100644 (file)
index 0000000..d1a4cee
--- /dev/null
@@ -0,0 +1,38 @@
+/*
+ * Copyright © 2020 Orange, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.transportpce.nbinotifications.utils;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Properties;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public final class NbiNotificationsUtils {
+
+    private static final Logger LOG = LoggerFactory.getLogger(NbiNotificationsUtils.class);
+
+    private NbiNotificationsUtils() {
+    }
+
+    public static Properties loadProperties(String propertyFileName) {
+        Properties props = new Properties();
+        InputStream inputStream = NbiNotificationsUtils.class.getClassLoader()
+                .getResourceAsStream(propertyFileName);
+        try {
+            if (inputStream != null) {
+                props.load(inputStream);
+            } else {
+                LOG.warn("Kafka property file '{}' is empty", propertyFileName);
+            }
+        } catch (IOException e) {
+            LOG.warn("Kafka property file '{}' was not found in the classpath", propertyFileName);
+        }
+        return props;
+    }
+}
diff --git a/nbinotifications/src/main/resources/OSGI-INF/blueprint/nobinotifications-blueprint.xml b/nbinotifications/src/main/resources/OSGI-INF/blueprint/nobinotifications-blueprint.xml
new file mode 100644 (file)
index 0000000..9b3a3bd
--- /dev/null
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- vi: set et smarttab sw=4 tabstop=4: -->
+<!-- Copyright © 2020 Orange and others. All rights reserved. This program and the accompanying materials
+    are made available under the terms of the Eclipse Public License v1.0 which accompanies this distribution,
+    and is available at http://www.eclipse.org/legal/epl-v10.html -->
+<blueprint xmlns="http://www.osgi.org/xmlns/blueprint/v1.0.0" xmlns:odl="http://opendaylight.org/xmlns/blueprint/v1.0.0"
+xmlns:cm="http://aries.apache.org/blueprint/xmlns/blueprint-cm/v1.1.0"
+    odl:use-default-for-reference-types="true">
+    <cm:property-placeholder persistent-id="org.opendaylight.transportpce.nbinotifications" update-strategy="reload">
+        <cm:default-properties>
+            <cm:property name="suscriber.server" value="" />
+            <cm:property name="publisher.server" value="" />
+        </cm:default-properties>
+    </cm:property-placeholder>
+    <reference id="rpcService" interface="org.opendaylight.mdsal.binding.api.RpcProviderService"/>
+    <reference id="notificationService" interface="org.opendaylight.mdsal.binding.api.NotificationService"/>
+    <reference id="bindingDOMCodecServices" interface="org.opendaylight.mdsal.binding.dom.codec.spi.BindingDOMCodecServices" />
+    <bean id="provider"
+        class="org.opendaylight.transportpce.nbinotifications.impl.NbiNotificationsProvider"
+        init-method="init" destroy-method="close">
+        <argument>
+            <list value-type="java.lang.String">
+                <value>PceListener</value>
+                <value>ServiceHandlerOperations</value>
+                <value>ServiceHandler</value>
+                <value>RendererListener</value>
+            </list>
+        </argument>
+        <argument value="${suscriber.server}"/>
+        <argument value="${publisher.server}"/>
+        <argument ref="rpcService" />
+        <argument ref="notificationService" />
+        <argument ref="bindingDOMCodecServices" />
+    </bean>
+</blueprint>
diff --git a/nbinotifications/src/main/resources/publisher.properties b/nbinotifications/src/main/resources/publisher.properties
new file mode 100644 (file)
index 0000000..ecbc156
--- /dev/null
@@ -0,0 +1,8 @@
+#Kafka Producer/AdminClient properties
+bootstrap.servers=localhost:9092
+acks=all
+retries=3
+max.in.flight.requests.per.connection=1
+batch.size=16384
+linger.ms=1
+buffer.memory=33554432
diff --git a/nbinotifications/src/main/resources/subscriber.properties b/nbinotifications/src/main/resources/subscriber.properties
new file mode 100644 (file)
index 0000000..0c3e96e
--- /dev/null
@@ -0,0 +1,5 @@
+#Kafka Consumer properties
+bootstrap.servers=localhost:9092
+enable.auto.commit=true
+auto.commit.interval.ms=1000
+auto.offset.reset=earliest
diff --git a/nbinotifications/src/test/java/org/opendaylight/transportpce/nbinotifications/consumer/SubscriberTest.java b/nbinotifications/src/test/java/org/opendaylight/transportpce/nbinotifications/consumer/SubscriberTest.java
new file mode 100644 (file)
index 0000000..de58a49
--- /dev/null
@@ -0,0 +1,57 @@
+/*
+ * Copyright © 2020 Orange, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.transportpce.nbinotifications.consumer;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import org.apache.kafka.clients.consumer.ConsumerRecord;
+import org.apache.kafka.clients.consumer.MockConsumer;
+import org.apache.kafka.clients.consumer.OffsetResetStrategy;
+import org.apache.kafka.common.TopicPartition;
+import org.junit.Before;
+import org.junit.Test;
+import org.opendaylight.transportpce.nbinotifications.utils.NotificationServiceDataUtils;
+import org.opendaylight.transportpce.test.AbstractTest;
+import org.opendaylight.yang.gen.v1.nbi.notifications.rev201130.get.notifications.service.output.NotificationService;
+
+public class SubscriberTest extends AbstractTest {
+    private static final String TOPIC = "topic";
+    private static final int PARTITION = 0;
+    private MockConsumer<String, NotificationService> mockConsumer;
+    private Subscriber subscriber;
+
+    @Before
+    public void setUp() {
+        mockConsumer = new MockConsumer<>(OffsetResetStrategy.EARLIEST);
+        subscriber = new Subscriber(mockConsumer);
+    }
+
+    @Test
+    public void subscribeServiceShouldBeSuccessful() {
+        // from https://www.baeldung.com/kafka-mockconsumer
+        ConsumerRecord<String, NotificationService> record = new ConsumerRecord<String, NotificationService>(
+                TOPIC, PARTITION, 0L, "key", NotificationServiceDataUtils.buildReceivedEvent());
+        mockConsumer.schedulePollTask(() -> {
+            mockConsumer.rebalance(Collections.singletonList(new TopicPartition(TOPIC, PARTITION)));
+            mockConsumer.addRecord(record);
+        });
+
+        Map<TopicPartition, Long> startOffsets = new HashMap<>();
+        TopicPartition tp = new TopicPartition(TOPIC, PARTITION);
+        startOffsets.put(tp, 0L);
+        mockConsumer.updateBeginningOffsets(startOffsets);
+        List<NotificationService> result = subscriber.subscribeService(TOPIC);
+        assertEquals("There should be 1 record", 1, result.size());
+        assertTrue("Consumer should be closed", mockConsumer.closed());
+    }
+}
diff --git a/nbinotifications/src/test/java/org/opendaylight/transportpce/nbinotifications/impl/NbiNotificationsImplTest.java b/nbinotifications/src/test/java/org/opendaylight/transportpce/nbinotifications/impl/NbiNotificationsImplTest.java
new file mode 100644 (file)
index 0000000..da82550
--- /dev/null
@@ -0,0 +1,50 @@
+/*
+ * Copyright © 2020 Orange, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.transportpce.nbinotifications.impl;
+
+import static org.junit.Assert.assertNull;
+
+import com.google.common.util.concurrent.ListenableFuture;
+import java.util.concurrent.ExecutionException;
+import org.junit.Before;
+import org.junit.Test;
+import org.opendaylight.transportpce.common.converter.JsonStringConverter;
+import org.opendaylight.transportpce.test.AbstractTest;
+import org.opendaylight.yang.gen.v1.http.org.openroadm.common.service.types.rev190531.ConnectionType;
+import org.opendaylight.yang.gen.v1.nbi.notifications.rev201130.GetNotificationsServiceInputBuilder;
+import org.opendaylight.yang.gen.v1.nbi.notifications.rev201130.GetNotificationsServiceOutput;
+import org.opendaylight.yangtools.yang.common.RpcResult;
+
+public class NbiNotificationsImplTest extends AbstractTest {
+    private NbiNotificationsImpl nbiNotificationsImpl;
+
+    @Before
+    public void setUp() {
+        JsonStringConverter<org.opendaylight.yang.gen.v1
+            .nbi.notifications.rev201130.NotificationService> converter = new JsonStringConverter<>(
+                getDataStoreContextUtil().getBindingDOMCodecServices());
+        nbiNotificationsImpl = new NbiNotificationsImpl(converter, "localhost:8080");
+    }
+
+    public void getNotificationsServiceEmptyDataTest() throws InterruptedException, ExecutionException {
+        ListenableFuture<RpcResult<GetNotificationsServiceOutput>> result =
+                nbiNotificationsImpl.getNotificationsService(new GetNotificationsServiceInputBuilder().build());
+        assertNull("Should be null", result.get().getResult().getNotificationService());
+    }
+
+    @Test
+    public void getNotificationsServiceTest() throws InterruptedException, ExecutionException {
+        GetNotificationsServiceInputBuilder builder = new GetNotificationsServiceInputBuilder();
+        builder.setGroupId("groupId");
+        builder.setIdConsumer("consumerId");
+        builder.setConnectionType(ConnectionType.Service);
+        ListenableFuture<RpcResult<GetNotificationsServiceOutput>> result =
+                nbiNotificationsImpl.getNotificationsService(builder.build());
+        assertNull("Should be null", result.get().getResult().getNotificationService());
+    }
+}
diff --git a/nbinotifications/src/test/java/org/opendaylight/transportpce/nbinotifications/impl/NbiNotificationsProviderTest.java b/nbinotifications/src/test/java/org/opendaylight/transportpce/nbinotifications/impl/NbiNotificationsProviderTest.java
new file mode 100644 (file)
index 0000000..178fc42
--- /dev/null
@@ -0,0 +1,50 @@
+/*
+ * Copyright © 2020 Orange, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.transportpce.nbinotifications.impl;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+
+import java.util.Arrays;
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.opendaylight.mdsal.binding.api.NotificationService;
+import org.opendaylight.mdsal.binding.api.RpcProviderService;
+import org.opendaylight.transportpce.nbinotifications.listener.NbiNotificationsListenerImpl;
+import org.opendaylight.transportpce.test.AbstractTest;
+
+public class NbiNotificationsProviderTest  extends AbstractTest {
+
+    @Mock
+    RpcProviderService rpcProviderRegistry;
+
+    @Mock
+    private NotificationService notificationService;
+
+    @Before
+    public void init() {
+        MockitoAnnotations.openMocks(this);
+
+    }
+
+    @Test
+    public void initTest() {
+        NbiNotificationsProvider provider = new NbiNotificationsProvider(
+                Arrays.asList("topic1", "topic2"), "localhost:8080", "localhost:8080",
+                rpcProviderRegistry, notificationService,
+                getDataStoreContextUtil().getBindingDOMCodecServices());
+        provider.init();
+        verify(rpcProviderRegistry, times(1))
+                .registerRpcImplementation(any(), any(NbiNotificationsImpl.class));
+        verify(notificationService, times(1))
+                .registerNotificationListener(any(NbiNotificationsListenerImpl.class));
+    }
+}
diff --git a/nbinotifications/src/test/java/org/opendaylight/transportpce/nbinotifications/listener/NbiNotificationsListenerImplTest.java b/nbinotifications/src/test/java/org/opendaylight/transportpce/nbinotifications/listener/NbiNotificationsListenerImplTest.java
new file mode 100644 (file)
index 0000000..cb8faf2
--- /dev/null
@@ -0,0 +1,54 @@
+/*
+ * Copyright © 2021 Orange, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.transportpce.nbinotifications.listener;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+
+import java.util.Map;
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.opendaylight.transportpce.nbinotifications.producer.Publisher;
+import org.opendaylight.transportpce.test.AbstractTest;
+import org.opendaylight.yang.gen.v1.http.org.openroadm.common.service.types.rev190531.ConnectionType;
+import org.opendaylight.yang.gen.v1.http.org.openroadm.common.state.types.rev181130.State;
+import org.opendaylight.yang.gen.v1.nbi.notifications.rev201130.PublishNotificationService;
+import org.opendaylight.yang.gen.v1.nbi.notifications.rev201130.PublishNotificationServiceBuilder;
+
+public class NbiNotificationsListenerImplTest extends AbstractTest {
+    @Mock
+    private Publisher publisher;
+
+    @Before
+    public void setUp() {
+        MockitoAnnotations.openMocks(this);
+    }
+
+    @Test
+    public void onPublishNotificationServiceTest() {
+        NbiNotificationsListenerImpl listener = new NbiNotificationsListenerImpl(Map.of("test", publisher));
+        PublishNotificationService notification = new PublishNotificationServiceBuilder().setTopic("test")
+                .setCommonId("commonId").setConnectionType(ConnectionType.Service).setMessage("Service deleted")
+                .setOperationalState(State.OutOfService).setServiceName("service name").build();
+        listener.onPublishNotificationService(notification);
+        verify(publisher, times(1)).sendEvent(any());
+    }
+
+    @Test
+    public void onPublishNotificationServiceWrongTopicTest() {
+        NbiNotificationsListenerImpl listener = new NbiNotificationsListenerImpl(Map.of("test", publisher));
+        PublishNotificationService notification = new PublishNotificationServiceBuilder().setTopic("wrongtopic")
+                .setCommonId("commonId").setConnectionType(ConnectionType.Service).setMessage("Service deleted")
+                .setOperationalState(State.OutOfService).setServiceName("service name").build();
+        listener.onPublishNotificationService(notification);
+        verify(publisher, times(0)).sendEvent(any());
+    }
+}
diff --git a/nbinotifications/src/test/java/org/opendaylight/transportpce/nbinotifications/producer/PublisherTest.java b/nbinotifications/src/test/java/org/opendaylight/transportpce/nbinotifications/producer/PublisherTest.java
new file mode 100644 (file)
index 0000000..b3a5b2e
--- /dev/null
@@ -0,0 +1,55 @@
+/*
+ * Copyright © 2020 Orange, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.transportpce.nbinotifications.producer;
+
+import static org.junit.Assert.assertEquals;
+
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Paths;
+import java.util.Map;
+import org.apache.kafka.clients.producer.MockProducer;
+import org.apache.kafka.common.serialization.StringSerializer;
+import org.junit.Before;
+import org.junit.Test;
+import org.opendaylight.transportpce.common.converter.JsonStringConverter;
+import org.opendaylight.transportpce.nbinotifications.serialization.ConfigConstants;
+import org.opendaylight.transportpce.nbinotifications.serialization.NotificationServiceSerializer;
+import org.opendaylight.transportpce.test.AbstractTest;
+import org.opendaylight.yang.gen.v1.nbi.notifications.rev201130.NotificationService;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.codec.gson.JSONCodecFactorySupplier;
+
+public class PublisherTest extends AbstractTest {
+    private JsonStringConverter<NotificationService> converter;
+    private Publisher publisher;
+    private MockProducer<String, NotificationService> mockProducer;
+
+    @Before
+    public void setUp() {
+        NotificationServiceSerializer serializer = new NotificationServiceSerializer();
+        Map<String, Object> properties = Map.of(ConfigConstants.CONVERTER , serializer);
+        serializer.configure(properties, false);
+        mockProducer =  new MockProducer<>(true, new StringSerializer(), serializer);
+        converter = new JsonStringConverter<NotificationService>(
+                getDataStoreContextUtil().getBindingDOMCodecServices());
+        publisher = new Publisher("test",mockProducer);
+    }
+
+    @Test
+    public void sendEventShouldBeSuccessful() throws IOException {
+        String json = Files.readString(Paths.get("src/test/resources/event.json"));
+        NotificationService notificationService = converter
+                .createDataObjectFromJsonString(YangInstanceIdentifier.of(NotificationService.QNAME),
+                        json, JSONCodecFactorySupplier.RFC7951);
+        publisher.sendEvent(notificationService);
+        assertEquals("We should have one message", 1, mockProducer.history().size());
+        assertEquals("Key should be test", "test",mockProducer.history().get(0).key());
+    }
+
+}
diff --git a/nbinotifications/src/test/java/org/opendaylight/transportpce/nbinotifications/serialization/NotificationServiceDeserializerTest.java b/nbinotifications/src/test/java/org/opendaylight/transportpce/nbinotifications/serialization/NotificationServiceDeserializerTest.java
new file mode 100644 (file)
index 0000000..928c247
--- /dev/null
@@ -0,0 +1,35 @@
+/*
+ * Copyright © 2021 Orange, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.transportpce.nbinotifications.serialization;
+
+import static org.junit.Assert.assertEquals;
+
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Paths;
+import java.util.Map;
+import org.junit.Test;
+import org.opendaylight.transportpce.common.converter.JsonStringConverter;
+import org.opendaylight.transportpce.test.AbstractTest;
+import org.opendaylight.yang.gen.v1.nbi.notifications.rev201130.get.notifications.service.output.NotificationService;
+
+public class NotificationServiceDeserializerTest extends AbstractTest {
+
+    @Test
+    public void deserializeTest() throws IOException {
+        JsonStringConverter<org.opendaylight.yang.gen.v1.nbi.notifications.rev201130.NotificationService> converter =
+                new JsonStringConverter<>(getDataStoreContextUtil().getBindingDOMCodecServices());
+        NotificationServiceDeserializer deserializer = new NotificationServiceDeserializer();
+        Map<String, Object> configs = Map.of(ConfigConstants.CONVERTER, converter);
+        deserializer.configure(configs, false);
+        NotificationService readEvent = deserializer.deserialize("Test",
+                Files.readAllBytes(Paths.get("src/test/resources/event.json")));
+        deserializer.close();
+        assertEquals("Service name should be service1", "service1", readEvent.getServiceName());
+    }
+}
diff --git a/nbinotifications/src/test/java/org/opendaylight/transportpce/nbinotifications/serialization/NotificationServiceSerializerTest.java b/nbinotifications/src/test/java/org/opendaylight/transportpce/nbinotifications/serialization/NotificationServiceSerializerTest.java
new file mode 100644 (file)
index 0000000..3fe658b
--- /dev/null
@@ -0,0 +1,44 @@
+/*
+ * Copyright © 2021 Orange, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.transportpce.nbinotifications.serialization;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+
+import java.io.IOException;
+import java.nio.charset.StandardCharsets;
+import java.nio.file.Files;
+import java.nio.file.Paths;
+import java.util.Map;
+import org.junit.Test;
+import org.opendaylight.transportpce.common.converter.JsonStringConverter;
+import org.opendaylight.transportpce.test.AbstractTest;
+import org.opendaylight.yang.gen.v1.nbi.notifications.rev201130.NotificationService;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.codec.gson.JSONCodecFactorySupplier;
+
+public class NotificationServiceSerializerTest extends AbstractTest {
+
+    @Test
+    public void serializeTest() throws IOException {
+        JsonStringConverter<NotificationService> converter =
+                new JsonStringConverter<>(getDataStoreContextUtil().getBindingDOMCodecServices());
+        String json = Files.readString(Paths.get("src/test/resources/event.json"));
+        NotificationService notificationService = converter
+                .createDataObjectFromJsonString(YangInstanceIdentifier.of(NotificationService.QNAME),
+                        json, JSONCodecFactorySupplier.RFC7951);
+        NotificationServiceSerializer serializer = new NotificationServiceSerializer();
+        Map<String, Object> configs = Map.of(ConfigConstants.CONVERTER, converter);
+        serializer.configure(configs, false);
+        byte[] data = serializer.serialize("test", notificationService);
+        serializer.close();
+        assertNotNull("Serialized data should not be null", data);
+        String expectedJson = Files.readString(Paths.get("src/test/resources/expected_event.json"));
+        assertEquals("The event should be equals", expectedJson, new String(data, StandardCharsets.UTF_8));
+    }
+}
diff --git a/nbinotifications/src/test/java/org/opendaylight/transportpce/nbinotifications/utils/NotificationServiceDataUtils.java b/nbinotifications/src/test/java/org/opendaylight/transportpce/nbinotifications/utils/NotificationServiceDataUtils.java
new file mode 100644 (file)
index 0000000..44b6958
--- /dev/null
@@ -0,0 +1,98 @@
+/*
+ * Copyright © 2020 Orange, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.transportpce.nbinotifications.utils;
+
+import org.opendaylight.yang.gen.v1.http.org.openroadm.common.node.types.rev181130.NodeIdType;
+import org.opendaylight.yang.gen.v1.http.org.openroadm.common.service.types.rev190531.ConnectionType;
+import org.opendaylight.yang.gen.v1.http.org.openroadm.common.service.types.rev190531.service.endpoint.RxDirection;
+import org.opendaylight.yang.gen.v1.http.org.openroadm.common.service.types.rev190531.service.endpoint.TxDirection;
+import org.opendaylight.yang.gen.v1.http.org.openroadm.common.service.types.rev190531.service.lgx.LgxBuilder;
+import org.opendaylight.yang.gen.v1.http.org.openroadm.common.service.types.rev190531.service.port.PortBuilder;
+import org.opendaylight.yang.gen.v1.http.org.openroadm.common.state.types.rev181130.State;
+import org.opendaylight.yang.gen.v1.http.org.openroadm.service.format.rev190531.ServiceFormat;
+import org.opendaylight.yang.gen.v1.nbi.notifications.rev201130.NotificationService;
+import org.opendaylight.yang.gen.v1.nbi.notifications.rev201130.NotificationServiceBuilder;
+import org.opendaylight.yang.gen.v1.nbi.notifications.rev201130.notification.service.ServiceAEndBuilder;
+import org.opendaylight.yang.gen.v1.nbi.notifications.rev201130.notification.service.ServiceZEndBuilder;
+import org.opendaylight.yangtools.yang.common.Uint32;
+
+public final class NotificationServiceDataUtils {
+
+    private NotificationServiceDataUtils() {
+    }
+
+    public static NotificationService buildSendEventInput() {
+        NotificationServiceBuilder notificationServiceBuilder = new NotificationServiceBuilder()
+                .setMessage("message")
+                .setServiceName("service1")
+                .setOperationalState(State.InService)
+                .setResponseFailed("")
+                .setCommonId("commond-id")
+                .setConnectionType(ConnectionType.Service)
+                .setServiceZEnd(getServiceZEndBuild().build())
+                .setServiceAEnd(getServiceAEndBuild().build());
+
+        return notificationServiceBuilder.build();
+    }
+
+    public static org.opendaylight.yang.gen.v1
+        .nbi.notifications.rev201130.get.notifications.service.output.NotificationService buildReceivedEvent() {
+        org.opendaylight.yang.gen.v1
+            .nbi.notifications.rev201130.get.notifications.service.output.NotificationServiceBuilder
+            notificationServiceBuilder = new org.opendaylight.yang.gen.v1
+            .nbi.notifications.rev201130.get.notifications.service.output.NotificationServiceBuilder()
+                .setMessage("message")
+                .setServiceName("service1")
+                .setOperationalState(State.InService)
+                .setResponseFailed("")
+                .setCommonId("commond-id")
+                .setConnectionType(ConnectionType.Service)
+                .setServiceZEnd(getServiceZEndBuild().build())
+                .setServiceAEnd(getServiceAEndBuild().build());
+
+        return notificationServiceBuilder.build();
+    }
+
+    public static ServiceAEndBuilder getServiceAEndBuild() {
+        return new ServiceAEndBuilder()
+                .setClli("clli").setServiceFormat(ServiceFormat.OC).setServiceRate(Uint32.valueOf(1))
+                .setNodeId(new NodeIdType("XPONDER-1-2"))
+                .setTxDirection(getTxDirection())
+                .setRxDirection(getRxDirection());
+    }
+
+    public static ServiceZEndBuilder getServiceZEndBuild() {
+        return new ServiceZEndBuilder()
+                .setClli("clli").setServiceFormat(ServiceFormat.OC).setServiceRate(Uint32.valueOf(1))
+                .setNodeId(new NodeIdType("XPONDER-1-2"))
+                .setTxDirection(getTxDirection())
+                .setRxDirection(getRxDirection());
+    }
+
+    private static TxDirection getTxDirection() {
+        return new org.opendaylight.yang.gen.v1.http.org.openroadm.common.service.types.rev190531.service
+                .endpoint.TxDirectionBuilder().setPort(new PortBuilder().setPortDeviceName("device name")
+                .setPortName("port name").setPortRack("port rack").setPortShelf("port shelf")
+                .setPortSlot("port slot").setPortSubSlot("port subslot").setPortType("port type").build())
+                .setLgx(new LgxBuilder().setLgxDeviceName("lgx device name").setLgxPortName("lgx port name")
+                        .setLgxPortRack("lgx port rack").setLgxPortShelf("lgx port shelf").build())
+                .build();
+    }
+
+    private static RxDirection getRxDirection() {
+        return new org.opendaylight.yang.gen.v1.http.org.openroadm.common.service.types.rev190531.service
+                .endpoint.RxDirectionBuilder()
+                .setPort(new PortBuilder().setPortDeviceName("device name").setPortName("port name")
+                        .setPortRack("port rack").setPortShelf("port shelf").setPortSlot("port slot")
+                        .setPortSubSlot("port subslot").setPortType("port type").build())
+                .setLgx(new LgxBuilder().setLgxDeviceName("lgx device name")
+                        .setLgxPortName("lgx port name").setLgxPortRack("lgx port rack")
+                        .setLgxPortShelf("lgx port shelf").build())
+                .build();
+    }
+}
diff --git a/nbinotifications/src/test/resources/event.json b/nbinotifications/src/test/resources/event.json
new file mode 100644 (file)
index 0000000..63c7bec
--- /dev/null
@@ -0,0 +1,90 @@
+{
+    "notification-service": {
+        "service-name": "service1",
+        "service-a-end": {
+            "service-format": "OC",
+            "node-id": "XPONDER-1-2",
+            "service-rate": 1,
+            "clli": "clli",
+            "tx-direction": {
+                "port": {
+                    "port-slot": "port slot",
+                    "port-device-name": "device name",
+                    "port-rack": "port rack",
+                    "port-shelf": "port shelf",
+                    "port-type": "port type",
+                    "port-sub-slot": "port subslot",
+                    "port-name": "port name"
+                },
+                "lgx": {
+                    "lgx-port-name": "lgx port name",
+                    "lgx-port-shelf": "lgx port shelf",
+                    "lgx-port-rack": "lgx port rack",
+                    "lgx-device-name": "lgx device name"
+                }
+            },
+            "rx-direction": {
+                "port": {
+                    "port-slot": "port slot",
+                    "port-device-name": "device name",
+                    "port-rack": "port rack",
+                    "port-shelf": "port shelf",
+                    "port-type": "port type",
+                    "port-sub-slot": "port subslot",
+                    "port-name": "port name"
+                },
+                "lgx": {
+                    "lgx-port-name": "lgx port name",
+                    "lgx-port-shelf": "lgx port shelf",
+                    "lgx-port-rack": "lgx port rack",
+                    "lgx-device-name": "lgx device name"
+                }
+            }
+        },
+        "common-id": "commond-id",
+        "operational-state": "inService",
+        "connection-type": "service",
+        "service-z-end": {
+            "service-format": "OC",
+            "node-id": "XPONDER-1-2",
+            "service-rate": 1,
+            "clli": "clli",
+            "tx-direction": {
+                "port": {
+                    "port-slot": "port slot",
+                    "port-device-name": "device name",
+                    "port-rack": "port rack",
+                    "port-shelf": "port shelf",
+                    "port-type": "port type",
+                    "port-sub-slot": "port subslot",
+                    "port-name": "port name"
+                },
+                "lgx": {
+                    "lgx-port-name": "lgx port name",
+                    "lgx-port-shelf": "lgx port shelf",
+                    "lgx-port-rack": "lgx port rack",
+                    "lgx-device-name": "lgx device name"
+                }
+            },
+            "rx-direction": {
+                "port": {
+                    "port-slot": "port slot",
+                    "port-device-name": "device name",
+                    "port-rack": "port rack",
+                    "port-shelf": "port shelf",
+                    "port-type": "port type",
+                    "port-sub-slot": "port subslot",
+                    "port-name": "port name"
+                },
+                "lgx": {
+                    "lgx-port-name": "lgx port name",
+                    "lgx-port-shelf": "lgx port shelf",
+                    "lgx-port-rack": "lgx port rack",
+                    "lgx-device-name": "lgx device name"
+                }
+            }
+        },
+        "message": "message",
+        "response-failed": ""
+    }
+}
diff --git a/nbinotifications/src/test/resources/expected_event.json b/nbinotifications/src/test/resources/expected_event.json
new file mode 100644 (file)
index 0000000..2b8924d
--- /dev/null
@@ -0,0 +1 @@
+{"notification-service":{"service-name":"service1","service-a-end":{"service-format":"OC","node-id":"XPONDER-1-2","service-rate":1,"clli":"clli","tx-direction":{"port":{"port-slot":"port slot","port-device-name":"device name","port-rack":"port rack","port-shelf":"port shelf","port-type":"port type","port-sub-slot":"port subslot","port-name":"port name"},"lgx":{"lgx-port-name":"lgx port name","lgx-port-shelf":"lgx port shelf","lgx-port-rack":"lgx port rack","lgx-device-name":"lgx device name"}},"rx-direction":{"port":{"port-slot":"port slot","port-device-name":"device name","port-rack":"port rack","port-shelf":"port shelf","port-type":"port type","port-sub-slot":"port subslot","port-name":"port name"},"lgx":{"lgx-port-name":"lgx port name","lgx-port-shelf":"lgx port shelf","lgx-port-rack":"lgx port rack","lgx-device-name":"lgx device name"}}},"common-id":"commond-id","operational-state":"inService","connection-type":"service","service-z-end":{"service-format":"OC","node-id":"XPONDER-1-2","service-rate":1,"clli":"clli","tx-direction":{"port":{"port-slot":"port slot","port-device-name":"device name","port-rack":"port rack","port-shelf":"port shelf","port-type":"port type","port-sub-slot":"port subslot","port-name":"port name"},"lgx":{"lgx-port-name":"lgx port name","lgx-port-shelf":"lgx port shelf","lgx-port-rack":"lgx port rack","lgx-device-name":"lgx device name"}},"rx-direction":{"port":{"port-slot":"port slot","port-device-name":"device name","port-rack":"port rack","port-shelf":"port shelf","port-type":"port type","port-sub-slot":"port subslot","port-name":"port name"},"lgx":{"lgx-port-name":"lgx port name","lgx-port-shelf":"lgx port shelf","lgx-port-rack":"lgx port rack","lgx-device-name":"lgx device name"}}},"message":"message","response-failed":""}}
\ No newline at end of file
diff --git a/nbinotifications/src/test/resources/publisher.properties b/nbinotifications/src/test/resources/publisher.properties
new file mode 100644 (file)
index 0000000..ecbc156
--- /dev/null
@@ -0,0 +1,8 @@
+#Kafka Producer/AdminClient properties
+bootstrap.servers=localhost:9092
+acks=all
+retries=3
+max.in.flight.requests.per.connection=1
+batch.size=16384
+linger.ms=1
+buffer.memory=33554432
diff --git a/nbinotifications/src/test/resources/subscriber.properties b/nbinotifications/src/test/resources/subscriber.properties
new file mode 100644 (file)
index 0000000..0c3e96e
--- /dev/null
@@ -0,0 +1,5 @@
+#Kafka Consumer properties
+bootstrap.servers=localhost:9092
+enable.auto.commit=true
+auto.commit.interval.ms=1000
+auto.offset.reset=earliest
diff --git a/pom.xml b/pom.xml
index 7d26a84342d4e27c0efadb078e1794bb9afe1849..b3395f990a2a5cd0fa3e23eb2fee0cb2ca3d6b20 100644 (file)
--- a/pom.xml
+++ b/pom.xml
@@ -42,6 +42,8 @@ and is available at http://www.eclipse.org/legal/epl-v10.html INTERNAL
         <module>pce</module>
         <module>servicehandler</module>
         <module>tapi</module>
+        <module>nbinotifications</module>
+        <module>dmaap-client</module>
         <module>features</module>
         <module>karaf</module>
     </modules>
index ce05db6003cd3ef1f6d52b5d4be9dedf77d23e75..15c90048cfbed7a22a0e01959765baeb63c70a4d 100644 (file)
@@ -80,6 +80,10 @@ import org.opendaylight.yang.gen.v1.http.org.openroadm.service.rev190531.TempSer
 import org.opendaylight.yang.gen.v1.http.org.openroadm.service.rev190531.service.delete.input.ServiceDeleteReqInfo.TailRetention;
 import org.opendaylight.yang.gen.v1.http.org.openroadm.service.rev190531.service.delete.input.ServiceDeleteReqInfoBuilder;
 import org.opendaylight.yang.gen.v1.http.org.openroadm.service.rev190531.service.list.Services;
+import org.opendaylight.yang.gen.v1.nbi.notifications.rev201130.PublishNotificationService;
+import org.opendaylight.yang.gen.v1.nbi.notifications.rev201130.PublishNotificationServiceBuilder;
+import org.opendaylight.yang.gen.v1.nbi.notifications.rev201130.notification.service.ServiceAEndBuilder;
+import org.opendaylight.yang.gen.v1.nbi.notifications.rev201130.notification.service.ServiceZEndBuilder;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.DateAndTime;
 import org.opendaylight.yangtools.yang.common.RpcResult;
 import org.slf4j.Logger;
@@ -106,13 +110,16 @@ public class ServicehandlerImpl implements OrgOpenroadmServiceService {
     private PceListenerImpl pceListenerImpl;
     private RendererListenerImpl rendererListenerImpl;
     private NetworkModelListenerImpl networkModelListenerImpl;
+    private NotificationPublishService notificationPublishService;
+    private final String topic;
 
     //TODO: remove private request fields as they are in global scope
 
     public ServicehandlerImpl(DataBroker databroker, PathComputationService pathComputationService,
             RendererServiceOperations rendererServiceOperations, NotificationPublishService notificationPublishService,
             PceListenerImpl pceListenerImpl, RendererListenerImpl rendererListenerImpl,
-            NetworkModelListenerImpl networkModelListenerImpl, ServiceDataStoreOperations serviceDataStoreOperations) {
+            NetworkModelListenerImpl networkModelListenerImpl, ServiceDataStoreOperations serviceDataStoreOperations,
+            String topic) {
         this.db = databroker;
         this.serviceDataStoreOperations = serviceDataStoreOperations;
         this.pceServiceWrapper = new PCEServiceWrapper(pathComputationService, notificationPublishService);
@@ -120,6 +127,8 @@ public class ServicehandlerImpl implements OrgOpenroadmServiceService {
         this.pceListenerImpl = pceListenerImpl;
         this.rendererListenerImpl = rendererListenerImpl;
         this.networkModelListenerImpl = networkModelListenerImpl;
+        this.notificationPublishService =  notificationPublishService;
+        this.topic = topic;
     }
 
 
@@ -169,6 +178,17 @@ public class ServicehandlerImpl implements OrgOpenroadmServiceService {
                     input, ResponseCodes.FINAL_ACK_YES,
                     validationResult.getResultMessage(), ResponseCodes.RESPONSE_FAILED);
         }
+        PublishNotificationService nbiNotification = new PublishNotificationServiceBuilder()
+                .setServiceName(input.getServiceName())
+                .setServiceAEnd(new ServiceAEndBuilder(input.getServiceAEnd()).build())
+                .setServiceZEnd(new ServiceZEndBuilder(input.getServiceZEnd()).build())
+                .setCommonId(input.getCommonId()).setConnectionType(input.getConnectionType())
+                .setResponseFailed("")
+                .setMessage("ServiceCreate request received ...")
+                .setOperationalState(State.OutOfService)
+                .setTopic(topic)
+                .build();
+        sendNbiNotification(nbiNotification);
         this.pceListenerImpl.setInput(new ServiceInput(input));
         this.pceListenerImpl.setServiceReconfigure(false);
         this.pceListenerImpl.setserviceDataStoreOperations(this.serviceDataStoreOperations);
@@ -179,6 +199,12 @@ public class ServicehandlerImpl implements OrgOpenroadmServiceService {
         PathComputationRequestOutput output = this.pceServiceWrapper.performPCE(input, true);
         if (output == null) {
             LOG.warn(SERVICE_CREATE_MSG, LogMessages.ABORT_PCE_FAILED);
+            nbiNotification = new PublishNotificationServiceBuilder(nbiNotification)
+                    .setResponseFailed(LogMessages.ABORT_PCE_FAILED)
+                    .setMessage("ServiceCreate request failed ...")
+                    .setOperationalState(State.Degraded)
+                    .build();
+            sendNbiNotification(nbiNotification);
             return ModelMappingUtils.createCreateServiceReply(input, ResponseCodes.FINAL_ACK_YES,
                     LogMessages.PCE_FAILED, ResponseCodes.RESPONSE_FAILED);
         }
@@ -219,6 +245,17 @@ public class ServicehandlerImpl implements OrgOpenroadmServiceService {
                     LogMessages.serviceNotInDS(serviceName), ResponseCodes.RESPONSE_FAILED);
         }
         service = serviceOpt.get();
+        PublishNotificationService nbiNotification = new PublishNotificationServiceBuilder()
+                .setServiceName(service.getServiceName())
+                .setServiceAEnd(new ServiceAEndBuilder(service.getServiceAEnd()).build())
+                .setServiceZEnd(new ServiceZEndBuilder(service.getServiceZEnd()).build())
+                .setCommonId(service.getCommonId()).setConnectionType(service.getConnectionType())
+                .setMessage("ServiceDelete request received ...")
+                .setOperationalState(State.OutOfService)
+                .setResponseFailed("")
+                .setTopic(topic)
+                .build();
+        sendNbiNotification(nbiNotification);
         LOG.debug("serviceDelete: Service '{}' found in datastore", serviceName);
         this.pceListenerImpl.setInput(new ServiceInput(input));
         this.pceListenerImpl.setServiceReconfigure(false);
@@ -235,6 +272,12 @@ public class ServicehandlerImpl implements OrgOpenroadmServiceService {
 
         if (output == null) {
             LOG.error(SERVICE_DELETE_MSG, LogMessages.RENDERER_DELETE_FAILED);
+            nbiNotification = new PublishNotificationServiceBuilder(nbiNotification)
+                    .setMessage("ServiceCreate request failed ...")
+                    .setOperationalState(State.OutOfService)
+                    .setResponseFailed(LogMessages.ABORT_PCE_FAILED)
+                    .build();
+            sendNbiNotification(nbiNotification);
             return ModelMappingUtils.createDeleteServiceReply(
                     input, ResponseCodes.FINAL_ACK_YES,
                     LogMessages.RENDERER_DELETE_FAILED, ResponseCodes.RESPONSE_FAILED);
@@ -625,4 +668,16 @@ public class ServicehandlerImpl implements OrgOpenroadmServiceService {
         return null;
     }
 
+    /**
+     * Send notification to NBI notification in order to publish message.
+     * @param service PublishNotificationService
+     */
+    private void sendNbiNotification(PublishNotificationService service) {
+        try {
+            notificationPublishService.putNotification(service);
+        } catch (InterruptedException e) {
+            LOG.warn("Cannot send notification to nbi", e);
+            Thread.currentThread().interrupt();
+        }
+    }
 }
index c5da973eb8860c29a77e6730486ff48f1babb269..bd7564419d3a0f416b60c05dbd31b3fff72a7b63 100644 (file)
@@ -47,7 +47,6 @@ public class ServicehandlerProvider {
     private NetworkModelListenerImpl networkModelListenerImpl;
     private ServicehandlerImpl servicehandler;
 
-
     public ServicehandlerProvider(final DataBroker dataBroker, RpcProviderService rpcProviderService,
             NotificationService notificationService, ServiceDataStoreOperations serviceDataStoreOperations,
             PceListenerImpl pceListenerImpl, RendererListenerImpl rendererListenerImpl,
index 43668620bc88b6c8e23e37eeb4d043ba2829ac5f..1ecc6a246e868ef593f5faa0fe5301a7c4cd6e5c 100644 (file)
@@ -23,15 +23,21 @@ import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.pce.rev20
 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.pce.rev200128.service.path.rpc.result.PathDescription;
 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.pce.rev200128.service.path.rpc.result.PathDescriptionBuilder;
 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.renderer.rev201125.ServiceImplementationRequestInput;
+import org.opendaylight.yang.gen.v1.http.org.openroadm.common.state.types.rev181130.State;
 import org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.service.types.rev200128.RpcStatusEx;
 import org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.service.types.rev200128.response.parameters.sp.ResponseParameters;
 import org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.service.types.rev200128.response.parameters.sp.ResponseParametersBuilder;
+import org.opendaylight.yang.gen.v1.nbi.notifications.rev201130.PublishNotificationService;
+import org.opendaylight.yang.gen.v1.nbi.notifications.rev201130.PublishNotificationServiceBuilder;
+import org.opendaylight.yang.gen.v1.nbi.notifications.rev201130.notification.service.ServiceAEndBuilder;
+import org.opendaylight.yang.gen.v1.nbi.notifications.rev201130.notification.service.ServiceZEndBuilder;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 public class PceListenerImpl implements TransportpcePceListener {
 
     private static final Logger LOG = LoggerFactory.getLogger(PceListenerImpl.class);
+    private static final String TOPIC = "PceListener";
 
     private ServicePathRpcResult servicePathRpcResult;
     private RendererServiceOperations rendererServiceOperations;
@@ -41,6 +47,7 @@ public class PceListenerImpl implements TransportpcePceListener {
     private Boolean serviceReconfigure;
     private Boolean tempService;
     private Boolean serviceFeasiblity;
+    private NotificationPublishService notificationPublishService;
 
     public PceListenerImpl(RendererServiceOperations rendererServiceOperations,
             PathComputationService pathComputationService, NotificationPublishService notificationPublishService,
@@ -52,6 +59,7 @@ public class PceListenerImpl implements TransportpcePceListener {
         setInput(null);
         setTempService(false);
         setServiceFeasiblity(false);
+        this.notificationPublishService = notificationPublishService;
     }
 
     @Override
@@ -80,20 +88,11 @@ public class PceListenerImpl implements TransportpcePceListener {
      * @param notification the result notification.
      */
     private void onPathComputationResult(ServicePathRpcResult notification) {
-        LOG.info("PCE '{}' Notification received : {}",servicePathRpcResult.getNotificationType().getName(),
+        LOG.info("PCE '{}' Notification received : {}", servicePathRpcResult.getNotificationType().getName(),
                 notification);
-        if (servicePathRpcResult.getStatus() == RpcStatusEx.Failed) {
-            LOG.error("PCE path computation failed !");
-            return;
-        } else if (servicePathRpcResult.getStatus() == RpcStatusEx.Pending) {
-            LOG.warn("PCE path computation returned a Penging RpcStatusEx code!");
-            return;
-        } else if (servicePathRpcResult.getStatus() != RpcStatusEx.Successful) {
-            LOG.error("PCE path computation returned an unknown RpcStatusEx code!");
+        if (!checkStatus(notification)) {
             return;
         }
-
-        LOG.info("PCE calculation done OK !");
         if (servicePathRpcResult.getPathDescription() == null) {
             LOG.error("'PathDescription' parameter is null ");
             return;
@@ -124,10 +123,9 @@ public class PceListenerImpl implements TransportpcePceListener {
             }
         }
         ResponseParameters responseParameters = new ResponseParametersBuilder()
-                .setPathDescription(new org.opendaylight.yang.gen.v1.http.org
-                        .transportpce.b.c._interface.service.types.rev200128
-                        .response.parameters.sp.response.parameters
-                        .PathDescriptionBuilder(pathDescription).build())
+                .setPathDescription(new org.opendaylight.yang.gen.v1.http
+                        .org.transportpce.b.c._interface.service.types.rev200128
+                        .response.parameters.sp.response.parameters.PathDescriptionBuilder(pathDescription).build())
                 .build();
         PathComputationRequestOutput pceResponse = new PathComputationRequestOutputBuilder()
                 .setResponseParameters(responseParameters).build();
@@ -142,6 +140,57 @@ public class PceListenerImpl implements TransportpcePceListener {
         this.rendererServiceOperations.serviceImplementation(serviceImplementationRequest);
     }
 
+    /**
+     * Check status of notification and send nbi notification.
+     * @param notification ServicePathRpcResult the notification to check.
+     * @return true is status is Successful, false otherwise.
+     */
+    private boolean checkStatus(ServicePathRpcResult notification) {
+        PublishNotificationService nbiNotification = getPublishNotificationService(notification);
+        PublishNotificationServiceBuilder publishNotificationServiceBuilder = new PublishNotificationServiceBuilder(
+                nbiNotification);
+        switch (servicePathRpcResult.getStatus()) {
+            case Failed:
+                LOG.error("PCE path computation failed !");
+                nbiNotification = publishNotificationServiceBuilder.setMessage("ServiceCreate request failed ...")
+                        .setResponseFailed("PCE path computation failed !")
+                        .setOperationalState(State.Degraded).build();
+                sendNbiNotification(nbiNotification);
+                return false;
+            case Pending:
+                LOG.warn("PCE path computation returned a Penging RpcStatusEx code!");
+                return false;
+            case Successful:
+                LOG.info("PCE calculation done OK !");
+                nbiNotification = publishNotificationServiceBuilder.setMessage("PCE calculation done OK !")
+                        .setResponseFailed("").setOperationalState(State.OutOfService).build();
+                sendNbiNotification(nbiNotification);
+                return true;
+            default:
+                LOG.error("PCE path computation returned an unknown RpcStatusEx code {}",
+                        servicePathRpcResult.getStatus());
+                nbiNotification = publishNotificationServiceBuilder.setMessage("ServiceCreate request failed ...")
+                        .setResponseFailed("PCE path computation returned an unknown RpcStatusEx code!")
+                        .setOperationalState(State.Degraded).build();
+                sendNbiNotification(nbiNotification);
+                return false;
+        }
+    }
+
+    private PublishNotificationService getPublishNotificationService(ServicePathRpcResult notification) {
+        PublishNotificationServiceBuilder nbiNotificationBuilder = new PublishNotificationServiceBuilder();
+        if (input != null) {
+            nbiNotificationBuilder.setServiceName(input.getServiceName())
+                    .setServiceAEnd(new ServiceAEndBuilder(input.getServiceAEnd()).build())
+                    .setServiceZEnd(new ServiceZEndBuilder(input.getServiceZEnd()).build())
+                    .setCommonId(input.getCommonId()).setConnectionType(input.getConnectionType());
+        } else {
+            nbiNotificationBuilder.setServiceName(notification.getServiceName());
+        }
+        nbiNotificationBuilder.setTopic(TOPIC);
+        return nbiNotificationBuilder.build();
+    }
+
     /**
      * Process cancel resource result.
      */
@@ -228,4 +277,16 @@ public class PceListenerImpl implements TransportpcePceListener {
         this.serviceFeasiblity = serviceFeasiblity;
     }
 
+    /**
+     * Send notification to NBI notification in order to publish message.
+     * @param service PublishNotificationService
+     */
+    private void sendNbiNotification(PublishNotificationService service) {
+        try {
+            notificationPublishService.putNotification(service);
+        } catch (InterruptedException e) {
+            LOG.warn("Cannot send notification to nbi", e);
+            Thread.currentThread().interrupt();
+        }
+    }
 }
index b79bcb518ca988ab810a36416586a8638fc43f32..38a054917d87801f1532290d3a528d71c88a0885 100644 (file)
@@ -21,6 +21,11 @@ import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.serviceha
 import org.opendaylight.yang.gen.v1.http.org.openroadm.common.service.types.rev190531.ServiceNotificationTypes;
 import org.opendaylight.yang.gen.v1.http.org.openroadm.common.state.types.rev181130.State;
 import org.opendaylight.yang.gen.v1.http.org.openroadm.equipment.states.types.rev181130.AdminStates;
+import org.opendaylight.yang.gen.v1.http.org.openroadm.service.rev190531.service.list.Services;
+import org.opendaylight.yang.gen.v1.nbi.notifications.rev201130.PublishNotificationService;
+import org.opendaylight.yang.gen.v1.nbi.notifications.rev201130.PublishNotificationServiceBuilder;
+import org.opendaylight.yang.gen.v1.nbi.notifications.rev201130.notification.service.ServiceAEndBuilder;
+import org.opendaylight.yang.gen.v1.nbi.notifications.rev201130.notification.service.ServiceZEndBuilder;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -32,6 +37,7 @@ import org.slf4j.LoggerFactory;
  */
 public class RendererListenerImpl implements TransportpceRendererListener {
 
+    private static final String TOPIC = "RendererListener";
     private static final Logger LOG = LoggerFactory.getLogger(RendererListenerImpl.class);
     private RendererRpcResultSp serviceRpcResultSp;
     private ServiceDataStoreOperations serviceDataStoreOperations;
@@ -91,6 +97,21 @@ public class RendererListenerImpl implements TransportpceRendererListener {
                 LOG.error("Renderer service delete returned an unknown RpcStatusEx code!");
                 return;
         }
+        Services service = serviceDataStoreOperations.getService(notification.getServiceName()).get();
+        PublishNotificationService nbiNotification = new PublishNotificationServiceBuilder()
+                .setServiceName(service.getServiceName())
+                .setServiceAEnd(new ServiceAEndBuilder(service.getServiceAEnd()).build())
+                .setServiceZEnd(new ServiceZEndBuilder(service.getServiceZEnd()).build())
+                .setCommonId(service.getCommonId())
+                .setConnectionType(service.getConnectionType())
+                .setResponseFailed("")
+                .setMessage("Service deleted !")
+                .setOperationalState(org.opendaylight.yang.gen.v1.http
+                        .org.openroadm.common.state.types.rev181130.State.Degraded)
+                .setTopic(TOPIC)
+                .build();
+        sendNbiNotification(nbiNotification);
+        LOG.info("Service '{}' deleted !", notification.getServiceName());
         if (this.input == null) {
             LOG.error("ServiceInput parameter is null !");
             return;
@@ -128,6 +149,18 @@ public class RendererListenerImpl implements TransportpceRendererListener {
      */
     private void onSuccededServiceImplementation(RendererRpcResultSp notification) {
         LOG.info("Service implemented !");
+        PublishNotificationService nbiNotification = new PublishNotificationServiceBuilder()
+                .setServiceName(input.getServiceName())
+                .setServiceAEnd(new ServiceAEndBuilder(input.getServiceAEnd()).build())
+                .setServiceZEnd(new ServiceZEndBuilder(input.getServiceZEnd()).build())
+                .setCommonId(input.getCommonId()).setConnectionType(input.getConnectionType())
+                .setResponseFailed("")
+                .setMessage("Service implemented !")
+                .setOperationalState(org.opendaylight.yang.gen.v1.http
+                        .org.openroadm.common.state.types.rev181130.State.InService)
+                .setTopic(TOPIC)
+                .build();
+        sendNbiNotification(nbiNotification);
         if (serviceDataStoreOperations == null) {
             LOG.debug("serviceDataStoreOperations is null");
             return;
@@ -141,9 +174,7 @@ public class RendererListenerImpl implements TransportpceRendererListener {
             }
         } else {
             operationResult = this.serviceDataStoreOperations.modifyService(
-                    serviceRpcResultSp.getServiceName(),
-                    State.InService,
-                    AdminStates.InService);
+                    serviceRpcResultSp.getServiceName(), State.InService, AdminStates.InService);
             if (!operationResult.isSuccess()) {
                 LOG.warn("Service status not updated in datastore !");
             } else {
@@ -236,4 +267,17 @@ public class RendererListenerImpl implements TransportpceRendererListener {
     public void setTempService(Boolean tempService) {
         this.tempService = tempService;
     }
+
+    /**
+     * Send notification to NBI notification in order to publish message.
+     * @param service PublishNotificationService
+     */
+    private void sendNbiNotification(PublishNotificationService service) {
+        try {
+            notificationPublishService.putNotification(service);
+        } catch (InterruptedException e) {
+            LOG.warn("Cannot send notification to nbi", e);
+            Thread.currentThread().interrupt();
+        }
+    }
 }
index d3e7a2727c98dc7aa972c7199aa32770a2844676..5813d31abca9f5ca8fc7e13a2c6f458f123a0a87 100644 (file)
@@ -61,6 +61,7 @@ Author: Martial Coulibaly <martial.coulibaly@gfi.com> on behalf of Orange
         <argument ref="rendererListener" />
         <argument ref="networkModelListener" />
         <argument ref="serviceDatastoreOperation" />
+        <argument value="ServiceHandler" />
     </bean>
 
     <bean id="provider"
index 46289d95be7ea9ba040e5806952aa3edbfe6f6cb..641c107a341cddf1e2e9622f8443f2d2e14c0780 100644 (file)
@@ -103,7 +103,7 @@ public class ServicehandlerImplTest extends AbstractTest  {
         ServicehandlerImpl servicehandlerImpl =
             new ServicehandlerImpl(getNewDataBroker(), pathComputationService, rendererServiceOperations,
                 notificationPublishService, pceListenerImpl, rendererListenerImpl, networkModelListenerImpl,
-                serviceDataStoreOperations);
+                serviceDataStoreOperations, "ServiceHandler");
         ListenableFuture<RpcResult<ServiceCreateOutput>> result =
             servicehandlerImpl.serviceCreate(new ServiceCreateInputBuilder().build());
         result.addListener(new Runnable() {
@@ -129,7 +129,7 @@ public class ServicehandlerImplTest extends AbstractTest  {
         ServicehandlerImpl servicehandlerImpl =
             new ServicehandlerImpl(getNewDataBroker(), pathComputationService, rendererServiceOperations,
                 notificationPublishService, pceListenerImpl, rendererListenerImpl, networkModelListenerImpl,
-                serviceDataStoreOperations);
+                serviceDataStoreOperations, "ServiceHandler");
         ListenableFuture<RpcResult<ServiceCreateOutput>> result =  servicehandlerImpl.serviceCreate(input);
         result.addListener(new Runnable() {
             @Override
@@ -151,7 +151,7 @@ public class ServicehandlerImplTest extends AbstractTest  {
         ServicehandlerImpl servicehandlerImpl =
             new ServicehandlerImpl(getNewDataBroker(), pathComputationService, rendererServiceOperations,
                 notificationPublishService, pceListenerImpl, rendererListenerImpl, networkModelListenerImpl,
-                serviceDataStoreOperations);
+                serviceDataStoreOperations, "ServiceHandler");
         ListenableFuture<RpcResult<ServiceDeleteOutput>> result =
             servicehandlerImpl.serviceDelete(new ServiceDeleteInputBuilder()
                 .setServiceDeleteReqInfo(new ServiceDeleteReqInfoBuilder().setServiceName("").build()).build());
@@ -176,7 +176,7 @@ public class ServicehandlerImplTest extends AbstractTest  {
         ServicehandlerImpl servicehandlerImpl =
             new ServicehandlerImpl(getNewDataBroker(), pathComputationService, rendererServiceOperations,
                 notificationPublishService, pceListenerImpl, rendererListenerImpl, networkModelListenerImpl,
-                serviceDataStoreOperations);
+                serviceDataStoreOperations, "ServiceHandler");
         ListenableFuture<RpcResult<ServiceDeleteOutput>> result = servicehandlerImpl.serviceDelete(input);
         result.addListener(new Runnable() {
             @Override
@@ -200,7 +200,7 @@ public class ServicehandlerImplTest extends AbstractTest  {
         ServicehandlerImpl servicehandlerImpl =
             new ServicehandlerImpl(dataBroker, pathComputationService, rendererServiceOperations,
                 notificationPublishService, pceListenerImpl, rendererListenerImpl, networkModelListenerImpl,
-                serviceDataStoreOperations);
+                serviceDataStoreOperations, "ServiceHandler");
         ServiceCreateInput createInput = ServiceDataUtils.buildServiceCreateInput();
         serviceDataStoreOperations.createService(createInput);
         ServiceDeleteInput input = ServiceDataUtils.buildServiceDeleteInput();
@@ -226,7 +226,7 @@ public class ServicehandlerImplTest extends AbstractTest  {
         ServicehandlerImpl servicehandlerImpl =
                 new ServicehandlerImpl(getNewDataBroker(), pathComputationService, rendererServiceOperations,
                         notificationPublishService, pceListenerImpl, rendererListenerImpl, networkModelListenerImpl,
-                        serviceDataStoreOperations);
+                        serviceDataStoreOperations, "ServiceHandler");
         ListenableFuture<RpcResult<ServiceFeasibilityCheckOutput>> result =
                 servicehandlerImpl.serviceFeasibilityCheck(new ServiceFeasibilityCheckInputBuilder().build());
         result.addListener(new Runnable() {
@@ -252,7 +252,7 @@ public class ServicehandlerImplTest extends AbstractTest  {
         ServicehandlerImpl servicehandlerImpl =
                 new ServicehandlerImpl(getNewDataBroker(), pathComputationService, rendererServiceOperations,
                         notificationPublishService, pceListenerImpl, rendererListenerImpl, networkModelListenerImpl,
-                        serviceDataStoreOperations);
+                        serviceDataStoreOperations, "ServiceHandler");
         ListenableFuture<RpcResult<ServiceFeasibilityCheckOutput>> result =
             servicehandlerImpl.serviceFeasibilityCheck(input);
         result.addListener(new Runnable() {
@@ -275,7 +275,7 @@ public class ServicehandlerImplTest extends AbstractTest  {
         ServicehandlerImpl servicehandlerImpl =
                 new ServicehandlerImpl(getNewDataBroker(), pathComputationService, rendererServiceOperations,
                         notificationPublishService, pceListenerImpl, rendererListenerImpl, networkModelListenerImpl,
-                        serviceDataStoreOperations);
+                        serviceDataStoreOperations, "ServiceHandler");
         ListenableFuture<RpcResult<ServiceReconfigureOutput>> result =
                 servicehandlerImpl.serviceReconfigure(new ServiceReconfigureInputBuilder().setServiceName("").build());
         result.addListener(new Runnable() {
@@ -302,7 +302,7 @@ public class ServicehandlerImplTest extends AbstractTest  {
         ServicehandlerImpl servicehandlerImpl =
                 new ServicehandlerImpl(getNewDataBroker(), pathComputationService, rendererServiceOperations,
                         notificationPublishService, pceListenerImpl, rendererListenerImpl, networkModelListenerImpl,
-                        serviceDataStoreOperations);
+                        serviceDataStoreOperations, "ServiceHandler");
         ListenableFuture<RpcResult<ServiceReconfigureOutput>> result = servicehandlerImpl.serviceReconfigure(input);
 
         result.addListener(new Runnable() {
@@ -332,7 +332,7 @@ public class ServicehandlerImplTest extends AbstractTest  {
         ServicehandlerImpl servicehandlerImpl =
                 new ServicehandlerImpl(dataBroker, pathComputationService, rendererServiceOperations,
                         notificationPublishService, pceListenerImpl, rendererListenerImpl, networkModelListenerImpl,
-                        serviceDataStoreOperations);
+                        serviceDataStoreOperations, "ServiceHandler");
         ServiceCreateInput createInput = ServiceDataUtils.buildServiceCreateInput();
         serviceDataStoreOperations.createService(createInput);
 
@@ -360,7 +360,7 @@ public class ServicehandlerImplTest extends AbstractTest  {
         ServicehandlerImpl servicehandlerImpl =
                 new ServicehandlerImpl(getNewDataBroker(), pathComputationService, rendererServiceOperations,
                         notificationPublishService, pceListenerImpl, rendererListenerImpl, networkModelListenerImpl,
-                        serviceDataStoreOperations);
+                        serviceDataStoreOperations, "ServiceHandler");
         ListenableFuture<RpcResult<ServiceRestorationOutput>> result =
                 servicehandlerImpl.serviceRestoration(new ServiceRestorationInputBuilder().setServiceName("").build());
         result.addListener(new Runnable() {
@@ -387,7 +387,7 @@ public class ServicehandlerImplTest extends AbstractTest  {
         ServicehandlerImpl servicehandlerImpl =
                 new ServicehandlerImpl(getNewDataBroker(), pathComputationService, rendererServiceOperations,
                         notificationPublishService, pceListenerImpl, rendererListenerImpl, networkModelListenerImpl,
-                        serviceDataStoreOperations);
+                        serviceDataStoreOperations, "ServiceHandler");
         ListenableFuture<RpcResult<ServiceRestorationOutput>> result = servicehandlerImpl.serviceRestoration(input);
 
         result.addListener(new Runnable() {
@@ -417,7 +417,7 @@ public class ServicehandlerImplTest extends AbstractTest  {
         ServicehandlerImpl servicehandlerImpl =
                 new ServicehandlerImpl(dataBroker, pathComputationService, rendererServiceOperations,
                         notificationPublishService, pceListenerImpl, rendererListenerImpl, networkModelListenerImpl,
-                        serviceDataStoreOperations);
+                        serviceDataStoreOperations, "ServiceHandler");
         ServiceCreateInput createInput = ServiceDataUtils.buildServiceCreateInput();
         serviceDataStoreOperations.createService(createInput);
 
@@ -445,7 +445,7 @@ public class ServicehandlerImplTest extends AbstractTest  {
         ServicehandlerImpl servicehandlerImpl =
                 new ServicehandlerImpl(getNewDataBroker(), pathComputationService, rendererServiceOperations,
                         notificationPublishService, pceListenerImpl, rendererListenerImpl, networkModelListenerImpl,
-                        serviceDataStoreOperations);
+                        serviceDataStoreOperations, "ServiceHandler");
         ListenableFuture<RpcResult<ServiceRerouteOutput>> result =
                 servicehandlerImpl.serviceReroute(new ServiceRerouteInputBuilder().setServiceName("").build());
         result.addListener(new Runnable() {
@@ -471,7 +471,7 @@ public class ServicehandlerImplTest extends AbstractTest  {
         ServicehandlerImpl servicehandlerImpl =
                 new ServicehandlerImpl(getNewDataBroker(), pathComputationService, rendererServiceOperations,
                         notificationPublishService, pceListenerImpl, rendererListenerImpl, networkModelListenerImpl,
-                        serviceDataStoreOperations);
+                        serviceDataStoreOperations, "ServiceHandler");
         ListenableFuture<RpcResult<ServiceRerouteOutput>> result = servicehandlerImpl.serviceReroute(input);
 
         result.addListener(new Runnable() {
@@ -501,7 +501,7 @@ public class ServicehandlerImplTest extends AbstractTest  {
         ServicehandlerImpl servicehandlerImpl =
                 new ServicehandlerImpl(dataBroker, pathComputationService, rendererServiceOperations,
                         notificationPublishService, pceListenerImpl, rendererListenerImpl, networkModelListenerImpl,
-                        serviceDataStoreOperations);
+                        serviceDataStoreOperations, "ServiceHandler");
         ServiceCreateInput createInput = ServiceDataUtils.buildServiceCreateInput();
         serviceDataStoreOperations.createService(createInput);
 
@@ -529,7 +529,7 @@ public class ServicehandlerImplTest extends AbstractTest  {
         ServicehandlerImpl servicehandlerImpl =
                 new ServicehandlerImpl(getNewDataBroker(), pathComputationService, rendererServiceOperations,
                         notificationPublishService, pceListenerImpl, rendererListenerImpl, networkModelListenerImpl,
-                        serviceDataStoreOperations);
+                        serviceDataStoreOperations, "ServiceHandler");
         ListenableFuture<RpcResult<TempServiceDeleteOutput>> result =
                 servicehandlerImpl.tempServiceDelete(new TempServiceDeleteInputBuilder()
                         .setCommonId("").build());
@@ -557,7 +557,7 @@ public class ServicehandlerImplTest extends AbstractTest  {
         ServicehandlerImpl servicehandlerImpl =
                 new ServicehandlerImpl(getNewDataBroker(), pathComputationService, rendererServiceOperations,
                         notificationPublishService, pceListenerImpl, rendererListenerImpl, networkModelListenerImpl,
-                        serviceDataStoreOperations);
+                        serviceDataStoreOperations, "ServiceHandler");
         ListenableFuture<RpcResult<TempServiceDeleteOutput>> result = servicehandlerImpl.tempServiceDelete(input);
         result.addListener(new Runnable() {
             @Override
@@ -583,7 +583,7 @@ public class ServicehandlerImplTest extends AbstractTest  {
         ServicehandlerImpl servicehandlerImpl =
                 new ServicehandlerImpl(dataBroker, pathComputationService, rendererServiceOperations,
                         notificationPublishService, pceListenerImpl, rendererListenerImpl, networkModelListenerImpl,
-                        serviceDataStoreOperations);
+                        serviceDataStoreOperations, "ServiceHandler");
         TempServiceCreateInput createInput = ServiceDataUtils.buildTempServiceCreateInput();
         serviceDataStoreOperations.createTempService(createInput);
 
@@ -610,7 +610,7 @@ public class ServicehandlerImplTest extends AbstractTest  {
         ServicehandlerImpl servicehandlerImpl =
                 new ServicehandlerImpl(getNewDataBroker(), pathComputationService, rendererServiceOperations,
                         notificationPublishService, pceListenerImpl, rendererListenerImpl, networkModelListenerImpl,
-                        serviceDataStoreOperations);
+                        serviceDataStoreOperations, "ServiceHandler");
         ListenableFuture<RpcResult<TempServiceCreateOutput>> result =
                 servicehandlerImpl.tempServiceCreate(new TempServiceCreateInputBuilder().build());
         result.addListener(new Runnable() {
@@ -638,7 +638,7 @@ public class ServicehandlerImplTest extends AbstractTest  {
         ServicehandlerImpl servicehandlerImpl =
                 new ServicehandlerImpl(getNewDataBroker(), pathComputationService, rendererServiceOperations,
                         notificationPublishService, pceListenerImpl, rendererListenerImpl, networkModelListenerImpl,
-                        serviceDataStoreOperations);
+                        serviceDataStoreOperations, "ServiceHandler");
 
         ListenableFuture<RpcResult<TempServiceCreateOutput>> result =  servicehandlerImpl.tempServiceCreate(input);
         result.addListener(new Runnable() {
diff --git a/tests/nbinotifications/docker-compose.yml b/tests/nbinotifications/docker-compose.yml
new file mode 100644 (file)
index 0000000..b13f6b9
--- /dev/null
@@ -0,0 +1,15 @@
+version: '2'
+services:
+  zookeeper:
+    image: wurstmeister/zookeeper
+    container_name: nbinotifications_zookeeper
+    ports:
+      - "2181:2181"
+  kafka:
+    image: wurstmeister/kafka
+    container_name: nbinotifications_kafka
+    ports:
+      - "9092:9092"
+    environment:
+      KAFKA_ADVERTISED_HOST_NAME: localhost
+      KAFKA_ZOOKEEPER_CONNECT: zookeeper:2181
\ No newline at end of file
diff --git a/tests/transportpce_tests/2.2.1/test_nbinotifications.py b/tests/transportpce_tests/2.2.1/test_nbinotifications.py
new file mode 100644 (file)
index 0000000..b772b36
--- /dev/null
@@ -0,0 +1,354 @@
+#!/usr/bin/env python
+##############################################################################
+# Copyright (c) 2020 Orange, Inc. and others.  All rights reserved.
+#
+# All rights reserved. This program and the accompanying materials
+# are made available under the terms of the Apache License, Version 2.0
+# which accompanies this distribution, and is available at
+# http://www.apache.org/licenses/LICENSE-2.0
+##############################################################################
+
+# pylint: disable=no-member
+# pylint: disable=too-many-public-methods
+
+import os
+import sys
+import unittest
+import time
+import requests
+from common import test_utils
+
+
+class TransportNbiNotificationstesting(unittest.TestCase):
+    processes = None
+    cr_serv_sample_data = {"input": {
+        "sdnc-request-header": {
+            "request-id": "e3028bae-a90f-4ddd-a83f-cf224eba0e58",
+            "rpc-action": "service-create",
+            "request-system-id": "appname",
+            "notification-url": "http://localhost:8585/NotificationServer/notify"
+        },
+        "service-name": "service1",
+        "common-id": "ASATT1234567",
+        "connection-type": "service",
+        "service-a-end": {
+            "service-rate": "100",
+            "node-id": "XPDR-A1",
+            "service-format": "Ethernet",
+            "clli": "SNJSCAMCJP8",
+            "tx-direction": {
+                "port": {
+                    "port-device-name": "ROUTER_SNJSCAMCJP8_000000.00_00",
+                    "port-type": "router",
+                    "port-name": "Gigabit Ethernet_Tx.ge-5/0/0.0",
+                    "port-rack": "000000.00",
+                    "port-shelf": "00"
+                },
+                "lgx": {
+                    "lgx-device-name": "LGX Panel_SNJSCAMCJP8_000000.00_00",
+                    "lgx-port-name": "LGX Back.3",
+                    "lgx-port-rack": "000000.00",
+                    "lgx-port-shelf": "00"
+                }
+            },
+            "rx-direction": {
+                "port": {
+                    "port-device-name": "ROUTER_SNJSCAMCJP8_000000.00_00",
+                    "port-type": "router",
+                    "port-name": "Gigabit Ethernet_Rx.ge-5/0/0.0",
+                    "port-rack": "000000.00",
+                    "port-shelf": "00"
+                },
+                "lgx": {
+                    "lgx-device-name": "LGX Panel_SNJSCAMCJP8_000000.00_00",
+                    "lgx-port-name": "LGX Back.4",
+                    "lgx-port-rack": "000000.00",
+                    "lgx-port-shelf": "00"
+                }
+            },
+            "optic-type": "gray"
+        },
+        "service-z-end": {
+            "service-rate": "100",
+            "node-id": "XPDR-C1",
+            "service-format": "Ethernet",
+            "clli": "SNJSCAMCJT4",
+            "tx-direction": {
+                "port": {
+                    "port-device-name": "ROUTER_SNJSCAMCJT4_000000.00_00",
+                    "port-type": "router",
+                    "port-name": "Gigabit Ethernet_Tx.ge-1/0/0.0",
+                    "port-rack": "000000.00",
+                    "port-shelf": "00"
+                },
+                "lgx": {
+                    "lgx-device-name": "LGX Panel_SNJSCAMCJT4_000000.00_00",
+                    "lgx-port-name": "LGX Back.29",
+                    "lgx-port-rack": "000000.00",
+                    "lgx-port-shelf": "00"
+                }
+            },
+            "rx-direction": {
+                "port": {
+                    "port-device-name": "ROUTER_SNJSCAMCJT4_000000.00_00",
+                    "port-type": "router",
+                    "port-name": "Gigabit Ethernet_Rx.ge-1/0/0.0",
+                    "port-rack": "000000.00",
+                    "port-shelf": "00"
+                },
+                "lgx": {
+                    "lgx-device-name": "LGX Panel_SNJSCAMCJT4_000000.00_00",
+                    "lgx-port-name": "LGX Back.30",
+                    "lgx-port-rack": "000000.00",
+                    "lgx-port-shelf": "00"
+                }
+            },
+            "optic-type": "gray"
+        },
+        "due-date": "2016-11-28T00:00:01Z",
+        "operator-contact": "pw1234"
+    }
+    }
+
+    WAITING = 20  # nominal value is 300
+
+    @classmethod
+    def setUpClass(cls):
+        # TODO: for lighty manage the activation of NBI notification feature
+        cls.processes = test_utils.start_tpce()
+        # NBI notification feature is not installed by default in Karaf
+        if "USE_LIGHTY" not in os.environ or os.environ['USE_LIGHTY'] != 'True':
+            print("installing NBI notification feature...")
+            result = test_utils.install_karaf_feature("odl-transportpce-nbinotifications")
+            if result.returncode != 0:
+                cls.init_failed = True
+            print("Restarting OpenDaylight...")
+            test_utils.shutdown_process(cls.processes[0])
+            cls.processes[0] = test_utils.start_karaf()
+            test_utils.process_list[0] = cls.processes[0]
+            cls.init_failed = not test_utils.wait_until_log_contains(
+                test_utils.KARAF_LOG, test_utils.KARAF_OK_START_MSG, time_to_wait=60)
+        if cls.init_failed:
+            print("NBI notification installation feature failed...")
+            test_utils.shutdown_process(cls.processes[0])
+            sys.exit(2)
+        cls.processes = test_utils.start_sims(['xpdra', 'roadma', 'roadmc', 'xpdrc'])
+
+    @classmethod
+    def tearDownClass(cls):
+        # pylint: disable=not-an-iterable
+        for process in cls.processes:
+            test_utils.shutdown_process(process)
+        print("all processes killed")
+
+    def setUp(self):  # instruction executed before each test method
+        print("execution of {}".format(self.id().split(".")[-1]))
+
+    def test_01_connect_xpdrA(self):
+        response = test_utils.mount_device("XPDR-A1", 'xpdra')
+        self.assertEqual(response.status_code, requests.codes.created, test_utils.CODE_SHOULD_BE_201)
+
+    def test_02_connect_xpdrC(self):
+        response = test_utils.mount_device("XPDR-C1", 'xpdrc')
+        self.assertEqual(response.status_code, requests.codes.created, test_utils.CODE_SHOULD_BE_201)
+
+    def test_03_connect_rdmA(self):
+        response = test_utils.mount_device("ROADM-A1", 'roadma')
+        self.assertEqual(response.status_code, requests.codes.created, test_utils.CODE_SHOULD_BE_201)
+
+    def test_04_connect_rdmC(self):
+        response = test_utils.mount_device("ROADM-C1", 'roadmc')
+        self.assertEqual(response.status_code, requests.codes.created, test_utils.CODE_SHOULD_BE_201)
+
+    def test_05_connect_xprdA_N1_to_roadmA_PP1(self):
+        response = test_utils.connect_xpdr_to_rdm_request("XPDR-A1", "1", "1",
+                                                          "ROADM-A1", "1", "SRG1-PP1-TXRX")
+        self.assertEqual(response.status_code, requests.codes.ok)
+        res = response.json()
+        self.assertIn('Xponder Roadm Link created successfully', res["output"]["result"])
+        time.sleep(2)
+
+    def test_06_connect_roadmA_PP1_to_xpdrA_N1(self):
+        response = test_utils.connect_rdm_to_xpdr_request("XPDR-A1", "1", "1",
+                                                          "ROADM-A1", "1", "SRG1-PP1-TXRX")
+        self.assertEqual(response.status_code, requests.codes.ok)
+        res = response.json()
+        self.assertIn('Roadm Xponder links created successfully', res["output"]["result"])
+        time.sleep(2)
+
+    def test_07_connect_xprdC_N1_to_roadmC_PP1(self):
+        response = test_utils.connect_xpdr_to_rdm_request("XPDR-C1", "1", "1",
+                                                          "ROADM-C1", "1", "SRG1-PP1-TXRX")
+        self.assertEqual(response.status_code, requests.codes.ok)
+        res = response.json()
+        self.assertIn('Xponder Roadm Link created successfully', res["output"]["result"])
+        time.sleep(2)
+
+    def test_08_connect_roadmC_PP1_to_xpdrC_N1(self):
+        response = test_utils.connect_rdm_to_xpdr_request("XPDR-C1", "1", "1",
+                                                          "ROADM-C1", "1", "SRG1-PP1-TXRX")
+        self.assertEqual(response.status_code, requests.codes.ok)
+        res = response.json()
+        self.assertIn('Roadm Xponder links created successfully', res["output"]["result"])
+        time.sleep(2)
+
+    def test_09_get_notifications_service1(self):
+        data = {
+            "input": {
+                "connection-type": "service",
+                "id-consumer": "consumer",
+                "group-id": "transportpceTest"
+            }
+        }
+        response = test_utils.get_notifications_service_request(data)
+        self.assertEqual(response.status_code, requests.codes.no_content)
+        time.sleep(2)
+
+    def test_10_create_eth_service1(self):
+        self.cr_serv_sample_data["input"]["service-name"] = "service1"
+        response = test_utils.service_create_request(self.cr_serv_sample_data)
+        self.assertEqual(response.status_code, requests.codes.ok)
+        res = response.json()
+        self.assertIn('PCE calculation in progress',
+                      res['output']['configuration-response-common']['response-message'])
+        time.sleep(self.WAITING)
+
+    def test_11_get_notifications_service1(self):
+        data = {
+            "input": {
+                "connection-type": "service",
+                "id-consumer": "consumer",
+                "group-id": "transportpceTest"
+            }
+        }
+        response = test_utils.get_notifications_service_request(data)
+        self.assertEqual(response.status_code, requests.codes.ok)
+        res = response.json()
+        self.assertEqual(res['output']['notification-service'][-2]['service-name'], 'service1')
+        self.assertEqual(res['output']['notification-service'][-2]['connection-type'], 'service')
+        self.assertEqual(res['output']['notification-service'][-2]['message'], 'ServiceCreate request received ...')
+        self.assertEqual(res['output']['notification-service'][-1]['service-name'], 'service1')
+        self.assertEqual(res['output']['notification-service'][-1]['message'], 'ServiceCreate request failed ...')
+        self.assertEqual(res['output']['notification-service'][-1]['response-failed'],
+                         'PCE path computation failed !')
+        time.sleep(2)
+
+    def test_12_add_omsAttributes_ROADMA_ROADMC(self):
+        # Config ROADMA-ROADMC oms-attributes
+        data = {"span": {
+            "auto-spanloss": "true",
+            "spanloss-base": 11.4,
+            "spanloss-current": 12,
+            "engineered-spanloss": 12.2,
+            "link-concatenation": [{
+                "SRLG-Id": 0,
+                "fiber-type": "smf",
+                "SRLG-length": 100000,
+                "pmd": 0.5}]}}
+        response = test_utils.add_oms_attr_request("ROADM-A1-DEG2-DEG2-TTP-TXRXtoROADM-C1-DEG1-DEG1-TTP-TXRX", data)
+        self.assertEqual(response.status_code, requests.codes.created)
+
+    def test_13_add_omsAttributes_ROADMC_ROADMA(self):
+        # Config ROADMC-ROADMA oms-attributes
+        data = {"span": {
+            "auto-spanloss": "true",
+            "spanloss-base": 11.4,
+            "spanloss-current": 12,
+            "engineered-spanloss": 12.2,
+            "link-concatenation": [{
+                "SRLG-Id": 0,
+                "fiber-type": "smf",
+                "SRLG-length": 100000,
+                "pmd": 0.5}]}}
+        response = test_utils.add_oms_attr_request("ROADM-C1-DEG1-DEG1-TTP-TXRXtoROADM-A1-DEG2-DEG2-TTP-TXRX", data)
+        self.assertEqual(response.status_code, requests.codes.created)
+
+    # test service-create for Eth service from xpdr to xpdr
+    def test_14_create_eth_service1(self):
+        self.cr_serv_sample_data["input"]["service-name"] = "service1"
+        response = test_utils.service_create_request(self.cr_serv_sample_data)
+        self.assertEqual(response.status_code, requests.codes.ok)
+        res = response.json()
+        self.assertIn('PCE calculation in progress',
+                      res['output']['configuration-response-common']['response-message'])
+        time.sleep(self.WAITING)
+
+    def test_15_get_eth_service1(self):
+        response = test_utils.get_service_list_request("services/service1")
+        self.assertEqual(response.status_code, requests.codes.ok)
+        res = response.json()
+        self.assertEqual(
+            res['services'][0]['administrative-state'], 'inService')
+        self.assertEqual(
+            res['services'][0]['service-name'], 'service1')
+        self.assertEqual(
+            res['services'][0]['connection-type'], 'service')
+        self.assertEqual(
+            res['services'][0]['lifecycle-state'], 'planned')
+        time.sleep(2)
+
+    def test_16_get_notifications_service1(self):
+        data = {
+            "input": {
+                "connection-type": "service",
+                "id-consumer": "consumer",
+                "group-id": "transportpceTest"
+            }
+        }
+        response = test_utils.get_notifications_service_request(data)
+        self.assertEqual(response.status_code, requests.codes.ok)
+        res = response.json()
+        self.assertEqual(res['output']['notification-service'][-3]['service-name'], 'service1')
+        self.assertEqual(res['output']['notification-service'][-3]['connection-type'], 'service')
+        self.assertEqual(res['output']['notification-service'][-3]['message'], 'ServiceCreate request received ...')
+        self.assertEqual(res['output']['notification-service'][-2]['service-name'], 'service1')
+        self.assertEqual(res['output']['notification-service'][-2]['message'], 'PCE calculation done OK !')
+        self.assertEqual(res['output']['notification-service'][-1]['service-name'], 'service1')
+        self.assertEqual(res['output']['notification-service'][-1]['message'], 'Service implemented !')
+        time.sleep(2)
+
+    def test_17_delete_eth_service1(self):
+        response = test_utils.service_delete_request("service1")
+        self.assertEqual(response.status_code, requests.codes.ok)
+        res = response.json()
+        self.assertIn('Renderer service delete in progress',
+                      res['output']['configuration-response-common']['response-message'])
+        time.sleep(20)
+
+    def test_18_get_notifications_service1(self):
+        data = {
+            "input": {
+                "connection-type": "service",
+                "id-consumer": "consumer",
+                "group-id": "transportpceTest"
+            }
+        }
+        response = test_utils.get_notifications_service_request(data)
+        self.assertEqual(response.status_code, requests.codes.ok)
+        res = response.json()
+        self.assertEqual(res['output']['notification-service'][-2]['service-name'], 'service1')
+        self.assertEqual(res['output']['notification-service'][-2]['connection-type'], 'service')
+        self.assertEqual(res['output']['notification-service'][-2]['message'], 'ServiceDelete request received ...')
+        self.assertEqual(res['output']['notification-service'][-1]['service-name'], 'service1')
+        self.assertEqual(res['output']['notification-service'][-1]['message'], 'Service deleted !')
+        time.sleep(2)
+
+    def test_19_disconnect_XPDRA(self):
+        response = test_utils.unmount_device("XPDR-A1")
+        self.assertEqual(response.status_code, requests.codes.ok, test_utils.CODE_SHOULD_BE_200)
+
+    def test_20_disconnect_XPDRC(self):
+        response = test_utils.unmount_device("XPDR-C1")
+        self.assertEqual(response.status_code, requests.codes.ok, test_utils.CODE_SHOULD_BE_200)
+
+    def test_21_disconnect_ROADMA(self):
+        response = test_utils.unmount_device("ROADM-A1")
+        self.assertEqual(response.status_code, requests.codes.ok, test_utils.CODE_SHOULD_BE_200)
+
+    def test_22_disconnect_ROADMC(self):
+        response = test_utils.unmount_device("ROADM-C1")
+        self.assertEqual(response.status_code, requests.codes.ok, test_utils.CODE_SHOULD_BE_200)
+
+
+if __name__ == "__main__":
+    unittest.main(verbosity=2)
index c2447a992fb8577cf73af4d559661aec17fa1870..1026df7e0583d20f743b32f57bd84a11fa224be5 100644 (file)
@@ -45,6 +45,7 @@ URL_CONFIG_CLLI_NET = "{}/config/ietf-network:networks/network/clli-network/"
 URL_CONFIG_ORDM_NET = "{}/config/ietf-network:networks/network/openroadm-network/"
 URL_PORTMAPPING = "{}/config/transportpce-portmapping:network/nodes/"
 URL_OPER_SERV_LIST = "{}/operational/org-openroadm-service:service-list/"
+URL_GET_NBINOTIFICATIONS_SERV = "{}/operations/nbi-notifications:get-notifications-service/"
 URL_SERV_CREATE = "{}/operations/org-openroadm-service:service-create"
 URL_SERV_DELETE = "{}/operations/org-openroadm-service:service-delete"
 URL_SERVICE_PATH = "{}/operations/transportpce-device-renderer:service-path"
@@ -337,6 +338,10 @@ def portmapping_request(suffix: str):
     return get_request(url)
 
 
+def get_notifications_service_request(attr):
+    return post_request(URL_GET_NBINOTIFICATIONS_SERV, attr)
+
+
 def get_service_list_request(suffix: str):
     url = URL_OPER_SERV_LIST + suffix
     return get_request(url)
diff --git a/tox.ini b/tox.ini
index aa39abd1f884a8c79006d05da74d8394dec97546..037d646abfde12f7c5ecc8825bfab5875d002bf7 100644 (file)
--- a/tox.ini
+++ b/tox.ini
@@ -23,19 +23,19 @@ commands =
 #install honeynode 1.2.1 simulators
   {py3,portmapping,topoPortMapping,rspn,topology,pce,olm,end2end}: - sh -c "./install_honeynode.sh 1.2.1"
 #patch OLM constant to speed up tests, unnecessary for PCE
-  {py3,portmapping,topoPortMapping,rspn,topology,olm,end2end,portmapping221,rspn221,otnrenderer,otnshrenderer,topology221,otn-topology,olm221,otnend2end,end2end221,tapi221}: - sh -c "sed -i'_' 's@=.*//#FUNCTESTVAL=@=@g' ../olm/src/main/java/org/opendaylight/transportpce/olm/util/OlmUtils.java"
+  {py3,portmapping,topoPortMapping,rspn,topology,olm,end2end,portmapping221,rspn221,otnrenderer,otnshrenderer,topology221,otn-topology,olm221,otnend2end,end2end221,tapi221,nbinotifications}: - sh -c "sed -i'_' 's@=.*//#FUNCTESTVAL=@=@g' ../olm/src/main/java/org/opendaylight/transportpce/olm/util/OlmUtils.java"
 #build controller, source JDK_JAVA_OPTIONS to remove illegal reflective acces warnings introduced by Java11
-  {py3,portmapping,topoPortMapping,rspn,topology,pce,olm,end2end,portmapping221,rspn221,otnrenderer,otnshrenderer,topology221,otntopology,flexgrid,olm221,tapi221,otnend2end,end2end221,gnpy}: - sh -c ". $PWD/reflectwarn.sh && cd .. && mvn clean install -s tests/odl_settings.xml -DskipTests -Dmaven.javadoc.skip=true -Dodlparent.spotbugs.skip -Dodlparent.checkstyle.skip"
-  {py3,portmapping,topoPortMapping,rspn,topology,olm,end2end,portmapping221,rspn221,otnrenderer,otnshrenderer,topology221,otn-topology,olm221,otnend2end,end2end221,tapi221}: - sh -c "mv  ../olm/src/main/java/org/opendaylight/transportpce/olm/util/OlmUtils.java_  ../olm/src/main/java/org/opendaylight/transportpce/olm/util/OlmUtils.java"
+  {py3,portmapping,topoPortMapping,rspn,topology,pce,olm,end2end,portmapping221,rspn221,otnrenderer,otnshrenderer,topology221,otntopology,flexgrid,olm221,tapi221,otnend2end,end2end221,gnpy,nbinotifications}: - sh -c ". $PWD/reflectwarn.sh && cd .. && mvn clean install -s tests/odl_settings.xml -DskipTests -Dmaven.javadoc.skip=true -Dodlparent.spotbugs.skip -Dodlparent.checkstyle.skip"
+  {py3,portmapping,topoPortMapping,rspn,topology,olm,end2end,portmapping221,rspn221,otnrenderer,otnshrenderer,topology221,otn-topology,olm221,otnend2end,end2end221,tapi221,nbinotifications}: - sh -c "mv  ../olm/src/main/java/org/opendaylight/transportpce/olm/util/OlmUtils.java_  ../olm/src/main/java/org/opendaylight/transportpce/olm/util/OlmUtils.java"
 #patch Karaf exec for the same reason at runtime
-  {py3,portmapping,topoPortMapping,rspn,topology,pce,olm,end2end,portmapping221,rspn221,otnrenderer,otnshrenderer,topology221,otntopology,flexgrid,olm221,tapi221,otnend2end,end2end221,gnpy}: - sh -c "sed -i'_' 's@!/bin/sh@!/bin/sh\'$'\n. $(dirname $0)/../../../../tests/reflectwarn.sh@' ../karaf/target/assembly/bin/karaf"
+  {py3,portmapping,topoPortMapping,rspn,topology,pce,olm,end2end,portmapping221,rspn221,otnrenderer,otnshrenderer,topology221,otntopology,flexgrid,olm221,tapi221,otnend2end,end2end221,gnpy,nbinotifications}: - sh -c "sed -i'_' 's@!/bin/sh@!/bin/sh\'$'\n. $(dirname $0)/../../../../tests/reflectwarn.sh@' ../karaf/target/assembly/bin/karaf"
   # the following command would be the straight and right way to support both BSD and GNU sed versions
   # sh -c "sed -i'_' '1 a\'$'\n. \$(dirname \$0)/\.\./\.\./\.\./\.\./tests/reflectwarn.sh\n' ../karaf/target/assembly/bin/karaf"
   # but tox reinterprets the quotes as
   # sh -c 'sed -i'"'"'_'"'"' '"'"'1 a\'"'"'$'"'"'\n. \$(dirname \$0)/\.\./\.\./\.\./\.\./tests/reflectwarn.sh\n'"'"' ../karaf/target/assembly/bin/karaf'
   # ,what results in an unexpected different formating (with a $ on the second line and the dot on the third)
 #build Lighty if needed
-  {py3,portmapping,topoPortMapping,rspn,topology,pce,olm,end2end,portmapping221,rspn221,otnrenderer,otnshrenderer,topology221,otntopology,flexgrid,olm221,tapi221,otnend2end,end2end221,gnpy}: - sh -c 'if [ "$USE_LIGHTY" = "True" ]; then (cd ../lighty && ./build.sh); fi'
+  {py3,portmapping,topoPortMapping,rspn,topology,pce,olm,end2end,portmapping221,rspn221,otnrenderer,otnshrenderer,topology221,otntopology,flexgrid,olm221,tapi221,otnend2end,end2end221,gnpy,nbinotifications}: - sh -c 'if [ "$USE_LIGHTY" = "True" ]; then (cd ../lighty && ./build.sh); fi'
 #run 1.2.1 functional tests
   {py3,portmapping}: nosetests --with-xunit transportpce_tests/1.2.1/test_portmapping.py
   {py3,topoPortMapping}: nosetests --with-xunit transportpce_tests/1.2.1/test_topo_portmapping.py
@@ -46,7 +46,7 @@ commands =
   #E2E 1.2.1 moved at the end before 2.2.1 E2E
 #run 2.2.1 functional tests
 #install honeynode 2.2.1 simulators
-  {py3,portmapping221,rspn221,otnrenderer,otnshrenderer,topology221,otntopology,flexgrid,olm221,tapi221,otnend2end,end2end221}: - sh -c "./install_honeynode.sh 2.2.1"
+  {py3,portmapping221,rspn221,otnrenderer,otnshrenderer,topology221,otntopology,flexgrid,olm221,tapi221,otnend2end,end2end221,nbinotifications}: - sh -c "./install_honeynode.sh 2.2.1"
   {py3,portmapping221}: nosetests --with-xunit transportpce_tests/2.2.1/test_portmapping.py
   {py3,topology221}: nosetests --with-xunit transportpce_tests/2.2.1/test_topology.py
   {py3,otntopology}: nosetests --with-xunit transportpce_tests/2.2.1/test_otn_topology.py
@@ -63,6 +63,9 @@ commands =
   {gnpy}: - sudo docker run -d -p 8008:5000 --name gnpy_tpce_rest1 atriki/gnpyrest:v1.2
   {gnpy}: nosetests --with-xunit transportpce_tests/1.2.1/test_gnpy.py
   {gnpy}: - sudo docker container rm -f gnpy_tpce_rest1
+  {nbinotifications}: - sudo docker-compose -f ./nbinotifications/docker-compose.yml up -d
+  {nbinotifications}: nosetests --with-xunit transportpce_tests/2.2.1/test_nbinotifications.py
+  {nbinotifications}: - sudo docker-compose -f ./nbinotifications/docker-compose.yml down --rmi all
 
 [testenv:docs]
 passenv = http_proxy HTTP_PROXY https_proxy HTTPS_PROXY no_proxy NO_PROXY