Add change notification functionality to yang-store. 79/2079/3
authorTomas Olvecky <tolvecky@cisco.com>
Tue, 22 Oct 2013 12:11:09 +0000 (14:11 +0200)
committerTomas Olvecky <tolvecky@cisco.com>
Wed, 23 Oct 2013 10:20:34 +0000 (12:20 +0200)
Add ability to listen for change notifications to yang-store. Listeners get notified when
new yang files are found in bundles and also when bundle with yang files is stopped.

Change-Id: I7c665a57ba7face18bf128d6a7db17c1a23526ce
Signed-off-by: Tomas Olvecky <tolvecky@cisco.com>
opendaylight/commons/opendaylight/pom.xml
opendaylight/config/yang-store-api/pom.xml
opendaylight/config/yang-store-api/src/main/java/org/opendaylight/controller/config/yang/store/api/YangStoreListenerRegistration.java [new file with mode: 0644]
opendaylight/config/yang-store-api/src/main/java/org/opendaylight/controller/config/yang/store/api/YangStoreService.java
opendaylight/config/yang-store-api/src/main/java/org/opendaylight/controller/config/yang/store/spi/YangStoreListener.java [new file with mode: 0644]
opendaylight/config/yang-store-impl/pom.xml
opendaylight/config/yang-store-impl/src/main/java/org/opendaylight/controller/config/yang/store/impl/ExtenderYangTracker.java
opendaylight/config/yang-store-impl/src/test/java/org/opendaylight/controller/config/yang/store/impl/HardcodedYangStoreService.java
opendaylight/distribution/opendaylight/pom.xml
opendaylight/netconf/pom.xml

index 77edba5b386cf410b3370d4458595d02d2b43a00..10b4ceab812ccad13e7c360930d22475633c3ec1 100644 (file)
@@ -77,6 +77,7 @@
     <controller.version>0.4.1-SNAPSHOT</controller.version>
     <config.version>0.2.1-SNAPSHOT</config.version>
     <netconf.version>0.2.2-SNAPSHOT</netconf.version>
+    <config.yangstore.version>0.2.2-SNAPSHOT</config.yangstore.version>
     <mdsal.version>1.0-SNAPSHOT</mdsal.version>
     <containermanager.version>0.5.1-SNAPSHOT</containermanager.version>
     <switchmanager.api.version>0.5.1-SNAPSHOT</switchmanager.api.version>
index 9388bdc50a6ee9ba8789564039b2ef9b22d9c084..4393903fd5ac7a757dc94ebbfe591ff88c7ff64e 100644 (file)
     <artifactId>yang-store-api</artifactId>
     <name>${project.artifactId}</name>
     <packaging>bundle</packaging>
+    <version>${config.yangstore.version}</version>
 
     <dependencies>
         <dependency>
             <groupId>org.opendaylight.controller</groupId>
             <artifactId>yang-jmx-generator</artifactId>
-            <version>0.2.1-SNAPSHOT</version>
+            <version>${config.version}</version>
         </dependency>
     </dependencies>
 
                 <artifactId>maven-bundle-plugin</artifactId>
                 <configuration>
                     <instructions>
-
-                        <Private-Package>
-                        </Private-Package>
-
                         <Import-Package>
                             org.opendaylight.controller.config.yangjmxgenerator,
                             org.opendaylight.yangtools.yang.model.api
                         </Import-Package>
                         <Export-Package>
-                            org.opendaylight.controller.config.yang.store.api
+                            org.opendaylight.controller.config.yang.store.api,
+                            org.opendaylight.controller.config.yang.store.spi
                         </Export-Package>
                     </instructions>
                 </configuration>
             </plugin>
-            <!-- test jar -->
-            <plugin>
-                <groupId>org.apache.maven.plugins</groupId>
-                <artifactId>maven-jar-plugin</artifactId>
-            </plugin>
         </plugins>
     </build>
 
diff --git a/opendaylight/config/yang-store-api/src/main/java/org/opendaylight/controller/config/yang/store/api/YangStoreListenerRegistration.java b/opendaylight/config/yang-store-api/src/main/java/org/opendaylight/controller/config/yang/store/api/YangStoreListenerRegistration.java
new file mode 100644 (file)
index 0000000..8101595
--- /dev/null
@@ -0,0 +1,14 @@
+/*
+ * Copyright (c) 2013 Cisco Systems, 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.controller.config.yang.store.api;
+
+public interface YangStoreListenerRegistration extends AutoCloseable {
+
+    @Override
+    void close();
+}
index 15619a88cc41b3ac88e59469b3e72563de0e1b5c..3ac4b84fdb2e1b203d9508dfb01f16b0db76af08 100644 (file)
@@ -7,6 +7,8 @@
  */
 package org.opendaylight.controller.config.yang.store.api;
 
+import org.opendaylight.controller.config.yang.store.spi.YangStoreListener;
+
 /**
  * Yang store OSGi service
  */
@@ -19,4 +21,10 @@ public interface YangStoreService {
      */
     YangStoreSnapshot getYangStoreSnapshot() throws YangStoreException;
 
+
+    /**
+     * Allows for registering for change notifications.
+     */
+    YangStoreListenerRegistration registerListener(YangStoreListener listener);
+
 }
diff --git a/opendaylight/config/yang-store-api/src/main/java/org/opendaylight/controller/config/yang/store/spi/YangStoreListener.java b/opendaylight/config/yang-store-api/src/main/java/org/opendaylight/controller/config/yang/store/spi/YangStoreListener.java
new file mode 100644 (file)
index 0000000..72c3d34
--- /dev/null
@@ -0,0 +1,23 @@
+/*
+ * Copyright (c) 2013 Cisco Systems, 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.controller.config.yang.store.spi;
+
+import java.net.URL;
+import java.util.Collection;
+
+/**
+ * Implementation of this interface gets notified when bundle containing yang files in META-INF/yang has been
+ * added or removed. One notification is sent per one bundle.
+ */
+public interface YangStoreListener {
+
+    void onAddedYangURL(Collection<URL> url);
+
+    void onRemovedYangURL(Collection<URL> url);
+
+}
index 11224cef2286a9239a12825eedaf179fa1c3fbb5..c9105262f95384d3f180f41dbdcbd3c669dd7dd5 100644 (file)
     <artifactId>yang-store-impl</artifactId>
     <name>${project.artifactId}</name>
     <packaging>bundle</packaging>
+    <version>${config.yangstore.version}</version>
 
     <dependencies>
         <dependency>
             <groupId>${project.groupId}</groupId>
             <artifactId>yang-store-api</artifactId>
-            <version>0.2.1-SNAPSHOT</version>
+            <version>${config.yangstore.version}</version>
         </dependency>
         <dependency>
             <groupId>org.osgi</groupId>
@@ -28,7 +29,7 @@
         <dependency>
             <groupId>${project.groupId}</groupId>
             <artifactId>yang-jmx-generator</artifactId>
-            <version>0.2.1-SNAPSHOT</version>
+            <version>${config.version}</version>
         </dependency>
         <dependency>
             <groupId>org.opendaylight.yangtools</groupId>
@@ -66,6 +67,7 @@
 
                         <Import-Package>
                             org.opendaylight.controller.config.yang.store.api,
+                            org.opendaylight.controller.config.yang.store.spi,
                             org.opendaylight.controller.config.yangjmxgenerator,
                             com.google.common.base,
                             com.google.common.collect,
@@ -74,7 +76,6 @@
                             org.osgi.framework,
                             org.osgi.util.tracker,
                             org.slf4j,
-                            javax.*,
                             <!-- YANGTOOLS -->
                             org.opendaylight.yangtools.sal.binding.yang.types,
                             org.opendaylight.yangtools.yang.common,
index e3be7346248809ac75ec26333ef3fa8a3f2bf3e4..ee2864878d1c0a7b5e2bdfb27ad49344d79b46fc 100644 (file)
@@ -10,13 +10,13 @@ package org.opendaylight.controller.config.yang.store.impl;
 import java.io.IOException;
 import java.io.InputStream;
 import java.net.URL;
-import java.util.Collection;
-import java.util.Enumeration;
-import java.util.Set;
+import java.util.*;
 
 import org.opendaylight.controller.config.yang.store.api.YangStoreException;
+import org.opendaylight.controller.config.yang.store.api.YangStoreListenerRegistration;
 import org.opendaylight.controller.config.yang.store.api.YangStoreService;
 import org.opendaylight.controller.config.yang.store.api.YangStoreSnapshot;
+import org.opendaylight.controller.config.yang.store.spi.YangStoreListener;
 import org.osgi.framework.Bundle;
 import org.osgi.framework.BundleContext;
 import org.osgi.framework.BundleEvent;
@@ -43,6 +43,7 @@ public class ExtenderYangTracker extends BundleTracker<Object> implements
             .create();
     private final YangStoreCache cache = new YangStoreCache();
     private final MbeParser mbeParser;
+    private final List<YangStoreListener> listeners = new ArrayList<>();
 
     public ExtenderYangTracker(BundleContext context) {
         this(context, new MbeParser());
@@ -59,38 +60,54 @@ public class ExtenderYangTracker extends BundleTracker<Object> implements
     @Override
     public Object addingBundle(Bundle bundle, BundleEvent event) {
 
-        // Ignore system bundle
-        //
-        // system bundle has config-api on classpath &&
+        // Ignore system bundle:
+        // system bundle might have config-api on classpath &&
         // config-api contains yang files =>
-        // system bundle contains yang files from that bundle
+        // system bundle might contain yang files from that bundle
         if (bundle.getBundleId() == 0)
             return bundle;
 
-        Enumeration<URL> yangURLs = bundle.findEntries("META-INF/yang",
-                "*.yang", false);
-
-        if (yangURLs == null)
-            return bundle;
-
-        synchronized (this) {
-            while (yangURLs.hasMoreElements()) {
-                URL yang = yangURLs.nextElement();
-                logger.debug("Bundle {} found yang file {}", bundle, yang);
-                bundlesToYangURLs.put(bundle, yang);
+        Enumeration<URL> yangURLs = bundle.findEntries("META-INF/yang", "*.yang", false);
+        if (yangURLs != null) {
+            synchronized (this) {
+                while (yangURLs.hasMoreElements()) {
+                    URL url = yangURLs.nextElement();
+                    logger.debug("Bundle {} found yang file {}", bundle, url);
+                    bundlesToYangURLs.put(bundle, url);
+                }
+                Collection<URL> urls = bundlesToYangURLs.get(bundle);
+                notifyListeners(urls, true);
             }
         }
-
         return bundle;
     }
 
+    private void notifyListeners(Collection<URL> urls, boolean adding) {
+        if (urls.size() > 0) {
+            RuntimeException potential = new RuntimeException("Error while notifying listeners");
+            for (YangStoreListener listener : listeners) {
+                try {
+                    if (adding) {
+                        listener.onAddedYangURL(urls);
+                    } else {
+                        listener.onRemovedYangURL(urls);
+                    }
+                } catch(RuntimeException e) {
+                    potential.addSuppressed(e);
+                }
+            }
+            if (potential.getSuppressed().length > 0) {
+                throw potential;
+            }
+        }
+    }
+
     @Override
-    public void removedBundle(Bundle bundle, BundleEvent event, Object object) {
-        synchronized (this) {
-            Collection<URL> urls = bundlesToYangURLs.removeAll(bundle);
-            logger.debug(
-                    "Removed following yang URLs {} because of removed bundle {}",
-                    urls, bundle);
+    public synchronized void removedBundle(Bundle bundle, BundleEvent event, Object object) {
+        Collection<URL> urls = bundlesToYangURLs.removeAll(bundle);
+        if (urls.size() > 0) {
+            logger.debug("Removed following yang URLs {} because of removed bundle {}", urls, bundle);
+            notifyListeners(urls, false);
         }
     }
 
@@ -139,6 +156,17 @@ public class ExtenderYangTracker extends BundleTracker<Object> implements
                 });
     }
 
+    @Override
+    public synchronized YangStoreListenerRegistration registerListener(final YangStoreListener listener) {
+        listeners.add(listener);
+        return new YangStoreListenerRegistration() {
+            @Override
+            public void close() {
+                listeners.remove(listener);
+            }
+        };
+    }
+
     private static final class YangStoreCache {
 
         Set<URL> cachedUrls;
index 96833bd5070392d802a66eb2b70aa2fcd6010cbb..844f682b7a6348a2e86cecceb35e010772e5074e 100644 (file)
@@ -17,8 +17,10 @@ import java.util.Collection;
 
 import org.apache.commons.io.IOUtils;
 import org.opendaylight.controller.config.yang.store.api.YangStoreException;
+import org.opendaylight.controller.config.yang.store.api.YangStoreListenerRegistration;
 import org.opendaylight.controller.config.yang.store.api.YangStoreService;
 import org.opendaylight.controller.config.yang.store.api.YangStoreSnapshot;
+import org.opendaylight.controller.config.yang.store.spi.YangStoreListener;
 
 public class HardcodedYangStoreService implements YangStoreService {
 
@@ -48,4 +50,9 @@ public class HardcodedYangStoreService implements YangStoreService {
         }
         return new MbeParser().parseYangFiles(byteArrayInputStreams);
     }
+
+    @Override
+    public YangStoreListenerRegistration registerListener(YangStoreListener listener){
+        throw new UnsupportedOperationException("Cannot register for changes on this service");
+    }
 }
index d95a6dca01a7336c67f20dbfadd61734c81851fb..a3a323fc97b4eaa043aad6f7ae5fae89e12cb1b8 100644 (file)
         <dependency>
           <groupId>org.opendaylight.controller</groupId>
           <artifactId>yang-store-api</artifactId>
-          <version>${config.version}</version>
+          <version>${config.yangstore.version}</version>
         </dependency>
         <dependency>
           <groupId>org.opendaylight.controller</groupId>
           <artifactId>yang-store-impl</artifactId>
-          <version>${config.version}</version>
+          <version>${config.yangstore.version}</version>
         </dependency>
         <dependency>
           <groupId>org.opendaylight.controller</groupId>
index 8436a1388b250ef683cf0eeadee0143b806ace13..b9f93144992e6ae3525b9dc007599dab5986788d 100644 (file)
             <dependency>
                 <groupId>${project.groupId}</groupId>
                 <artifactId>yang-store-api</artifactId>
-                <version>${config.version}</version>
+                <version>${config.yangstore.version}</version>
             </dependency>
             <dependency>
                 <groupId>${project.groupId}</groupId>
                 <artifactId>yang-store-impl</artifactId>
-                <version>${config.version}</version>
+                <version>${config.yangstore.version}</version>
             </dependency>
             <dependency>
                 <groupId>${project.groupId}</groupId>