BUG-2739 Fixed leftover data when removing NETCONF device from topology
[controller.git] / opendaylight / md-sal / sal-netconf-connector / src / main / java / org / opendaylight / controller / sal / connect / netconf / sal / NetconfDeviceSalProvider.java
index fc54bfbc3d8f0b93ec58d9df664b26815a500184..568ebde0d393aca1b1d66c660d2b8f801f1dad8b 100644 (file)
@@ -11,15 +11,20 @@ import com.google.common.base.Preconditions;
 import java.util.Collection;
 import java.util.Collections;
 import java.util.concurrent.ExecutorService;
+import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+import org.opendaylight.controller.md.sal.dom.api.DOMDataBroker;
+import org.opendaylight.controller.md.sal.dom.api.DOMMountPoint;
+import org.opendaylight.controller.md.sal.dom.api.DOMMountPointService;
 import org.opendaylight.controller.sal.binding.api.BindingAwareBroker;
 import org.opendaylight.controller.sal.binding.api.BindingAwareProvider;
-import org.opendaylight.controller.sal.binding.api.data.DataProviderService;
 import org.opendaylight.controller.sal.connect.util.RemoteDeviceId;
 import org.opendaylight.controller.sal.core.api.Broker;
 import org.opendaylight.controller.sal.core.api.Provider;
-import org.opendaylight.controller.sal.core.api.mount.MountProvisionInstance;
-import org.opendaylight.controller.sal.core.api.mount.MountProvisionService;
-import org.opendaylight.yangtools.yang.binding.RpcService;
+import org.opendaylight.controller.sal.core.api.RpcProvisionRegistry;
+import org.opendaylight.controller.sal.core.api.notify.NotificationPublishService;
+import org.opendaylight.yangtools.concepts.ObjectRegistration;
+import org.opendaylight.yangtools.yang.data.api.CompositeNode;
+import org.opendaylight.yangtools.yang.model.api.SchemaContext;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -29,17 +34,19 @@ final class NetconfDeviceSalProvider implements AutoCloseable, Provider, Binding
 
     private final RemoteDeviceId id;
     private final ExecutorService executor;
-    private volatile MountProvisionInstance mountInstance;
     private volatile NetconfDeviceDatastoreAdapter datastoreAdapter;
+    private MountInstance mountInstance;
+
+    private volatile NetconfDeviceTopologyAdapter topologyDatastoreAdapter;
 
     public NetconfDeviceSalProvider(final RemoteDeviceId deviceId, final ExecutorService executor) {
         this.id = deviceId;
         this.executor = executor;
     }
 
-    public MountProvisionInstance getMountInstance() {
+    public MountInstance getMountInstance() {
         Preconditions.checkState(mountInstance != null,
-                "%s: Sal provider was not initialized by sal. Cannot get mount instance", id);
+                "%s: Mount instance was not initialized by sal. Cannot get mount instance", id);
         return mountInstance;
     }
 
@@ -49,14 +56,20 @@ final class NetconfDeviceSalProvider implements AutoCloseable, Provider, Binding
         return datastoreAdapter;
     }
 
+    public NetconfDeviceTopologyAdapter getTopologyDatastoreAdapter() {
+        Preconditions.checkState(topologyDatastoreAdapter != null,
+                "%s: Sal provider %s was not initialized by sal. Cannot get topology datastore adapter", id);
+        return topologyDatastoreAdapter;
+    }
+
     @Override
     public void onSessionInitiated(final Broker.ProviderSession session) {
-        final MountProvisionService mountService = session.getService(MountProvisionService.class);
+        logger.debug("{}: (BI)Session with sal established {}", id, session);
+
+        final DOMMountPointService mountService = session.getService(DOMMountPointService.class);
         if (mountService != null) {
-            mountInstance = mountService.createOrGetMountPoint(id.getPath());
+            mountInstance = new MountInstance(mountService, id);
         }
-
-        logger.debug("{}: (BI)Session with sal established {}", id, session);
     }
 
     @Override
@@ -64,32 +77,119 @@ final class NetconfDeviceSalProvider implements AutoCloseable, Provider, Binding
         return Collections.emptySet();
     }
 
-    @Override
-    public Collection<? extends RpcService> getImplementations() {
-        return Collections.emptySet();
-    }
-
-    @Override
-    public Collection<? extends BindingAwareProvider.ProviderFunctionality> getFunctionality() {
-        return Collections.emptySet();
-    }
-
     @Override
     public void onSessionInitiated(final BindingAwareBroker.ProviderContext session) {
-        final DataProviderService dataBroker = session.getSALService(DataProviderService.class);
-        datastoreAdapter = new NetconfDeviceDatastoreAdapter(id, dataBroker, executor);
-
         logger.debug("{}: Session with sal established {}", id, session);
-    }
 
-    @Override
-    public void onSessionInitialized(final BindingAwareBroker.ConsumerContext session) {
+        final DataBroker dataBroker = session.getSALService(DataBroker.class);
+        datastoreAdapter = new NetconfDeviceDatastoreAdapter(id, dataBroker);
+
+        topologyDatastoreAdapter = new NetconfDeviceTopologyAdapter(id, dataBroker);
     }
 
     public void close() throws Exception {
-        mountInstance = null;
+        mountInstance.close();
         datastoreAdapter.close();
         datastoreAdapter = null;
+        topologyDatastoreAdapter.close();
+        topologyDatastoreAdapter = null;
+    }
+
+    static final class MountInstance implements AutoCloseable {
+
+        private DOMMountPointService mountService;
+        private final RemoteDeviceId id;
+        private ObjectRegistration<DOMMountPoint> registration;
+        private NotificationPublishService notificationSerivce;
+
+        private ObjectRegistration<DOMMountPoint> topologyRegistration;
+
+        MountInstance(final DOMMountPointService mountService, final RemoteDeviceId id) {
+            this.mountService = Preconditions.checkNotNull(mountService);
+            this.id = Preconditions.checkNotNull(id);
+        }
+
+        @Deprecated
+        synchronized void onDeviceConnected(final SchemaContext initialCtx,
+                final DOMDataBroker broker, final RpcProvisionRegistry rpc,
+                final NotificationPublishService notificationSerivce) {
+
+            Preconditions.checkNotNull(mountService, "Closed");
+            Preconditions.checkState(registration == null, "Already initialized");
+
+            final DOMMountPointService.DOMMountPointBuilder mountBuilder = mountService.createMountPoint(id.getPath());
+            mountBuilder.addInitialSchemaContext(initialCtx);
+
+            mountBuilder.addService(DOMDataBroker.class, broker);
+            mountBuilder.addService(RpcProvisionRegistry.class, rpc);
+            this.notificationSerivce = notificationSerivce;
+            mountBuilder.addService(NotificationPublishService.class, notificationSerivce);
+
+            registration = mountBuilder.register();
+        }
+
+        @Deprecated
+        synchronized void onDeviceDisconnected() {
+            if(registration == null) {
+                return;
+            }
+
+            try {
+                registration.close();
+            } catch (final Exception e) {
+                // Only log and ignore
+                logger.warn("Unable to unregister mount instance for {}. Ignoring exception", id.getPath(), e);
+            } finally {
+                registration = null;
+            }
+        }
+
+        synchronized void onTopologyDeviceConnected(final SchemaContext initialCtx,
+                final DOMDataBroker broker, final RpcProvisionRegistry rpc,
+                final NotificationPublishService notificationSerivce) {
+
+            Preconditions.checkNotNull(mountService, "Closed");
+            Preconditions.checkState(topologyRegistration == null, "Already initialized");
+
+            final DOMMountPointService.DOMMountPointBuilder mountBuilder = mountService.createMountPoint(id.getTopologyPath());
+            mountBuilder.addInitialSchemaContext(initialCtx);
+
+            mountBuilder.addService(DOMDataBroker.class, broker);
+            mountBuilder.addService(RpcProvisionRegistry.class, rpc);
+            this.notificationSerivce = notificationSerivce;
+            mountBuilder.addService(NotificationPublishService.class, notificationSerivce);
+
+            topologyRegistration = mountBuilder.register();
+        }
+
+        synchronized void onTopologyDeviceDisconnected() {
+            if(topologyRegistration == null) {
+                return;
+            }
+
+            try {
+                topologyRegistration.close();
+            } catch (final Exception e) {
+                // Only log and ignore
+                logger.warn("Unable to unregister mount instance for {}. Ignoring exception", id.getTopologyPath(), e);
+            } finally {
+                topologyRegistration = null;
+            }
+        }
+
+        @Override
+        synchronized public void close() throws Exception {
+            if(registration != null) {
+                onDeviceDisconnected();
+                onTopologyDeviceDisconnected();
+            }
+            mountService = null;
+        }
+
+        public synchronized void publish(final CompositeNode domNotification) {
+            Preconditions.checkNotNull(notificationSerivce, "Device not set up yet, cannot handle notification {}", domNotification);
+            notificationSerivce.publish(domNotification);
+        }
     }
 
 }