Merge "Makes validateLtpType() consistent with local conf"
diff --git a/global/ce-orchestration/src/main/java/org/opencord/ce/global/orchestration/MetroOrchestrationManager.java b/global/ce-orchestration/src/main/java/org/opencord/ce/global/orchestration/MetroOrchestrationManager.java
index fda358b..9b18473 100644
--- a/global/ce-orchestration/src/main/java/org/opencord/ce/global/orchestration/MetroOrchestrationManager.java
+++ b/global/ce-orchestration/src/main/java/org/opencord/ce/global/orchestration/MetroOrchestrationManager.java
@@ -658,7 +658,10 @@
 
     @Override
     public void removeEvc(EvcConnId evcId) {
+        log.info("Received remove request of EVC, {}", evcId);
+        log.debug("existing EVCs {}", evcMap);
         if (evcMap.containsKey(evcId)) {
+            log.debug("EVC existing, removing, {}", evcId);
             CarrierEthernetVirtualConnection evc = evcMap.get(evcId);
             evc.fcSet().forEach(fc -> {
                 // Decrement the FC refCount to make removal possible
@@ -666,8 +669,12 @@
                 removeFc(fc.id());
             });
             // Avoid excessively incrementing EVC ids
-            nextEvcShortId = evc.shortId() < nextEvcShortId ? evc.shortId() : nextEvcShortId;
+            if (evc.shortId() != null) {
+                nextEvcShortId = evc.shortId() < nextEvcShortId ? evc.shortId() : nextEvcShortId;
+            }
             evcMap.remove(evcId);
+        } else {
+            log.info("EVC {} not present", evcId);
         }
     }
 
diff --git a/global/config-samples/ecord-global-config.json b/global/config-samples/ecord-global-config.json
index 5b9e72a..9dba092 100644
--- a/global/config-samples/ecord-global-config.json
+++ b/global/config-samples/ecord-global-config.json
@@ -4,13 +4,11 @@
       "xos" : {
         "username" : "xosadmin@opencord.org",
         "password" : "0Ui8QNJNCdXrjjLpF1U6",
-        "address" : "127.0.0.1",
-        "resource" : "/xosapi/v1/metronet/usernetworkinterfaces/"
+        "endpoint" : "10.90.1.10:80/xosapi/v1/vnaas/usernetworkinterfaces"
       }
     },
     "org.opencord.ce.global.channel.http" : {
       "endPoints" : {
-        "port" : "8182",
         "topics" : [
           "ecord-domains-topic-one",
           "ecord-domains-topic-two",
diff --git a/global/http-channel/src/main/java/org/opencord/ce/global/channel/client/ConnectionConfig.java b/global/http-channel/src/main/java/org/opencord/ce/global/channel/client/ConnectionConfig.java
index ca7388a..8fd025c 100644
--- a/global/http-channel/src/main/java/org/opencord/ce/global/channel/client/ConnectionConfig.java
+++ b/global/http-channel/src/main/java/org/opencord/ce/global/channel/client/ConnectionConfig.java
@@ -46,14 +46,6 @@
     private static final String TOPIC = "topic";
 
     /**
-     * Gets listen port from configuration.
-     * @return port number
-     */
-    public int listenPort() {
-        return object.path(PORT).asInt();
-    }
-
-    /**
      * List of topics to distribute network operations among ONOS instances.
      * @return list of topics
      */
diff --git a/global/http-channel/src/main/java/org/opencord/ce/global/channel/client/HttpClientInstance.java b/global/http-channel/src/main/java/org/opencord/ce/global/channel/client/HttpClientInstance.java
index a6687a1..4c17837 100644
--- a/global/http-channel/src/main/java/org/opencord/ce/global/channel/client/HttpClientInstance.java
+++ b/global/http-channel/src/main/java/org/opencord/ce/global/channel/client/HttpClientInstance.java
@@ -185,6 +185,7 @@
 
     @Override
     public void createBandwidthProfileResources(CarrierEthernetForwardingConstruct fc, CarrierEthernetUni uni) {
+        log.debug("FC {}, UNI {}", fc, uni);
         DomainId domainId = domainService.getDomain(uni.cp().deviceId());
         if (domainId == LOCAL || !isLeader(getTopic(domainId))) {
             return;
diff --git a/global/virtualprovider/src/main/java/org/opencord/ce/global/virtualdomain/VirtualDomainDeviceProvider.java b/global/virtualprovider/src/main/java/org/opencord/ce/global/virtualdomain/VirtualDomainDeviceProvider.java
index d1bdefb..8d8eb38 100644
--- a/global/virtualprovider/src/main/java/org/opencord/ce/global/virtualdomain/VirtualDomainDeviceProvider.java
+++ b/global/virtualprovider/src/main/java/org/opencord/ce/global/virtualdomain/VirtualDomainDeviceProvider.java
@@ -24,6 +24,9 @@
 import org.apache.felix.scr.annotations.ReferenceCardinality;
 import org.apache.felix.scr.annotations.Service;
 import org.onosproject.net.config.basics.SubjectFactories;
+import org.onosproject.net.device.DeviceService;
+import org.onosproject.store.service.AtomicCounter;
+import org.onosproject.store.service.StorageService;
 import org.opencord.ce.api.services.virtualprovider.DomainVirtualDevice;
 import org.opencord.ce.api.services.virtualprovider.EcordDeviceProviderService;
 import org.onlab.packet.ChassisId;
@@ -65,12 +68,15 @@
 
 import java.util.List;
 import java.util.concurrent.ExecutorService;
+import java.util.stream.Collectors;
 
 import static java.util.concurrent.Executors.newFixedThreadPool;
 import static org.onlab.util.Tools.groupedThreads;
 import static org.onosproject.net.AnnotationKeys.DRIVER;
 import static org.onosproject.net.AnnotationKeys.LATITUDE;
 import static org.onosproject.net.AnnotationKeys.LONGITUDE;
+import static org.opencord.ce.api.services.channel.Symbols.MEF_PORT_TYPE;
+import static org.opencord.ce.api.services.channel.Symbols.UNI;
 import static org.slf4j.LoggerFactory.getLogger;
 import static org.opencord.ce.api.models.CarrierEthernetNetworkInterface.Type;
 
@@ -87,7 +93,7 @@
     private static final String UNKNOWN = "unknown";
     private static final String NO_LLDP = "no-lldp";
     private static final String DOMAIN_ID = "domainId";
-    private static final String MEF_IF_TYPE = "mefIfType";
+    private static final String LATLNG_COUNTER = "ecord-latlng-counter";
 
     private ApplicationId appId;
 
@@ -110,12 +116,19 @@
     protected ClusterService clusterService;
 
     @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+    protected StorageService storageService;
+
+    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
     protected MetroOrchestrationService metroOrchestrationService;
 
+    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+    protected DeviceService deviceService;
+
     protected DeviceProviderService deviceProviderService;
 
     private EcordDriverConfig ecordDriverConfig;
     private XoSHttpClient xoSHttpClient;
+    private AtomicCounter latlngCounter;
 
     private final NetworkConfigListener configListener = new InternalConfigListener();
 
@@ -147,9 +160,16 @@
     public void activate() {
         appId = coreService.registerApplication(PROVIDER_NAME);
        // configRegistry.registerConfigFactory(diverConfigFactory);
+        latlngCounter = storageService.atomicCounterBuilder()
+                .withName(LATLNG_COUNTER)
+                .build()
+                .asAtomicCounter();
         configRegistry.registerConfigFactory(xosEndpointConfigFactory);
         configService.addListener(configListener);
         deviceProviderService = deviceProviderRegistry.register(this);
+        if (!configService.getSubjects(XosEndPointConfig.class).isEmpty()) {
+            readXoSEndPointConfig();
+        }
         log.info("Started");
     }
 
@@ -260,10 +280,19 @@
      * @param portDescriptions description of ports
      */
     private void advertiseDevicePorts(DeviceId deviceId, List<PortDescription> portDescriptions) {
+        List<PortNumber> ports = deviceService.getPorts(deviceId).stream().map(Port::number)
+                .collect(Collectors.toList());
+        List<PortDescription> toNotify = portDescriptions.stream()
+                .filter(portDescription -> !ports.contains(portDescription.portNumber())
+                        && portDescription.annotations().value(MEF_PORT_TYPE).equalsIgnoreCase(UNI))
+                .collect(Collectors.toList());
         log.info("Notifying ecord virtual ports...");
+        log.debug("E-CORD virtual ports {}", portDescriptions);
         deviceProviderService.updatePorts(deviceId, portDescriptions);
        // addGlobalMefLtp(deviceId, portDescriptions);
-        notifyXoS(deviceId, portDescriptions);
+        log.info("Notifying XOS of virtual ports...");
+        log.debug("E-CORD to XOS ports {}", toNotify);
+        notifyXoS(deviceId, toNotify);
     }
 
     private void disconnectDevice(DeviceId deviceId) {
@@ -272,19 +301,32 @@
 
     private void notifyXoS(DeviceId deviceId, List<PortDescription> portDescriptions) {
         portDescriptions.forEach(port -> {
-            if (port.annotations().keys().contains(MEF_IF_TYPE)) {
+            if (port.annotations().keys().contains(MEF_PORT_TYPE)) {
                 Type type = Type.valueOf(
-                        port.annotations().value(MEF_IF_TYPE));
+                        port.annotations().value(MEF_PORT_TYPE));
                 ConnectPoint cp = new ConnectPoint(deviceId, port.portNumber());
                 switch (type) {
                     case UNI:
+                        log.debug("Port descriptions {}", portDescriptions);
+                        //If XoSClient null create new one
+                        if (xoSHttpClient == null) {
+                            readXoSEndPointConfig();
+                        }
                         ObjectNode body = xoSHttpClient.mapper().createObjectNode();
                         body.put("tenant", port.annotations().value(DOMAIN_ID));
                         body.put("name", "UNI:" + cp.toString());
-                        body.put("latlng", "[" + port.annotations().value(LATITUDE) + "," +
-                                port.annotations().value(LONGITUDE) + "]");
+                        String latitude = port.annotations().value(LATITUDE);
+                        String longitude = port.annotations().value(LONGITUDE);
+                        if (latitude == null || longitude == null) {
+                            //Something went wrong in the local, lets reset them both
+                            longitude = String.valueOf(latlngCounter.get());
+                            latitude = String.valueOf(latlngCounter.getAndAdd(10L));
+                        }
+                        body.put("latlng", "[" + latitude + ", " +
+                                longitude + "]");
                         body.put("cpe_id", cp.toString());
-                        xoSHttpClient.restPut(body.toString(), cp.toString());
+                        log.debug("Node {}", body.toString());
+                        xoSHttpClient.restPost(body.toString());
                         break;
                     case ENNI:
 
@@ -311,9 +353,9 @@
      */
     private void addGlobalMefLtp(DeviceId deviceId, List<PortDescription> portDescriptions) {
         portDescriptions.forEach(port -> {
-            if (port.annotations().keys().contains(MEF_IF_TYPE)) {
+            if (port.annotations().keys().contains(MEF_PORT_TYPE)) {
                 Type type = Type.valueOf(
-                        port.annotations().value(MEF_IF_TYPE));
+                        port.annotations().value(MEF_PORT_TYPE));
                 CarrierEthernetNetworkInterface ni;
                 ConnectPoint cp = new ConnectPoint(deviceId, port.portNumber());
                 switch (type) {
@@ -347,8 +389,12 @@
     }
 
     private void readXoSEndPointConfig() {
-        xoSHttpClient =
-                new XoSHttpClient(configRegistry.getConfig(appId, XosEndPointConfig.class).xos());
+        XosEndPointConfig xosEndPointConfig = configRegistry.getConfig(appId, XosEndPointConfig.class);
+        if (xosEndPointConfig != null) {
+            xoSHttpClient = new XoSHttpClient(xosEndPointConfig.xos());
+        } else {
+            log.warn("Null configuration for XOS, can't push UNIs");
+        }
     }
 
     private void readDriverFromConfig() {
@@ -359,13 +405,9 @@
     private class InternalConfigListener implements NetworkConfigListener {
         @Override
         public void event(NetworkConfigEvent event) {
-            if (!event.configClass().equals(EcordDriverConfig.class) ||
-                    !event.configClass().equals(XosEndPointConfig.class)) {
-                return;
-            }
             switch (event.type()) {
                 case CONFIG_ADDED:
-                    log.info("Network configuration added");
+                    log.debug("Network configuration added");
                     if (event.configClass().equals(EcordDriverConfig.class)) {
                         eventExecutor.execute(VirtualDomainDeviceProvider.this::readDriverFromConfig);
                     } else {
@@ -374,7 +416,7 @@
 
                     break;
                 case CONFIG_UPDATED:
-                    log.info("Network configuration updated");
+                    log.debug("Network configuration updated");
                     if (event.configClass().equals(EcordDriverConfig.class)) {
                         eventExecutor.execute(VirtualDomainDeviceProvider.this::readDriverFromConfig);
                     } else {
@@ -385,5 +427,11 @@
                     break;
             }
         }
+
+        @Override
+        public boolean isRelevant(NetworkConfigEvent event) {
+            return event.configClass().equals(EcordDriverConfig.class)
+                    || event.configClass().equals(XosEndPointConfig.class);
+        }
     }
 }
diff --git a/global/virtualprovider/src/main/java/org/opencord/ce/global/virtualdomain/XoSHttpClient.java b/global/virtualprovider/src/main/java/org/opencord/ce/global/virtualdomain/XoSHttpClient.java
index 1d72b40..59c544f 100644
--- a/global/virtualprovider/src/main/java/org/opencord/ce/global/virtualdomain/XoSHttpClient.java
+++ b/global/virtualprovider/src/main/java/org/opencord/ce/global/virtualdomain/XoSHttpClient.java
@@ -18,6 +18,7 @@
 
 import com.fasterxml.jackson.databind.SerializationFeature;
 import org.glassfish.jersey.client.ClientProperties;
+import org.glassfish.jersey.client.authentication.HttpAuthenticationFeature;
 import org.onosproject.rest.AbstractWebResource;
 import org.slf4j.Logger;
 
@@ -43,24 +44,39 @@
     private XosEndPoint xosEndPoint;
     private final Client client = ClientBuilder.newClient();
 
-
+    /**
+     * Creates a Client to contact XOS from this ONOS instance.
+     * @param xosEndPoint class containing info of the endpoint of XOS
+     */
     public XoSHttpClient(XosEndPoint xosEndPoint) {
         this.xosEndPoint = xosEndPoint;
+        // Setup credentials
+        HttpAuthenticationFeature feature = HttpAuthenticationFeature.basicBuilder()
+                .nonPreemptive()
+                .credentials(xosEndPoint.username(), xosEndPoint.password())
+                .build();
 
+        client.register(feature);
         client.property(ClientProperties.CONNECT_TIMEOUT, DEFAULT_TIMEOUT_MS);
         client.property(ClientProperties.READ_TIMEOUT, DEFAULT_TIMEOUT_MS);
         mapper().enable(SerializationFeature.INDENT_OUTPUT);
     }
 
-    public void restPut(String body, String cpeId) {
-        WebTarget webTarget = client.target("http://" + xosEndPoint.ipAddress().toString() +
-                 xosEndPoint.resource() + "/" + cpeId);
+    /**
+     * Enables to make a post request to XOS.
+     * @param body the body to post to XOS
+     */
+    public void restPost(String body) {
+        log.info("URL {}", "http://" + xosEndPoint.endpoint());
+        WebTarget webTarget = client.target("http://" + xosEndPoint.endpoint());
         Response response;
         response = webTarget.request(MediaType.APPLICATION_JSON)
-                .put(Entity.entity(body, MediaType.APPLICATION_JSON));
+                .post(Entity.entity(body, MediaType.APPLICATION_JSON));
         try {
             if (response.getStatus() != HTTP_OK) {
-                log.warn("Failed to put resource {}", xosEndPoint.resource());
+                log.warn("Failed to post resource {}, response {}", xosEndPoint.endpoint(), response);
+            } else {
+                log.info("Post UNIs to XoS successful: {}", response.getStatus());
             }
         } catch (javax.ws.rs.ProcessingException e) {
             log.error("Javax process exception in XoSClientHttp: {}", e.getMessage());
diff --git a/global/virtualprovider/src/main/java/org/opencord/ce/global/virtualdomain/config/XosEndPointConfig.java b/global/virtualprovider/src/main/java/org/opencord/ce/global/virtualdomain/config/XosEndPointConfig.java
index df0c59e..c64aaa9 100644
--- a/global/virtualprovider/src/main/java/org/opencord/ce/global/virtualdomain/config/XosEndPointConfig.java
+++ b/global/virtualprovider/src/main/java/org/opencord/ce/global/virtualdomain/config/XosEndPointConfig.java
@@ -16,46 +16,43 @@
 
 package org.opencord.ce.global.virtualdomain.config;
 
-import com.fasterxml.jackson.databind.JsonNode;
-import org.onlab.packet.IpAddress;
 import org.onosproject.core.ApplicationId;
 import org.onosproject.net.config.Config;
 
 /**
- * Global XoS endpoint.
+ * Global XoS endpoint containing all information from XOS.
  */
 public class XosEndPointConfig extends Config<ApplicationId> {
+
     private static final String USERNAME = "username";
     private static final String PASSWD = "password";
-    private static final String XOS = "xos";
-    private static final String ADDRESS = "address";
-    private static final String RESOURCE = "resource";
+    private static final String ENDPOINT = "endpoint";
 
+    /**
+     * Gets the enpoint from the Configuration.
+     * @return a class containing all the info to connect
+     */
     public XosEndPoint xos() {
-        JsonNode xosNode = object.path(XOS);
-        IpAddress ipAddress = IpAddress.valueOf(xosNode.get(ADDRESS).asText());
-        String username = xosNode.get(USERNAME).asText();
-        String password = xosNode.get(PASSWD).asText();
-        String resource = xosNode.get(RESOURCE).asText();
-        return new XosEndPoint(ipAddress, username, password, resource);
+        String endpoint = node.get(ENDPOINT).asText();
+        String username = node.get(USERNAME).asText();
+        String password = node.get(PASSWD).asText();
+        return new XosEndPoint(endpoint, username, password);
     }
 
     public static class XosEndPoint {
-        private IpAddress ipAddress;
+        private String endpoint;
         private String username;
         private String password;
-        private String resource;
 
-        public XosEndPoint(IpAddress ipAddress, String username,
-                           String password, String resource) {
-            this.ipAddress = ipAddress;
+        public XosEndPoint(String endpoint, String username,
+                           String password) {
+            this.endpoint = endpoint;
             this.username = username;
             this.password = password;
-            this.resource = resource;
         }
 
-        public IpAddress ipAddress() {
-            return ipAddress;
+        public String endpoint() {
+            return endpoint;
         }
 
         public String username() {
@@ -66,9 +63,6 @@
             return password;
         }
 
-        public String resource() {
-            return resource;
-        }
     }
 
 }