Fix logging arguments
[netconf.git] / netconf / callhome-provider / src / main / java / org / opendaylight / netconf / callhome / mount / CallhomeStatusReporter.java
index ee068ec1fb20e37cc1d40062e696113463f356ac..1f819ae0a34ffa3f0cf5a32597ed9c72d1be6c86 100644 (file)
@@ -5,28 +5,28 @@
  * 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.netconf.callhome.mount;
 
-import com.google.common.base.Optional;
-import com.google.common.util.concurrent.CheckedFuture;
+import com.google.common.util.concurrent.FutureCallback;
+import com.google.common.util.concurrent.ListenableFuture;
+import com.google.common.util.concurrent.MoreExecutors;
 import java.io.IOException;
-import java.security.NoSuchAlgorithmException;
-import java.security.NoSuchProviderException;
+import java.security.GeneralSecurityException;
 import java.security.PublicKey;
-import java.security.spec.InvalidKeySpecException;
 import java.util.ArrayList;
+import java.util.Collection;
 import java.util.List;
-import java.util.Map;
-import org.opendaylight.controller.md.sal.binding.api.DataBroker;
-import org.opendaylight.controller.md.sal.binding.api.DataChangeListener;
-import org.opendaylight.controller.md.sal.binding.api.ReadOnlyTransaction;
-import org.opendaylight.controller.md.sal.binding.api.ReadWriteTransaction;
-import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
-import org.opendaylight.controller.md.sal.common.api.data.AsyncDataBroker;
-import org.opendaylight.controller.md.sal.common.api.data.AsyncDataChangeEvent;
-import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
-import org.opendaylight.controller.md.sal.common.api.data.ReadFailedException;
+import java.util.Optional;
+import java.util.concurrent.ExecutionException;
+import org.opendaylight.mdsal.binding.api.DataBroker;
+import org.opendaylight.mdsal.binding.api.DataObjectModification;
+import org.opendaylight.mdsal.binding.api.DataTreeChangeListener;
+import org.opendaylight.mdsal.binding.api.DataTreeIdentifier;
+import org.opendaylight.mdsal.binding.api.DataTreeModification;
+import org.opendaylight.mdsal.binding.api.ReadTransaction;
+import org.opendaylight.mdsal.binding.api.WriteTransaction;
+import org.opendaylight.mdsal.common.api.CommitInfo;
+import org.opendaylight.mdsal.common.api.LogicalDatastoreType;
 import org.opendaylight.netconf.callhome.protocol.AuthorizedKeysDecoder;
 import org.opendaylight.netconf.callhome.protocol.StatusRecorder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.callhome.device.status.rev170112.Device1;
@@ -47,12 +47,11 @@ import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.
 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.NodeKey;
 import org.opendaylight.yangtools.concepts.ListenerRegistration;
-import org.opendaylight.yangtools.yang.binding.DataObject;
 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-class CallhomeStatusReporter implements DataChangeListener, StatusRecorder, AutoCloseable {
+class CallhomeStatusReporter implements DataTreeChangeListener<Node>, StatusRecorder, AutoCloseable {
     private static final InstanceIdentifier<Topology> NETCONF_TOPO_IID =
             InstanceIdentifier.create(NetworkTopology.class).child(Topology.class,
                     new TopologyKey(new TopologyId(TopologyNetconf.QNAME.getLocalName())));
@@ -60,46 +59,54 @@ class CallhomeStatusReporter implements DataChangeListener, StatusRecorder, Auto
     private static final Logger LOG = LoggerFactory.getLogger(CallhomeStatusReporter.class);
 
     private final DataBroker dataBroker;
-    private final ListenerRegistration<DataChangeListener> reg;
+    private final ListenerRegistration<CallhomeStatusReporter> reg;
 
-    CallhomeStatusReporter(DataBroker broker) {
+    CallhomeStatusReporter(final DataBroker broker) {
         this.dataBroker = broker;
-        this.reg = dataBroker.registerDataChangeListener(LogicalDatastoreType.OPERATIONAL,
-            NETCONF_TOPO_IID.child(Node.class), this, AsyncDataBroker.DataChangeScope.SUBTREE);
+        this.reg = dataBroker.registerDataTreeChangeListener(DataTreeIdentifier.create(LogicalDatastoreType.OPERATIONAL,
+            NETCONF_TOPO_IID.child(Node.class)), this);
     }
 
     @Override
-    public void onDataChanged(AsyncDataChangeEvent<InstanceIdentifier<?>, DataObject> change) {
-        for (InstanceIdentifier<?> removedPath : change.getRemovedPaths()) {
-            if (removedPath.getTargetType() != NetconfNode.class) {
-                continue;
-            }
-
-            final NodeId nodeId = getNodeId(removedPath);
-            if (nodeId != null) {
-                handleDisconnectedNetconfNode(nodeId);
-                return;
+    public void onDataTreeChanged(final Collection<DataTreeModification<Node>> changes) {
+        for (DataTreeModification<Node> change: changes) {
+            final DataObjectModification<Node> rootNode = change.getRootNode();
+            final InstanceIdentifier<Node> identifier = change.getRootPath().getRootIdentifier();
+            switch (rootNode.getModificationType()) {
+                case WRITE:
+                case SUBTREE_MODIFIED:
+                    if (isNetconfNode(rootNode.getDataAfter())) {
+                        NodeId nodeId = getNodeId(identifier);
+                        if (nodeId != null) {
+                            NetconfNode nnode = rootNode.getDataAfter().augmentation(NetconfNode.class);
+                            handledNetconfNode(nodeId, nnode);
+                        }
+                    }
+                    break;
+                case DELETE:
+                    if (isNetconfNode(rootNode.getDataBefore())) {
+                        final NodeId nodeId = getNodeId(identifier);
+                        if (nodeId != null) {
+                            handleDisconnectedNetconfNode(nodeId);
+                        }
+                    }
+                    break;
+                default:
+                    break;
             }
         }
+    }
 
-        for (Map.Entry<InstanceIdentifier<?>, DataObject> entry : change.getUpdatedData().entrySet()) {
-            if (entry.getKey().getTargetType() == NetconfNode.class) {
-                NodeId nodeId = getNodeId(entry.getKey());
-                if (nodeId != null) {
-                    NetconfNode nnode = (NetconfNode) entry.getValue();
-                    handledNetconfNode(nodeId, nnode);
-                    return;
-                }
-            }
-        }
+    private static boolean isNetconfNode(final Node node) {
+        return node.augmentation(NetconfNode.class) != null;
     }
 
-    private NodeId getNodeId(final InstanceIdentifier<?> path) {
+    private static NodeId getNodeId(final InstanceIdentifier<?> path) {
         NodeKey key = path.firstKeyOf(Node.class);
         return key != null ? key.getNodeId() : null;
     }
 
-    private void handledNetconfNode(NodeId nodeId, NetconfNode nnode) {
+    private void handledNetconfNode(final NodeId nodeId, final NetconfNode nnode) {
         NetconfNodeConnectionStatus.ConnectionStatus csts = nnode.getConnectionStatus();
 
         switch (csts) {
@@ -115,7 +122,7 @@ class CallhomeStatusReporter implements DataChangeListener, StatusRecorder, Auto
         }
     }
 
-    private void handleConnectedNetconfNode(NodeId nodeId) {
+    private void handleConnectedNetconfNode(final NodeId nodeId) {
         // Fully connected, all services for remote device are
         // available from the MountPointService.
         LOG.debug("NETCONF Node: {} is fully connected", nodeId.getValue());
@@ -133,7 +140,7 @@ class CallhomeStatusReporter implements DataChangeListener, StatusRecorder, Auto
         }
     }
 
-    private void handleDisconnectedNetconfNode(NodeId nodeId) {
+    private void handleDisconnectedNetconfNode(final NodeId nodeId) {
         LOG.debug("NETCONF Node: {} disconnected", nodeId.getValue());
 
         Device opDev = readAndGetDevice(nodeId);
@@ -149,7 +156,7 @@ class CallhomeStatusReporter implements DataChangeListener, StatusRecorder, Auto
         }
     }
 
-    private void handleUnableToConnectNetconfNode(NodeId nodeId) {
+    private void handleUnableToConnectNetconfNode(final NodeId nodeId) {
         // The maximum configured number of reconnect attempts
         // have been reached. No more reconnects will be
         // attempted by the Netconf Connector.
@@ -168,19 +175,19 @@ class CallhomeStatusReporter implements DataChangeListener, StatusRecorder, Auto
         }
     }
 
-    void asForceListedDevice(String id, PublicKey serverKey) {
+    void asForceListedDevice(final String id, final PublicKey serverKey) {
         NodeId nid = new NodeId(id);
         Device device = newDevice(id, serverKey, Device1.DeviceStatus.DISCONNECTED);
         writeDevice(nid, device);
     }
 
-    void asUnlistedDevice(String id, PublicKey serverKey) {
+    void asUnlistedDevice(final String id, final PublicKey serverKey) {
         NodeId nid = new NodeId(id);
         Device device = newDevice(id, serverKey, Device1.DeviceStatus.FAILEDNOTALLOWED);
         writeDevice(nid, device);
     }
 
-    private Device newDevice(String id, PublicKey serverKey, Device1.DeviceStatus status) {
+    private static Device newDevice(final String id, final PublicKey serverKey, final Device1.DeviceStatus status) {
         String sshEncodedKey = serverKey.toString();
         try {
             sshEncodedKey = AuthorizedKeysDecoder.encodePublicKey(serverKey);
@@ -190,110 +197,108 @@ class CallhomeStatusReporter implements DataChangeListener, StatusRecorder, Auto
         Device1 d1 = new Device1Builder().setDeviceStatus(Device1.DeviceStatus.FAILEDNOTALLOWED).build();
         DeviceBuilder builder = new DeviceBuilder()
                 .setUniqueId(id)
-                .setKey(new DeviceKey(id))
+                .withKey(new DeviceKey(id))
                 .setSshHostKey(sshEncodedKey)
                 .addAugmentation(Device1.class, d1);
 
         return builder.build();
     }
 
-    private Device readAndGetDevice(NodeId nodeId) {
-        Optional<Device> opDevGet = readDevice(nodeId);
-        if (opDevGet != null) {
-            if (opDevGet.isPresent()) {
-                return opDevGet.get();
-            }
-        }
-
-        return null;
+    private Device readAndGetDevice(final NodeId nodeId) {
+        return readDevice(nodeId).orElse(null);
     }
 
-    private Optional<Device> readDevice(NodeId nodeId) {
-        ReadOnlyTransaction opTx = dataBroker.newReadOnlyTransaction();
+    private Optional<Device> readDevice(final NodeId nodeId) {
+        ReadTransaction opTx = dataBroker.newReadOnlyTransaction();
 
         InstanceIdentifier<Device> deviceIID = buildDeviceInstanceIdentifier(nodeId);
-        CheckedFuture<Optional<Device>, ReadFailedException> devFuture =
-                opTx.read(LogicalDatastoreType.OPERATIONAL, deviceIID);
-
+        ListenableFuture<Optional<Device>> devFuture = opTx.read(LogicalDatastoreType.OPERATIONAL, deviceIID);
         try {
-            return devFuture.checkedGet();
-        } catch (ReadFailedException e) {
-            return null;
+            return devFuture.get();
+        } catch (InterruptedException | ExecutionException e) {
+            return Optional.empty();
         }
     }
 
-    private void writeDevice(NodeId nodeId, Device modifiedDevice) {
-        ReadWriteTransaction opTx = dataBroker.newReadWriteTransaction();
+    private void writeDevice(final NodeId nodeId, final Device modifiedDevice) {
+        WriteTransaction opTx = dataBroker.newWriteOnlyTransaction();
         opTx.merge(LogicalDatastoreType.OPERATIONAL, buildDeviceInstanceIdentifier(nodeId), modifiedDevice);
-        opTx.submit();
+        commit(opTx, modifiedDevice.key());
     }
 
-    private InstanceIdentifier<Device> buildDeviceInstanceIdentifier(NodeId nodeId) {
+    private static InstanceIdentifier<Device> buildDeviceInstanceIdentifier(final NodeId nodeId) {
         return InstanceIdentifier.create(NetconfCallhomeServer.class)
                 .child(AllowedDevices.class)
                 .child(Device.class, new DeviceKey(nodeId.getValue()));
     }
 
-    private Device withConnectedStatus(Device opDev) {
+    private static Device withConnectedStatus(final Device opDev) {
         Device1 status = new Device1Builder().setDeviceStatus(Device1.DeviceStatus.CONNECTED).build();
         return new DeviceBuilder().addAugmentation(Device1.class, status).setUniqueId(opDev.getUniqueId())
                 .setSshHostKey(opDev.getSshHostKey()).build();
     }
 
-    private Device withFailedStatus(Device opDev) {
+    private static Device withFailedStatus(final Device opDev) {
         Device1 status = new Device1Builder().setDeviceStatus(Device1.DeviceStatus.FAILED).build();
         return new DeviceBuilder().addAugmentation(Device1.class, status).setUniqueId(opDev.getUniqueId())
                 .setSshHostKey(opDev.getSshHostKey()).build();
     }
 
-    private Device withDisconnectedStatus(Device opDev) {
+    private static Device withDisconnectedStatus(final Device opDev) {
         Device1 status = new Device1Builder().setDeviceStatus(Device1.DeviceStatus.DISCONNECTED).build();
         return new DeviceBuilder().addAugmentation(Device1.class, status).setUniqueId(opDev.getUniqueId())
                 .setSshHostKey(opDev.getSshHostKey()).build();
     }
 
-    private Device withFailedAuthStatus(Device opDev) {
+    private static Device withFailedAuthStatus(final Device opDev) {
         Device1 status = new Device1Builder().setDeviceStatus(Device1.DeviceStatus.FAILEDAUTHFAILURE).build();
         return new DeviceBuilder().addAugmentation(Device1.class, status).setUniqueId(opDev.getUniqueId())
                 .setSshHostKey(opDev.getSshHostKey()).build();
     }
 
-    private void setDeviceStatus(Device device) {
+    private void setDeviceStatus(final Device device) {
         WriteTransaction tx = dataBroker.newWriteOnlyTransaction();
-        InstanceIdentifier<Device> deviceIId =
-                InstanceIdentifier.create(NetconfCallhomeServer.class)
+        InstanceIdentifier<Device> deviceIId = InstanceIdentifier.create(NetconfCallhomeServer.class)
                         .child(AllowedDevices.class)
-                        .child(Device.class, device.getKey());
+                        .child(Device.class, device.key());
 
         tx.merge(LogicalDatastoreType.OPERATIONAL, deviceIId, device);
-        tx.submit();
+        commit(tx, device.key());
+    }
+
+    private static void commit(final WriteTransaction tx, final DeviceKey device) {
+        tx.commit().addCallback(new FutureCallback<CommitInfo>() {
+            @Override
+            public void onSuccess(final CommitInfo result) {
+                LOG.debug("Device {} committed", device);
+            }
+
+            @Override
+            public void onFailure(final Throwable cause) {
+                LOG.warn("Failed to commit device {}", device, cause);
+            }
+        }, MoreExecutors.directExecutor());
     }
 
     private AllowedDevices getDevices() {
-        ReadOnlyTransaction rxTransaction = dataBroker.newReadOnlyTransaction();
-        CheckedFuture<Optional<AllowedDevices>, ReadFailedException> devicesFuture =
+        ReadTransaction rxTransaction = dataBroker.newReadOnlyTransaction();
+        ListenableFuture<Optional<AllowedDevices>> devicesFuture =
                 rxTransaction.read(LogicalDatastoreType.OPERATIONAL, IetfZeroTouchCallHomeServerProvider.ALL_DEVICES);
-
         try {
-            Optional<AllowedDevices> opt = devicesFuture.checkedGet();
-            if (opt.isPresent()) {
-                AllowedDevices devices = opt.get();
-                return devices;
-            }
-        } catch (ReadFailedException e) {
-            LOG.error("Error trying to read the whitelist devices: {}", e);
+            return devicesFuture.get().orElse(null);
+        } catch (ExecutionException | InterruptedException e) {
+            LOG.error("Error trying to read the whitelist devices", e);
+            return null;
         }
-
-        return null;
     }
 
     private List<Device> getDevicesAsList() {
         AllowedDevices devices = getDevices();
-        return (devices == null) ? new ArrayList<Device>() : devices.getDevice();
+        return devices == null ? new ArrayList<>() : devices.getDevice();
     }
 
     @Override
-    public void reportFailedAuth(PublicKey sshKey) {
+    public void reportFailedAuth(final PublicKey sshKey) {
         AuthorizedKeysDecoder decoder = new AuthorizedKeysDecoder();
 
         for (Device device : getDevicesAsList()) {
@@ -310,8 +315,8 @@ class CallhomeStatusReporter implements DataChangeListener, StatusRecorder, Auto
                     setDeviceStatus(failedDevice);
                     return;
                 }
-            } catch (InvalidKeySpecException | NoSuchAlgorithmException | NoSuchProviderException e) {
-                LOG.error("Failed decoding a device key with host key: {} {}", keyString, e);
+            } catch (GeneralSecurityException e) {
+                LOG.error("Failed decoding a device key with host key: {}", keyString, e);
                 return;
             }
         }
@@ -321,7 +326,7 @@ class CallhomeStatusReporter implements DataChangeListener, StatusRecorder, Auto
     }
 
     @Override
-    public void close() throws Exception {
+    public void close() {
         reg.close();
     }
 }