[ONOS-2159]Add to query devices by type api in DeviceService and
DeviceStore interfaces

Change-Id: Ifa7e94e08eb150fb4d71248a50a390832d1549df
diff --git a/core/api/src/main/java/org/onosproject/net/device/DeviceService.java b/core/api/src/main/java/org/onosproject/net/device/DeviceService.java
index 5ce4d16..ab6dba5 100644
--- a/core/api/src/main/java/org/onosproject/net/device/DeviceService.java
+++ b/core/api/src/main/java/org/onosproject/net/device/DeviceService.java
@@ -44,6 +44,15 @@
     Iterable<Device> getDevices();
 
     /**
+     * Returns a collection of the currently known infrastructure
+     * devices by device type.
+     *
+     * @param type device type
+     * @return collection of devices
+     */
+    Iterable<Device> getDevices(Device.Type type);
+
+    /**
      * Returns an iterable collection of all devices
      * currently available to the system.
      *
@@ -52,6 +61,14 @@
     Iterable<Device> getAvailableDevices();
 
     /**
+     * Returns an iterable collection of all devices currently available to the system by device type.
+     *
+     * @param type device type
+     * @return device collection
+     */
+    Iterable<Device> getAvailableDevices(Device.Type type);
+
+    /**
      * Returns the device with the specified identifier.
      *
      * @param deviceId device identifier
diff --git a/core/api/src/test/java/org/onosproject/net/device/DeviceServiceAdapter.java b/core/api/src/test/java/org/onosproject/net/device/DeviceServiceAdapter.java
index 88c2f94..539fd5f 100644
--- a/core/api/src/test/java/org/onosproject/net/device/DeviceServiceAdapter.java
+++ b/core/api/src/test/java/org/onosproject/net/device/DeviceServiceAdapter.java
@@ -19,6 +19,7 @@
 import com.google.common.collect.FluentIterable;
 
 import org.onosproject.net.Device;
+import org.onosproject.net.Device.Type;
 import org.onosproject.net.DeviceId;
 import org.onosproject.net.MastershipRole;
 import org.onosproject.net.Port;
@@ -91,4 +92,14 @@
     public void removeListener(DeviceListener listener) {
     }
 
+    @Override
+    public Iterable<Device> getDevices(Type type) {
+        return Collections.emptyList();
+    }
+
+    @Override
+    public Iterable<Device> getAvailableDevices(Type type) {
+        return Collections.emptyList();
+    }
+
 }
diff --git a/core/net/src/main/java/org/onosproject/net/device/impl/DeviceManager.java b/core/net/src/main/java/org/onosproject/net/device/impl/DeviceManager.java
index dfd8f29..c0ee516 100644
--- a/core/net/src/main/java/org/onosproject/net/device/impl/DeviceManager.java
+++ b/core/net/src/main/java/org/onosproject/net/device/impl/DeviceManager.java
@@ -15,7 +15,25 @@
  */
 package org.onosproject.net.device.impl;
 
-import com.google.common.collect.Lists;
+import static com.google.common.base.Preconditions.checkNotNull;
+import static java.util.concurrent.Executors.newSingleThreadScheduledExecutor;
+import static org.onlab.util.Tools.groupedThreads;
+import static org.onosproject.net.MastershipRole.MASTER;
+import static org.onosproject.net.MastershipRole.NONE;
+import static org.onosproject.net.MastershipRole.STANDBY;
+import static org.onosproject.security.AppGuard.checkPermission;
+import static org.slf4j.LoggerFactory.getLogger;
+
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Objects;
+import java.util.Set;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.TimeUnit;
+
 import org.apache.felix.scr.annotations.Activate;
 import org.apache.felix.scr.annotations.Component;
 import org.apache.felix.scr.annotations.Deactivate;
@@ -25,14 +43,15 @@
 import org.onosproject.cluster.ClusterService;
 import org.onosproject.cluster.NodeId;
 import org.onosproject.core.Permission;
-import org.onosproject.event.ListenerRegistry;
 import org.onosproject.event.EventDeliveryService;
+import org.onosproject.event.ListenerRegistry;
 import org.onosproject.mastership.MastershipEvent;
 import org.onosproject.mastership.MastershipListener;
 import org.onosproject.mastership.MastershipService;
 import org.onosproject.mastership.MastershipTerm;
 import org.onosproject.mastership.MastershipTermService;
 import org.onosproject.net.Device;
+import org.onosproject.net.Device.Type;
 import org.onosproject.net.DeviceId;
 import org.onosproject.net.MastershipRole;
 import org.onosproject.net.Port;
@@ -56,21 +75,7 @@
 import org.onosproject.net.provider.AbstractProviderService;
 import org.slf4j.Logger;
 
-import java.util.Collection;
-import java.util.List;
-import java.util.Objects;
-import java.util.concurrent.CompletableFuture;
-import java.util.concurrent.ExecutionException;
-import java.util.concurrent.ScheduledExecutorService;
-import java.util.concurrent.TimeUnit;
-
-import static com.google.common.base.Preconditions.checkNotNull;
-import static java.util.concurrent.Executors.newSingleThreadScheduledExecutor;
-import static org.onlab.util.Tools.groupedThreads;
-import static org.onosproject.net.MastershipRole.*;
-import static org.slf4j.LoggerFactory.getLogger;
-import static org.onosproject.security.AppGuard.checkPermission;
-
+import com.google.common.collect.Lists;
 
 /**
  * Provides implementation of the device SB &amp; NB APIs.
@@ -88,8 +93,7 @@
 
     private final Logger log = getLogger(getClass());
 
-    protected final ListenerRegistry<DeviceEvent, DeviceListener> listenerRegistry =
-            new ListenerRegistry<>();
+    protected final ListenerRegistry<DeviceEvent, DeviceListener> listenerRegistry = new ListenerRegistry<>();
 
     private final DeviceStoreDelegate delegate = new InternalStoreDelegate();
 
@@ -118,7 +122,8 @@
 
     @Activate
     public void activate() {
-        backgroundService = newSingleThreadScheduledExecutor(groupedThreads("onos/device", "manager-background"));
+        backgroundService = newSingleThreadScheduledExecutor(groupedThreads("onos/device",
+                                                                            "manager-background"));
         localNodeId = clusterService.getLocalNode().id();
 
         store.setDelegate(delegate);
@@ -258,8 +263,7 @@
     }
 
     @Override
-    protected DeviceProviderService createProviderService(
-            DeviceProvider provider) {
+    protected DeviceProviderService createProviderService(DeviceProvider provider) {
         return new InternalDeviceProviderService(provider);
     }
 
@@ -280,7 +284,8 @@
                 continue;
             }
 
-            log.info("{} is reachable but did not have a valid role, reasserting", deviceId);
+            log.info("{} is reachable but did not have a valid role, reasserting",
+                     deviceId);
 
             // isReachable but was not MASTER or STANDBY, get a role and apply
             // Note: NONE triggers request to MastershipService
@@ -300,20 +305,21 @@
         /**
          * Apply role in reaction to provider event.
          *
-         * @param deviceId  device identifier
-         * @param newRole   new role to apply to the device
+         * @param deviceId device identifier
+         * @param newRole new role to apply to the device
          * @return true if the request was sent to provider
          */
         private boolean applyRole(DeviceId deviceId, MastershipRole newRole) {
 
             if (newRole.equals(MastershipRole.NONE)) {
-                //no-op
+                // no-op
                 return true;
             }
 
             DeviceProvider provider = provider();
             if (provider == null) {
-                log.warn("Provider for {} was not found. Cannot apply role {}", deviceId, newRole);
+                log.warn("Provider for {} was not found. Cannot apply role {}",
+                         deviceId, newRole);
                 return false;
             }
             provider.roleChanged(deviceId, newRole);
@@ -322,7 +328,6 @@
             return true;
         }
 
-
         @Override
         public void deviceConnected(DeviceId deviceId,
                                     DeviceDescription deviceDescription) {
@@ -332,14 +337,16 @@
 
             log.info("Device {} connected", deviceId);
             // check my Role
-            CompletableFuture<MastershipRole> role = mastershipService.requestRoleFor(deviceId);
+            CompletableFuture<MastershipRole> role = mastershipService
+                    .requestRoleFor(deviceId);
             try {
                 // Device subsystem must wait for role assignment
                 // to avoid losing Device information.
                 // (This node could be the only Node connected to the Device.)
                 role.get();
             } catch (InterruptedException e) {
-                log.warn("Interrupted while waiting role-assignment for {}", deviceId);
+                log.warn("Interrupted while waiting role-assignment for {}",
+                         deviceId);
                 Thread.currentThread().interrupt();
             } catch (ExecutionException e) {
                 log.error("Exception thrown while waiting role-assignment for {}",
@@ -358,7 +365,8 @@
             }
 
             DeviceEvent event = store.createOrUpdateDevice(provider().id(),
-                                                           deviceId, deviceDescription);
+                                                           deviceId,
+                                                           deviceDescription);
 
             if (event != null) {
                 log.trace("event: {} {}", event.type(), event);
@@ -375,10 +383,8 @@
 
             List<Port> ports = store.getPorts(deviceId);
             List<PortDescription> descs = Lists.newArrayList();
-            ports.forEach(port ->
-                descs.add(new DefaultPortDescription(port.number(),
-                                                     false, port.type(),
-                                                     port.portSpeed())));
+            ports.forEach(port -> descs.add(new DefaultPortDescription(port
+                    .number(), false, port.type(), port.portSpeed())));
             store.updatePorts(this.provider().id(), deviceId, descs);
             try {
                 if (mastershipService.getLocalRole(deviceId) == MASTER) {
@@ -387,37 +393,49 @@
             } catch (IllegalStateException e) {
                 log.warn("Failed to mark {} offline", deviceId);
                 // only the MASTER should be marking off-line in normal cases,
-                // but if I was the last STANDBY connection, etc. and no one else
-                // was there to mark the device offline, this instance may need to
+                // but if I was the last STANDBY connection, etc. and no one
+                // else
+                // was there to mark the device offline, this instance may need
+                // to
                 // temporarily request for Master Role and mark offline.
 
-                //there are times when this node will correctly have mastership, BUT
-                //that isn't reflected in the ClockManager before the device disconnects.
-                //we want to let go of the device anyways, so make sure this happens.
+                // there are times when this node will correctly have
+                // mastership, BUT
+                // that isn't reflected in the ClockManager before the device
+                // disconnects.
+                // we want to let go of the device anyways, so make sure this
+                // happens.
 
                 // FIXME: Store semantics leaking out as IllegalStateException.
-                //  Consider revising store API to handle this scenario.
-                CompletableFuture<MastershipRole> roleFuture = mastershipService.requestRoleFor(deviceId);
+                // Consider revising store API to handle this scenario.
+                CompletableFuture<MastershipRole> roleFuture = mastershipService
+                        .requestRoleFor(deviceId);
                 roleFuture.whenComplete((role, error) -> {
-                    MastershipTerm term = termService.getMastershipTerm(deviceId);
-                    // TODO: Move this type of check inside device clock manager, etc.
-                    if (term != null && localNodeId.equals(term.master())) {
-                        log.info("Retry marking {} offline", deviceId);
-                        deviceClockProviderService.setMastershipTerm(deviceId, term);
-                        post(store.markOffline(deviceId));
-                    } else {
-                        log.info("Failed again marking {} offline. {}", deviceId, role);
-                    }
-                });
+                    MastershipTerm term = termService
+                            .getMastershipTerm(deviceId);
+                    // TODO: Move this type of check inside device clock
+                    // manager, etc.
+                        if (term != null && localNodeId.equals(term.master())) {
+                            log.info("Retry marking {} offline", deviceId);
+                            deviceClockProviderService
+                                    .setMastershipTerm(deviceId, term);
+                            post(store.markOffline(deviceId));
+                        } else {
+                            log.info("Failed again marking {} offline. {}",
+                                     deviceId, role);
+                        }
+                    });
             } finally {
                 try {
-                    //relinquish master role and ability to be backup.
+                    // relinquish master role and ability to be backup.
                     mastershipService.relinquishMastership(deviceId).get();
                 } catch (InterruptedException e) {
-                    log.warn("Interrupted while reliquishing role for {}", deviceId);
+                    log.warn("Interrupted while reliquishing role for {}",
+                             deviceId);
                     Thread.currentThread().interrupt();
                 } catch (ExecutionException e) {
-                    log.error("Exception thrown while relinquishing role for {}", deviceId, e);
+                    log.error("Exception thrown while relinquishing role for {}",
+                              deviceId, e);
                 }
             }
         }
@@ -432,12 +450,14 @@
             if (!deviceClockProviderService.isTimestampAvailable(deviceId)) {
                 // Never been a master for this device
                 // any update will be ignored.
-                log.trace("Ignoring {} port updates on standby node. {}", deviceId, portDescriptions);
+                log.trace("Ignoring {} port updates on standby node. {}",
+                          deviceId, portDescriptions);
                 return;
             }
 
             List<DeviceEvent> events = store.updatePorts(this.provider().id(),
-                                                         deviceId, portDescriptions);
+                                                         deviceId,
+                                                         portDescriptions);
             for (DeviceEvent event : events) {
                 post(event);
             }
@@ -453,12 +473,13 @@
             if (!deviceClockProviderService.isTimestampAvailable(deviceId)) {
                 // Never been a master for this device
                 // any update will be ignored.
-                log.trace("Ignoring {} port update on standby node. {}", deviceId, portDescription);
+                log.trace("Ignoring {} port update on standby node. {}",
+                          deviceId, portDescription);
                 return;
             }
 
-            final DeviceEvent event = store.updatePortStatus(this.provider().id(),
-                                                             deviceId, portDescription);
+            final DeviceEvent event = store.updatePortStatus(this.provider()
+                    .id(), deviceId, portDescription);
             if (event != null) {
                 log.info("Device {} port {} status changed", deviceId, event
                         .port().number());
@@ -467,7 +488,8 @@
         }
 
         @Override
-        public void receivedRoleReply(DeviceId deviceId, MastershipRole requested,
+        public void receivedRoleReply(DeviceId deviceId,
+                                      MastershipRole requested,
                                       MastershipRole response) {
             // Several things can happen here:
             // 1. request and response match
@@ -480,43 +502,50 @@
             // FIXME: implement response to this notification
 
             log.debug("got reply to a role request for {}: asked for {}, and got {}",
-                     deviceId, requested, response);
+                      deviceId, requested, response);
 
             if (requested == null && response == null) {
-                // something was off with DeviceProvider, maybe check channel too?
-                log.warn("Failed to assert role [{}] onto Device {}", requested, deviceId);
+                // something was off with DeviceProvider, maybe check channel
+                // too?
+                log.warn("Failed to assert role [{}] onto Device {}",
+                         requested, deviceId);
                 mastershipService.relinquishMastership(deviceId);
                 return;
             }
 
             if (Objects.equals(requested, response)) {
-                if (Objects.equals(requested, mastershipService.getLocalRole(deviceId))) {
+                if (Objects.equals(requested,
+                                   mastershipService.getLocalRole(deviceId))) {
                     return;
                 } else {
                     return;
-                    // FIXME roleManager got the device to comply, but doesn't agree with
+                    // FIXME roleManager got the device to comply, but doesn't
+                    // agree with
                     // the store; use the store's view, then try to reassert.
                 }
             } else {
                 // we didn't get back what we asked for. Reelect someone else.
-                log.warn("Failed to assert role [{}] onto Device {}", response, deviceId);
+                log.warn("Failed to assert role [{}] onto Device {}", response,
+                         deviceId);
                 if (response == MastershipRole.MASTER) {
                     mastershipService.relinquishMastership(deviceId);
                     // TODO: Shouldn't we be triggering event?
-                    //final Device device = getDevice(deviceId);
-                    //post(new DeviceEvent(DEVICE_MASTERSHIP_CHANGED, device));
+                    // final Device device = getDevice(deviceId);
+                    // post(new DeviceEvent(DEVICE_MASTERSHIP_CHANGED, device));
                 }
             }
         }
 
         @Override
-        public void updatePortStatistics(DeviceId deviceId, Collection<PortStatistics> portStatistics) {
+        public void updatePortStatistics(DeviceId deviceId,
+                                         Collection<PortStatistics> portStatistics) {
             checkNotNull(deviceId, DEVICE_ID_NULL);
             checkNotNull(portStatistics, "Port statistics list cannot be null");
             checkValidity();
 
-            DeviceEvent event = store.updatePortStatistics(this.provider().id(),
-                                                           deviceId, portStatistics);
+            DeviceEvent event = store
+                    .updatePortStatistics(this.provider().id(), deviceId,
+                                          portStatistics);
             post(event);
         }
     }
@@ -532,19 +561,20 @@
     /**
      * Apply role to device and send probe if MASTER.
      *
-     * @param deviceId  device identifier
-     * @param newRole   new role to apply to the device
+     * @param deviceId device identifier
+     * @param newRole new role to apply to the device
      * @return true if the request was sent to provider
      */
     private boolean applyRoleAndProbe(DeviceId deviceId, MastershipRole newRole) {
         if (newRole.equals(MastershipRole.NONE)) {
-            //no-op
+            // no-op
             return true;
         }
 
         DeviceProvider provider = getProvider(deviceId);
         if (provider == null) {
-            log.warn("Provider for {} was not found. Cannot apply role {}", deviceId, newRole);
+            log.warn("Provider for {} was not found. Cannot apply role {}",
+                     deviceId, newRole);
             return false;
         }
         provider.roleChanged(deviceId, newRole);
@@ -559,12 +589,11 @@
     /**
      * Reaasert role for specified device connected to this node.
      *
-     * @param did         device identifier
-     * @param nextRole    role to apply. If NONE is specified,
-     *        it will ask mastership service for a role and apply it.
+     * @param did device identifier
+     * @param nextRole role to apply. If NONE is specified, it will ask
+     *            mastership service for a role and apply it.
      */
-    private void reassertRole(final DeviceId did,
-                              final MastershipRole nextRole) {
+    private void reassertRole(final DeviceId did, final MastershipRole nextRole) {
 
         MastershipRole myNextRole = nextRole;
         if (myNextRole == NONE) {
@@ -581,18 +610,17 @@
         case MASTER:
             final Device device = getDevice(did);
             if ((device != null) && !isAvailable(did)) {
-                //flag the device as online. Is there a better way to do this?
-                DefaultDeviceDescription deviceDescription
-                    = new DefaultDeviceDescription(did.uri(),
-                                                   device.type(),
-                                                   device.manufacturer(),
-                                                   device.hwVersion(),
-                                                   device.swVersion(),
-                                                   device.serialNumber(),
-                                                   device.chassisId());
-                DeviceEvent devEvent =
-                        store.createOrUpdateDevice(device.providerId(), did,
-                                                   deviceDescription);
+                // flag the device as online. Is there a better way to do this?
+                DefaultDeviceDescription deviceDescription = new DefaultDeviceDescription(
+                                                                                          did.uri(),
+                                                                                          device.type(),
+                                                                                          device.manufacturer(),
+                                                                                          device.hwVersion(),
+                                                                                          device.swVersion(),
+                                                                                          device.serialNumber(),
+                                                                                          device.chassisId());
+                DeviceEvent devEvent = store.createOrUpdateDevice(device
+                        .providerId(), did, deviceDescription);
                 post(devEvent);
             }
             // TODO: should apply role only if there is mismatch
@@ -634,7 +662,8 @@
         if (localNodeId.equals(event.roleInfo().master())) {
             // confirm latest info
             MastershipTerm term = termService.getMastershipTerm(did);
-            final boolean iHaveControl = term != null && localNodeId.equals(term.master());
+            final boolean iHaveControl = term != null
+                    && localNodeId.equals(term.master());
             if (iHaveControl) {
                 deviceClockProviderService.setMastershipTerm(did, term);
                 myNextRole = MASTER;
@@ -647,15 +676,13 @@
             myNextRole = NONE;
         }
 
-
         final boolean isReachable = isReachable(did);
         if (!isReachable) {
             // device is not connected to this node
             if (myNextRole != NONE) {
                 log.warn("Node was instructed to be {} role for {}, "
                         + "but this node cannot reach the device.  "
-                        + "Relinquishing role.  ",
-                         myNextRole, did);
+                        + "Relinquishing role.  ", myNextRole, did);
                 mastershipService.relinquishMastership(did);
             }
             return;
@@ -691,4 +718,34 @@
             post(event);
         }
     }
+
+    @Override
+    public Iterable<Device> getDevices(Type type) {
+        checkPermission(Permission.DEVICE_READ);
+        Set<Device> results = new HashSet<>();
+        Iterable<Device> devices = store.getDevices();
+        if (devices != null) {
+            devices.forEach(d -> {
+                if (type.equals(d.type())) {
+                    results.add(d);
+                }
+            });
+        }
+        return results;
+    }
+
+    @Override
+    public Iterable<Device> getAvailableDevices(Type type) {
+        checkPermission(Permission.DEVICE_READ);
+        Set<Device> results = new HashSet<>();
+        Iterable<Device> availableDevices = store.getAvailableDevices();
+        if (availableDevices != null) {
+            availableDevices.forEach(d -> {
+                if (type.equals(d.type())) {
+                    results.add(d);
+                }
+            });
+        }
+        return results;
+    }
 }