netconf provider basic unitest and fix ONOS-5532

Change-Id: I31f31ae5bea580d0cd5ee05bf88339002ea741fc
diff --git a/core/api/src/test/java/org/onosproject/net/key/DeviceKeyAdminServiceAdapter.java b/core/api/src/test/java/org/onosproject/net/key/DeviceKeyAdminServiceAdapter.java
new file mode 100644
index 0000000..c63f6ff
--- /dev/null
+++ b/core/api/src/test/java/org/onosproject/net/key/DeviceKeyAdminServiceAdapter.java
@@ -0,0 +1,52 @@
+/*
+ * 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.net.key;
+
+import java.util.Collection;
+import java.util.Collections;
+
+/**
+ * Test Adapter for DeviceKeyAdminService API.
+ */
+public class DeviceKeyAdminServiceAdapter implements DeviceKeyAdminService {
+
+    @Override
+    public void addListener(DeviceKeyListener listener) {
+    }
+
+    @Override
+    public void removeListener(DeviceKeyListener listener) {
+    }
+
+    @Override
+    public void addKey(DeviceKey deviceKey) {
+    }
+
+    @Override
+    public void removeKey(DeviceKeyId id) {
+    }
+
+    @Override
+    public Collection<DeviceKey> getDeviceKeys() {
+        return Collections.emptyList();
+    }
+
+    @Override
+    public DeviceKey getDeviceKey(DeviceKeyId deviceKeyId) {
+        return null;
+    }
+}
diff --git a/providers/netconf/device/BUCK b/providers/netconf/device/BUCK
index c8d3fb5..2e462ff 100644
--- a/providers/netconf/device/BUCK
+++ b/providers/netconf/device/BUCK
@@ -4,6 +4,11 @@
     '//protocols/netconf/api:onos-protocols-netconf-api',
 ]
 
+TEST_DEPS = [
+    '//lib:TEST_ADAPTERS',
+]
+
 osgi_jar_with_tests (
     deps = COMPILE_DEPS,
+    test_deps = TEST_DEPS,
 )
diff --git a/providers/netconf/device/pom.xml b/providers/netconf/device/pom.xml
index 7d2856a..baed8d5 100644
--- a/providers/netconf/device/pom.xml
+++ b/providers/netconf/device/pom.xml
@@ -46,6 +46,11 @@
             <artifactId>onos-netconf-ctl</artifactId>
             <version>${project.version}</version>
         </dependency>
+        <dependency>
+            <groupId>org.easymock</groupId>
+            <artifactId>easymock</artifactId>
+            <scope>test</scope>
+        </dependency>
     </dependencies>
 
     <build>
diff --git a/providers/netconf/device/src/main/java/org/onosproject/provider/netconf/device/impl/NetconfDeviceProvider.java b/providers/netconf/device/src/main/java/org/onosproject/provider/netconf/device/impl/NetconfDeviceProvider.java
index 96dd14f..ffef6dd 100644
--- a/providers/netconf/device/src/main/java/org/onosproject/provider/netconf/device/impl/NetconfDeviceProvider.java
+++ b/providers/netconf/device/src/main/java/org/onosproject/provider/netconf/device/impl/NetconfDeviceProvider.java
@@ -24,8 +24,6 @@
 import org.apache.felix.scr.annotations.Reference;
 import org.apache.felix.scr.annotations.ReferenceCardinality;
 import org.onlab.packet.ChassisId;
-import org.onosproject.cluster.ClusterService;
-import org.onosproject.cluster.NodeId;
 import org.onosproject.core.ApplicationId;
 import org.onosproject.core.CoreService;
 import org.onosproject.incubator.net.config.basics.ConfigException;
@@ -84,7 +82,6 @@
 public class NetconfDeviceProvider extends AbstractProvider
         implements DeviceProvider {
 
-    public static final String ACTIVE = "active";
     private final Logger log = getLogger(getClass());
 
     @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
@@ -108,10 +105,7 @@
     @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
     protected MastershipService mastershipService;
 
-    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
-    protected ClusterService clusterService;
-
-    private static final String APP_NAME = "org.onosproject.netconf";
+    protected static final String APP_NAME = "org.onosproject.netconf";
     private static final String SCHEME_NAME = "netconf";
     private static final String DEVICE_PROVIDER_PACKAGE = "org.onosproject.netconf.provider.device";
     private static final String UNKNOWN = "unknown";
@@ -124,7 +118,7 @@
     private static final int ISREACHABLE_TIMEOUT = 2000;
     private static final int DEFAULT_POLL_FREQUENCY_SECONDS = 30;
 
-    private final ExecutorService executor =
+    protected final ExecutorService executor =
             Executors.newFixedThreadPool(5, groupedThreads("onos/netconfdeviceprovider",
                                                            "device-installer-%d", log));
     protected ScheduledExecutorService connectionExecutor
@@ -132,11 +126,10 @@
                                      groupedThreads("onos/netconfdeviceprovider",
                                                     "connection-executor-%d", log));
 
-    private DeviceProviderService providerService;
+    protected DeviceProviderService providerService;
     private NetconfDeviceListener innerNodeListener = new InnerNetconfDeviceListener();
     private InternalDeviceListener deviceListener = new InternalDeviceListener();
-    private NodeId localNodeId;
-    private ScheduledFuture<?> scheduledTask;
+    protected ScheduledFuture<?> scheduledTask;
 
     private final ConfigFactory factory =
             new ConfigFactory<ApplicationId, NetconfProviderConfig>(APP_SUBJECT_FACTORY,
@@ -148,7 +141,7 @@
                     return new NetconfProviderConfig();
                 }
             };
-    private final NetworkConfigListener cfgListener = new InternalNetworkConfigListener();
+    protected final NetworkConfigListener cfgListener = new InternalNetworkConfigListener();
     private ApplicationId appId;
     private boolean active;
 
@@ -163,7 +156,6 @@
         controller.addDeviceListener(innerNodeListener);
         deviceService.addListener(deviceListener);
         executor.execute(NetconfDeviceProvider.this::connectDevices);
-        localNodeId = clusterService.getLocalNode().id();
         scheduledTask = schedulePolling();
         log.info("Started");
     }
@@ -359,6 +351,10 @@
                             providerService.deviceConnected(
                                     deviceId, new DefaultDeviceDescription(
                                             updatedDeviceDescription, true, updatedDeviceDescription.annotations()));
+                        } else if (updatedDeviceDescription == null) {
+                            providerService.deviceConnected(
+                                    deviceId, new DefaultDeviceDescription(
+                                            deviceDescription, true, deviceDescription.annotations()));
                         }
                         //if ports are not discovered, retry the discovery
                         if (deviceService.getPorts(deviceId).isEmpty()) {
@@ -366,7 +362,11 @@
                         }
                     }
                 } else {
-                    log.warn("No DeviceDescriptionDiscovery behaviour for device {}", deviceId);
+                    log.warn("No DeviceDescriptionDiscovery behaviour for device {} " +
+                                     "using DefaultDeviceDescription", deviceId);
+                            providerService.deviceConnected(
+                                    deviceId, new DefaultDeviceDescription(
+                                    deviceDescription, true, deviceDescription.annotations()));
                 }
             } else if (!isReachable && deviceService.isAvailable(deviceId)) {
                 providerService.deviceDisconnected(deviceId);
@@ -511,7 +511,7 @@
             }
             return event.subject().annotations().value(AnnotationKeys.PROTOCOL)
                     .equals(SCHEME_NAME.toUpperCase()) &&
-                    mastershipService.getMasterFor(event.subject().id()).equals(localNodeId);
+                    mastershipService.isLocalMaster(event.subject().id());
         }
     }
 }
diff --git a/providers/netconf/device/src/test/java/org/onosproject/provider/netconf/device/impl/NetconfControllerAdapter.java b/providers/netconf/device/src/test/java/org/onosproject/provider/netconf/device/impl/NetconfControllerAdapter.java
new file mode 100644
index 0000000..af556cf
--- /dev/null
+++ b/providers/netconf/device/src/test/java/org/onosproject/provider/netconf/device/impl/NetconfControllerAdapter.java
@@ -0,0 +1,78 @@
+/*
+ * 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.provider.netconf.device.impl;
+
+import org.onlab.packet.IpAddress;
+import org.onosproject.net.DeviceId;
+import org.onosproject.netconf.NetconfController;
+import org.onosproject.netconf.NetconfDevice;
+import org.onosproject.netconf.NetconfDeviceListener;
+import org.onosproject.netconf.NetconfException;
+
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
+
+/**
+ * Test Adapter for NetconfControllerAdapter API.
+ */
+public class NetconfControllerAdapter implements NetconfController {
+
+    private Map<DeviceId, NetconfDevice> netconfDeviceMap = new ConcurrentHashMap<>();
+
+    @Override
+    public void addDeviceListener(NetconfDeviceListener listener) {
+    }
+
+    @Override
+    public void removeDeviceListener(NetconfDeviceListener listener) {
+    }
+
+    @Override
+    public NetconfDevice connectDevice(DeviceId deviceId) throws NetconfException {
+        return null;
+    }
+
+    @Override
+    public void disconnectDevice(DeviceId deviceId, boolean remove) {
+    }
+
+    @Override
+    public void removeDevice(DeviceId deviceId) {
+
+    }
+
+    @Override
+    public Map<DeviceId, NetconfDevice> getDevicesMap() {
+        return netconfDeviceMap;
+    }
+
+    @Override
+    public Set<DeviceId> getNetconfDevices() {
+        return netconfDeviceMap.keySet();
+    }
+
+    @Override
+    public NetconfDevice getNetconfDevice(DeviceId deviceInfo) {
+        return netconfDeviceMap.get(deviceInfo);
+    }
+
+    @Override
+    public NetconfDevice getNetconfDevice(IpAddress ip, int port) {
+        return null;
+    }
+}
diff --git a/providers/netconf/device/src/test/java/org/onosproject/provider/netconf/device/impl/NetconfDeviceProviderTest.java b/providers/netconf/device/src/test/java/org/onosproject/provider/netconf/device/impl/NetconfDeviceProviderTest.java
new file mode 100644
index 0000000..27a6961
--- /dev/null
+++ b/providers/netconf/device/src/test/java/org/onosproject/provider/netconf/device/impl/NetconfDeviceProviderTest.java
@@ -0,0 +1,362 @@
+/*
+ * 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.provider.netconf.device.impl;
+
+import com.google.common.collect.ImmutableSet;
+import org.junit.Before;
+import org.junit.Test;
+import org.onlab.packet.ChassisId;
+import org.onlab.packet.IpAddress;
+import org.onosproject.core.ApplicationId;
+import org.onosproject.core.CoreService;
+import org.onosproject.core.DefaultApplicationId;
+import org.onosproject.incubator.net.config.basics.ConfigException;
+import org.onosproject.mastership.MastershipService;
+import org.onosproject.mastership.MastershipServiceAdapter;
+import org.onosproject.net.AbstractProjectableModel;
+import org.onosproject.net.Annotations;
+import org.onosproject.net.DefaultDevice;
+import org.onosproject.net.Device;
+import org.onosproject.net.DeviceId;
+import org.onosproject.net.config.Config;
+import org.onosproject.net.config.ConfigFactory;
+import org.onosproject.net.config.NetworkConfigEvent;
+import org.onosproject.net.config.NetworkConfigListener;
+import org.onosproject.net.config.NetworkConfigRegistry;
+import org.onosproject.net.config.NetworkConfigRegistryAdapter;
+import org.onosproject.net.config.basics.BasicDeviceConfig;
+import org.onosproject.net.device.DeviceDescription;
+import org.onosproject.net.device.DeviceDescriptionDiscovery;
+import org.onosproject.net.device.DeviceEvent;
+import org.onosproject.net.device.DeviceListener;
+import org.onosproject.net.device.DeviceProvider;
+import org.onosproject.net.device.DeviceProviderRegistry;
+import org.onosproject.net.device.DeviceProviderRegistryAdapter;
+import org.onosproject.net.device.DeviceProviderService;
+import org.onosproject.net.device.DeviceProviderServiceAdapter;
+import org.onosproject.net.device.DeviceService;
+import org.onosproject.net.device.DeviceServiceAdapter;
+import org.onosproject.net.device.DeviceStore;
+import org.onosproject.net.device.DeviceStoreAdapter;
+import org.onosproject.net.device.PortDescription;
+import org.onosproject.net.driver.AbstractHandlerBehaviour;
+import org.onosproject.net.driver.Behaviour;
+import org.onosproject.net.driver.Driver;
+import org.onosproject.net.driver.DriverAdapter;
+import org.onosproject.net.driver.DriverHandler;
+import org.onosproject.net.driver.DriverServiceAdapter;
+import org.onosproject.net.key.DeviceKeyAdminService;
+import org.onosproject.net.key.DeviceKeyAdminServiceAdapter;
+import org.onosproject.net.provider.ProviderId;
+import org.onosproject.netconf.NetconfController;
+import org.onosproject.netconf.NetconfDeviceListener;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+import java.util.concurrent.CopyOnWriteArraySet;
+
+import static org.easymock.EasyMock.*;
+import static org.junit.Assert.*;
+import static org.onlab.junit.TestTools.assertAfter;
+import static org.onosproject.provider.netconf.device.impl.NetconfDeviceProvider.APP_NAME;
+
+/**
+ * Netconf device provider basic test.
+ */
+public class NetconfDeviceProviderTest {
+
+    private final NetconfDeviceProvider provider = new NetconfDeviceProvider();
+    private final NetconfController controller = new MockNetconfController();
+
+    //Provider Mock
+    private final DeviceProviderRegistry deviceRegistry = new MockDeviceProviderRegistry();
+    private final DeviceProviderService providerService = new MockDeviceProviderService();
+    private final DeviceService deviceService = new MockDeviceService();
+    private final MastershipService mastershipService = new MockMastershipService();
+    private final Driver driver = new MockDriver();
+    private final NetworkConfigRegistry cfgService = new MockNetworkConfigRegistry();
+    private final DeviceKeyAdminService deviceKeyAdminService = new DeviceKeyAdminServiceAdapter();
+    private final DeviceStore deviceStore = new MockDeviceStore();
+
+    //Class for testing
+    private final NetworkConfigEvent deviceAddedEvent =
+            new NetworkConfigEvent(NetworkConfigEvent.Type.CONFIG_ADDED,
+                                   null, NetconfProviderConfig.class);
+    private final NetconfProviderConfig netconfProviderConfig = new MockNetconfProviderConfig();
+    private static final String IP = "1.1.1.1";
+    private static final String TEST = "test";
+    private static final int DELAY_DISCOVERY = 500;
+
+    //Provider related classes
+    private CoreService coreService;
+    private ApplicationId appId =
+            new DefaultApplicationId(100, APP_NAME);
+    private DeviceDescriptionDiscovery descriptionDiscovery = new TestDescription();
+    private Set<DeviceListener> deviceListeners = new HashSet<>();
+    private ConfigFactory cfgFactory;
+    private Set<NetworkConfigListener> netCfgListeners = new HashSet<>();
+    private HashMap<DeviceId, Device> devices = new HashMap<>();
+
+    //Controller related classes
+    private Set<NetconfDeviceListener> netconfDeviceListeners = new CopyOnWriteArraySet<>();
+
+    @Before
+    public void setUp() {
+        coreService = createMock(CoreService.class);
+        expect(coreService.registerApplication(APP_NAME))
+                .andReturn(appId).anyTimes();
+        replay(coreService);
+        provider.coreService = coreService;
+        provider.providerRegistry = deviceRegistry;
+        provider.mastershipService = mastershipService;
+        provider.deviceService = deviceService;
+        provider.cfgService = cfgService;
+        provider.controller = controller;
+        provider.deviceKeyAdminService = deviceKeyAdminService;
+        AbstractProjectableModel.setDriverService(null, new DriverServiceAdapter());
+        provider.activate();
+    }
+
+    @Test
+    public void activate() throws Exception {
+
+        assertTrue("Provider should be registered", deviceRegistry.getProviders().contains(provider.id()));
+        assertEquals("Incorrect device service", deviceService, provider.deviceService);
+        assertEquals("Incorrect provider service", providerService, provider.providerService);
+        assertEquals("Device listener should be added", 1, deviceListeners.size());
+        assertFalse("Thread to connect device should be running",
+                    provider.executor.isShutdown() || provider.executor.isTerminated());
+        assertFalse("Scheduled task to update device should be running", provider.scheduledTask.isCancelled());
+    }
+
+    @Test
+    public void deactivate() throws Exception {
+        provider.deactivate();
+        assertEquals("Device listener should be removed", 0, deviceListeners.size());
+        assertFalse("Provider should not be registered", deviceRegistry.getProviders().contains(provider));
+        assertTrue("Thread to connect device should be shutdown", provider.executor.isShutdown());
+        assertTrue("Scheduled task to update device should be shutdown", provider.scheduledTask.isCancelled());
+        assertNull("Provider service should be null", provider.providerService);
+        assertEquals("Controller listener should be removed", 0, netconfDeviceListeners.size());
+    }
+
+    @Test
+    public void addDevice() {
+        assertNotNull(providerService);
+        assertTrue("Event should be relevant", provider.cfgListener.isRelevant(deviceAddedEvent));
+        provider.cfgListener.event(deviceAddedEvent);
+
+        assertAfter(DELAY_DISCOVERY, () ->
+                assertEquals("Device should be added", 1, deviceStore.getDeviceCount()));
+        devices.clear();
+    }
+
+    //TODO: implement ports discovery and check updates of the device description
+
+
+    //Mock classes
+    private class MockNetconfController extends NetconfControllerAdapter {
+
+        @Override
+        public void addDeviceListener(NetconfDeviceListener listener) {
+            if (!netconfDeviceListeners.contains(listener)) {
+                netconfDeviceListeners.add(listener);
+            }
+        }
+
+        @Override
+        public void removeDeviceListener(NetconfDeviceListener listener) {
+            netconfDeviceListeners.remove(listener);
+        }
+    }
+
+    private class MockDeviceProviderRegistry extends DeviceProviderRegistryAdapter {
+
+        Set<ProviderId> providers = new HashSet<>();
+
+        @Override
+        public DeviceProviderService register(DeviceProvider provider) {
+            providers.add(provider.id());
+            return providerService;
+        }
+
+        @Override
+        public void unregister(DeviceProvider provider) {
+            providers.remove(provider.id());
+        }
+
+        @Override
+        public Set<ProviderId> getProviders() {
+            return providers;
+        }
+
+    }
+
+    private class MockDeviceService extends DeviceServiceAdapter {
+        @Override
+        public void addListener(DeviceListener listener) {
+            deviceListeners.add(listener);
+        }
+
+        @Override
+        public void removeListener(DeviceListener listener) {
+            deviceListeners.remove(listener);
+        }
+    }
+
+    private class MockDeviceProviderService extends DeviceProviderServiceAdapter {
+
+        @Override
+        public void deviceConnected(DeviceId deviceId, DeviceDescription desc) {
+            assertNotNull("DeviceId should be not null", deviceId);
+            assertNotNull("DeviceDescription should be not null", desc);
+            deviceStore.createOrUpdateDevice(ProviderId.NONE, deviceId, desc);
+        }
+    }
+
+    private class MockDeviceStore extends DeviceStoreAdapter {
+
+        @Override
+        public DeviceEvent createOrUpdateDevice(ProviderId providerId, DeviceId deviceId,
+                                                DeviceDescription desc) {
+
+            devices.put(deviceId, new DefaultDevice(providerId, deviceId, desc.type(),
+                                                    desc.manufacturer(), desc.hwVersion(),
+                                                    desc.swVersion(), desc.serialNumber(),
+                                                    desc.chassisId(), desc.annotations()));
+
+            return null;
+        }
+
+        @Override
+        public Device getDevice(DeviceId deviceId) {
+            return devices.get(deviceId);
+        }
+
+        @Override
+        public int getDeviceCount() {
+            return devices.size();
+        }
+
+    }
+
+    private class MockMastershipService extends MastershipServiceAdapter {
+
+        @Override
+        public boolean isLocalMaster(DeviceId deviceId) {
+            return true;
+        }
+    }
+
+    private class MockNetworkConfigRegistry extends NetworkConfigRegistryAdapter {
+
+        @Override
+        public void registerConfigFactory(ConfigFactory configFactory) {
+            cfgFactory = configFactory;
+        }
+
+        @Override
+        public void unregisterConfigFactory(ConfigFactory configFactory) {
+            cfgFactory = null;
+        }
+
+        @Override
+        public void addListener(NetworkConfigListener listener) {
+            netCfgListeners.add(listener);
+        }
+
+        @Override
+        public void removeListener(NetworkConfigListener listener) {
+            netCfgListeners.remove(listener);
+        }
+
+
+        @Override
+        public <S, C extends Config<S>> C getConfig(S subject, Class<C> configClass) {
+            if (configClass.equals(NetconfProviderConfig.class)) {
+                return (C) netconfProviderConfig;
+            } else {
+                return (C) new BasicDeviceConfig();
+            }
+        }
+    }
+
+    private class MockNetconfProviderConfig extends NetconfProviderConfig {
+        protected NetconfDeviceAddress deviceInfo =
+                new NetconfDeviceAddress(IpAddress.valueOf(IP), 1, TEST, TEST);
+
+        @Override
+        public Set<NetconfProviderConfig.NetconfDeviceAddress> getDevicesAddresses() throws ConfigException {
+            return ImmutableSet.of(deviceInfo);
+        }
+
+    }
+
+    private class MockDevice extends DefaultDevice {
+
+        public MockDevice(ProviderId providerId, DeviceId id, Type type,
+                          String manufacturer, String hwVersion, String swVersion,
+                          String serialNumber, ChassisId chassisId, Annotations... annotations) {
+            super(providerId, id, type, manufacturer, hwVersion, swVersion, serialNumber,
+                  chassisId, annotations);
+        }
+
+        @Override
+        protected Driver locateDriver() {
+            return driver;
+        }
+
+        @Override
+        public Driver driver() {
+            return driver;
+        }
+    }
+
+    private class MockDriver extends DriverAdapter {
+        @Override
+        public <T extends Behaviour> T createBehaviour(DriverHandler handler, Class<T> behaviourClass) {
+
+            return (T) descriptionDiscovery;
+        }
+    }
+
+    private class TestDescription extends AbstractHandlerBehaviour implements DeviceDescriptionDiscovery {
+
+        List<PortDescription> portDescriptions = new ArrayList<>();
+
+        @Override
+        public DeviceDescription discoverDeviceDetails() {
+            return null;
+        }
+
+        @Override
+        public List<PortDescription> discoverPortDetails() {
+            return portDescriptions;
+        }
+
+        private void addDeviceDetails() {
+
+        }
+
+        private void addPortDesc(PortDescription portDescription) {
+            portDescriptions.add(portDescription);
+        }
+    }
+}