[ONOS-5090] YANG notification handler implementation

Change-Id: I8e161757b9f39e7beb2c54ebac8dae9ee6b4907f
~
diff --git a/apps/yms/app/src/main/java/org/onosproject/yms/app/ych/DefaultYangCodecHandler.java b/apps/yms/app/src/main/java/org/onosproject/yms/app/ych/DefaultYangCodecHandler.java
index 8ba016d..45eb37f 100644
--- a/apps/yms/app/src/main/java/org/onosproject/yms/app/ych/DefaultYangCodecHandler.java
+++ b/apps/yms/app/src/main/java/org/onosproject/yms/app/ych/DefaultYangCodecHandler.java
@@ -102,7 +102,7 @@
 
     @Override
     public void addDeviceSchema(Class<?> yangModule) {
-        schemaRegistry.registerApplication(null, yangModule, null);
+        schemaRegistry.registerApplication(null, yangModule);
     }
 
     @Override
diff --git a/apps/yms/app/src/main/java/org/onosproject/yms/app/ymsm/YmsManager.java b/apps/yms/app/src/main/java/org/onosproject/yms/app/ymsm/YmsManager.java
index 4ccce37..475a67e 100644
--- a/apps/yms/app/src/main/java/org/onosproject/yms/app/ymsm/YmsManager.java
+++ b/apps/yms/app/src/main/java/org/onosproject/yms/app/ymsm/YmsManager.java
@@ -25,12 +25,14 @@
 import org.onosproject.core.ApplicationId;
 import org.onosproject.core.CoreService;
 import org.onosproject.core.IdGenerator;
+import org.onosproject.event.ListenerService;
 import org.onosproject.yms.app.yab.YangApplicationBroker;
 import org.onosproject.yms.app.ych.DefaultYangCodecHandler;
 import org.onosproject.yms.app.ych.defaultcodecs.YangCodecRegistry;
 import org.onosproject.yms.app.ydt.DefaultYdtWalker;
 import org.onosproject.yms.app.ydt.YangRequestWorkBench;
 import org.onosproject.yms.app.ynh.YangNotificationExtendedService;
+import org.onosproject.yms.app.ynh.YangNotificationManager;
 import org.onosproject.yms.app.ysr.DefaultYangSchemaRegistry;
 import org.onosproject.yms.app.ysr.YangSchemaRegistry;
 import org.onosproject.yms.ych.YangCodecHandler;
@@ -86,7 +88,7 @@
                 Executors.newSingleThreadExecutor(groupedThreads(
                         "onos/apps/yang-management-system/schema-registry",
                         "schema-registry-handler", log));
-
+        ynhExtendedService = new YangNotificationManager(schemaRegistry);
         //Initilize the default codecs
         YangCodecRegistry.initializeDefaultCodec();
 
@@ -159,15 +161,6 @@
         return ynhExtendedService;
     }
 
-    /**
-     * Returns YANG notification extended service.
-     *
-     * @return YANG notification extended service
-     */
-    private YangNotificationExtendedService getYnhExtendedService() {
-        return ynhExtendedService;
-    }
-
     @Override
     public YangModuleLibrary getYangModuleLibrary() {
         return ((DefaultYangSchemaRegistry) schemaRegistry).getLibrary();
@@ -180,18 +173,35 @@
     }
 
     @Override
-    public void registerDefaultCodec(YangDataTreeCodec defaultCodec, YangProtocolEncodingFormat dataFormat) {
+    public void registerDefaultCodec(YangDataTreeCodec defaultCodec,
+                                     YangProtocolEncodingFormat dataFormat) {
         YangCodecRegistry.registerDefaultCodec(defaultCodec, dataFormat);
     }
 
     @Override
-    public void registerService(Object yangManager, Class<?> yangService,
-                                List<String> supportedFeatureList) {
+    public void registerService(Object manager, Class<?> service,
+                                List<String> features) {
+        schemaRegistryExecutor.execute(() -> {
+            schemaRegistry.registerApplication(manager, service);
+            processNotificationRegistration(service, manager);
+        });
+        // TODO implementation based on supported features.
+    }
 
-        //perform registration of service
-        schemaRegistryExecutor.execute(() -> schemaRegistry
-                .registerApplication(yangManager, yangService,
-                                     getYnhExtendedService()));
+    /**
+     * Process notification registration for manager class object.
+     *
+     * @param service yang service
+     * @param manager yang manager
+     */
+    private void processNotificationRegistration(Class<?> service,
+                                                 Object manager) {
+        if (manager != null && manager instanceof ListenerService) {
+            if (((DefaultYangSchemaRegistry) schemaRegistry)
+                    .verifyNotificationObject(service)) {
+                ynhExtendedService.registerAsListener((ListenerService) manager);
+            }
+        }
     }
 
     @Override
diff --git a/apps/yms/app/src/main/java/org/onosproject/yms/app/ynh/YangNotificationManager.java b/apps/yms/app/src/main/java/org/onosproject/yms/app/ynh/YangNotificationManager.java
new file mode 100644
index 0000000..59da18c
--- /dev/null
+++ b/apps/yms/app/src/main/java/org/onosproject/yms/app/ynh/YangNotificationManager.java
@@ -0,0 +1,106 @@
+/*
+ * Copyright 2016-present Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.onosproject.yms.app.ynh;
+
+import org.onosproject.event.Event;
+import org.onosproject.event.EventListener;
+import org.onosproject.event.ListenerRegistry;
+import org.onosproject.event.ListenerService;
+import org.onosproject.yms.app.ysr.YangSchemaRegistry;
+import org.onosproject.yms.app.ytb.DefaultYangTreeBuilder;
+import org.onosproject.yms.app.ytb.YangTreeBuilder;
+import org.onosproject.yms.ydt.YdtContext;
+import org.onosproject.yms.ynh.YangNotification;
+import org.onosproject.yms.ynh.YangNotificationEvent;
+import org.onosproject.yms.ynh.YangNotificationListener;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+
+import static org.onlab.util.Tools.groupedThreads;
+
+/**
+ * Representation of YANG notification manager.
+ */
+public class YangNotificationManager
+        extends ListenerRegistry<YangNotificationEvent, YangNotificationListener>
+        implements YangNotificationExtendedService {
+
+    private static final String YANG_NOTIFICATION = "yangnotification";
+    private final Logger log = LoggerFactory.getLogger(getClass());
+    private final ExecutorService executor;
+    private final YnhAbstractListener listener;
+    private final YangSchemaRegistry schemaRegistry;
+
+    /**
+     * Creates an instance of YANG notification manager.
+     *
+     * @param registry YANG schema registry
+     */
+    public YangNotificationManager(YangSchemaRegistry registry) {
+        listener = new YnhAbstractListener();
+        executor = Executors.newSingleThreadExecutor(
+                groupedThreads("onos/yms", "event-handler-%d", log));
+        schemaRegistry = registry;
+    }
+
+    @Override
+    public void registerAsListener(ListenerService manager) {
+        manager.addListener(listener);
+    }
+
+    @Override
+    public YangNotification getFilteredSubject(YangNotification subject,
+                                               YangNotification filter) {
+        return null;
+        // TODO
+    }
+
+    /**
+     * Representation of YANG notification handler's abstract listener. It
+     * listens for events from application(s).
+     */
+    private class YnhAbstractListener<E extends Event> implements
+            EventListener<E> {
+        @Override
+        public void event(Event event) {
+            executor.execute(() -> {
+                try {
+                    /*
+                     * Obtain YANG data tree corresponding to notification with
+                     * logical root node as yangnotification, followed by
+                     * module/sub-module, followed by notification.
+                     */
+                    YangTreeBuilder builder = new DefaultYangTreeBuilder();
+                    YdtContext context = builder.getYdtForNotification(
+                            event, YANG_NOTIFICATION, schemaRegistry);
+                    /*
+                     * Create YANG notification from obtained data tree and
+                     * send it to registered protocols.
+                     */
+                    YangNotification notification =
+                            new YangNotification(context);
+                    process(new YangNotificationEvent(notification));
+                } catch (Exception e) {
+                    log.warn("Failed to process {}", event, e);
+                }
+            });
+        }
+    }
+}
diff --git a/apps/yms/app/src/main/java/org/onosproject/yms/app/ysr/DefaultYangSchemaRegistry.java b/apps/yms/app/src/main/java/org/onosproject/yms/app/ysr/DefaultYangSchemaRegistry.java
index 370e9cc..ce123e1 100644
--- a/apps/yms/app/src/main/java/org/onosproject/yms/app/ysr/DefaultYangSchemaRegistry.java
+++ b/apps/yms/app/src/main/java/org/onosproject/yms/app/ysr/DefaultYangSchemaRegistry.java
@@ -16,7 +16,6 @@
 
 package org.onosproject.yms.app.ysr;
 
-import org.onosproject.event.ListenerService;
 import org.onosproject.yangutils.datamodel.RpcNotificationContainer;
 import org.onosproject.yangutils.datamodel.YangInclude;
 import org.onosproject.yangutils.datamodel.YangModule;
@@ -24,7 +23,6 @@
 import org.onosproject.yangutils.datamodel.YangSchemaNode;
 import org.onosproject.yangutils.datamodel.YangSubModule;
 import org.onosproject.yangutils.datamodel.exceptions.DataModelException;
-import org.onosproject.yms.app.ynh.YangNotificationExtendedService;
 import org.onosproject.yms.ysr.YangModuleIdentifier;
 import org.onosproject.yms.ysr.YangModuleInformation;
 import org.onosproject.yms.ysr.YangModuleLibrary;
@@ -79,72 +77,21 @@
     private static final String DATE_FORMAT = "yyyy-mm-dd";
     private static final Logger log =
             LoggerFactory.getLogger(DefaultYangSchemaRegistry.class);
-
-    /*
-     * Map for storing app objects.
-     */
     private final ConcurrentMap<String, YsrAppContext> appObjectStore;
-
-    /*
-     * Map for storing YANG schema nodes.
-     */
     private final ConcurrentMap<String, YsrAppContext> yangSchemaStore;
-
-    /*
-     * Map for storing YANG schema nodes with respect to root's generated
-     * interface file name.
-     */
     private final ConcurrentMap<String, YsrAppContext>
             yangSchemaStoreForRootInterface;
-
-    /*
-     * Map for storing YANG schema nodes root's generated op param file name.
-     */
     private final ConcurrentMap<String, YsrAppContext>
             yangSchemaStoreForRootOpParam;
-
-    /*
-     * Map for storing YANG schema nodes with respect to notifications.
-     */
     private final ConcurrentMap<String, YsrAppContext>
             yangRootSchemaStoreForNotification;
-
-    /*
-     * Map for storing registered classes.
-     */
     private final ConcurrentMap<String, Class<?>> registerClassStore;
-
-    /*
-     * Map for storing YANG file details.
-     */
     private final ConcurrentMap<YangModuleIdentifier, String> yangFileStore;
-
-    /*
-     * Context of application which is registering with YMS.
-     */
-    private YsrAppContext ysrAppContext;
-
-    /*
-     * Context of application which is registering with YMS with multiple
-     * revision.
-     */
-    private YsrAppContext ysrContextForSchemaStore;
-
-    /*
-     * Context of application which is registering with YMS with multiple
-     * manager object.
-     */
-    private YsrAppContext ysrContextForAppStore;
-
-    /*
-     * Class loader of service application.
-     */
-    private ClassLoader classLoader;
-
-    /**
-     * YANG module library.
-     */
     private final YangModuleLibrary library;
+    private YsrAppContext ysrAppContext;
+    private YsrAppContext ysrContextForSchemaStore;
+    private YsrAppContext ysrContextForAppStore;
+    private ClassLoader classLoader;
 
     /**
      * Creates an instance of default YANG schema registry.
@@ -164,20 +111,14 @@
 
 
     @Override
-    public void registerApplication(Object appObject, Class<?> serviceClass,
-                                    YangNotificationExtendedService
-                                            notificationExtendedService) {
+    public void registerApplication(Object appObject, Class<?> serviceClass) {
 
         BundleContext bundleContext = getBundle(serviceClass)
                 .getBundleContext();
         String jarPath = getJarPathFromBundleLocation(
                 bundleContext.getBundle().getLocation(),
                 bundleContext.getProperty(USER_DIRECTORY));
-        // process application registration.
         processRegistration(serviceClass, appObject, jarPath);
-        //process notification registration.
-        processNotificationRegistration(serviceClass, appObject,
-                                        notificationExtendedService);
     }
 
     /**
@@ -588,7 +529,6 @@
         }
         log.info("successfully registered this application {}{}", appName,
                  SERVICE);
-
     }
 
     /**
@@ -773,7 +713,7 @@
      * @return true if the manager object is already registered with
      * notification handler
      */
-    boolean verifyNotificationObject(Class<?> serviceClass) {
+    public boolean verifyNotificationObject(Class<?> serviceClass) {
         YangSchemaNode schemaNode = null;
         String serviceName = serviceClass.getName();
         if (appObjectStore.containsKey(serviceName)) {
@@ -1016,25 +956,6 @@
     }
 
     /**
-     * Process notification registration for manager class object.
-     *
-     * @param yangService yang service
-     * @param yangManager yang manager
-     * @param ynhService  notification extended service
-     */
-    private void processNotificationRegistration(
-            Class<?> yangService, Object yangManager,
-            YangNotificationExtendedService ynhService) {
-
-        if (yangManager != null && yangManager instanceof ListenerService) {
-            if (verifyNotificationObject(yangService)) {
-                ynhService.registerAsListener(
-                        (ListenerService) yangManager);
-            }
-        }
-    }
-
-    /**
      * Clears database for YSR.
      */
     public void flushYsrData() {
@@ -1112,5 +1033,4 @@
     public YangModuleLibrary getLibrary() {
         return library;
     }
-
 }
diff --git a/apps/yms/app/src/main/java/org/onosproject/yms/app/ysr/YangSchemaRegistry.java b/apps/yms/app/src/main/java/org/onosproject/yms/app/ysr/YangSchemaRegistry.java
index 1812f04..8098188 100644
--- a/apps/yms/app/src/main/java/org/onosproject/yms/app/ysr/YangSchemaRegistry.java
+++ b/apps/yms/app/src/main/java/org/onosproject/yms/app/ysr/YangSchemaRegistry.java
@@ -17,7 +17,6 @@
 package org.onosproject.yms.app.ysr;
 
 import org.onosproject.yangutils.datamodel.YangSchemaNode;
-import org.onosproject.yms.app.ynh.YangNotificationExtendedService;
 
 /**
  * Abstraction of entity which provides interfaces to YANG schema registry.
@@ -27,15 +26,10 @@
     /**
      * Registers applications to YMS.
      *
-     * @param managerObject               application's object
-     * @param serviceClass                service class which needs to be
-     *                                    registered
-     * @param notificationExtendedService notification extended service to
-     *                                    register application object with YNH
+     * @param managerObject application's object
+     * @param serviceClass  service class to be registered
      */
-    void registerApplication(Object managerObject, Class<?> serviceClass,
-                             YangNotificationExtendedService
-                                     notificationExtendedService);
+    void registerApplication(Object managerObject, Class<?> serviceClass);
 
     /**
      * Unregisters applications to YMS.