Initial implementation of the intent domain manager

Change-Id: I9721449599a4a67bfad7469173c3b47a681873f6
diff --git a/incubator/api/src/main/java/org/onosproject/incubator/net/config/Config.java b/incubator/api/src/main/java/org/onosproject/incubator/net/config/Config.java
index 2be2fba..1789bac 100644
--- a/incubator/api/src/main/java/org/onosproject/incubator/net/config/Config.java
+++ b/incubator/api/src/main/java/org/onosproject/incubator/net/config/Config.java
@@ -16,8 +16,14 @@
 package org.onosproject.incubator.net.config;
 
 import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.node.ArrayNode;
 import com.fasterxml.jackson.databind.node.ObjectNode;
 import com.google.common.annotations.Beta;
+import com.google.common.collect.Lists;
+
+import java.util.Collection;
+import java.util.List;
+import java.util.function.Function;
 
 import static com.google.common.base.Preconditions.checkNotNull;
 
@@ -259,4 +265,39 @@
         return this;
     }
 
+    /**
+     * Gets the specified array property as a list of items.
+     *
+     * @param name property name
+     * @param function mapper from string to item
+     * @param <T> type of item
+     * @return list of items
+     */
+    protected <T> List<T> getList(String name, Function<String, T> function) {
+        List<T> list = Lists.newArrayList();
+        ArrayNode arrayNode = (ArrayNode) node.path(name);
+        arrayNode.forEach(i -> list.add(function.apply(i.asText())));
+        return list;
+    }
+
+    /**
+     * Sets the specified property as an array of items in a given collection or
+     * clears it if null is given.
+     *
+     * @param name propertyName
+     * @param collection collection of items
+     * @param <T> type of items
+     * @return self
+     */
+    protected <T> Config<S> setOrClear(String name, Collection<T> collection) {
+        if (collection == null) {
+            node.remove(name);
+        } else {
+            ArrayNode arrayNode = mapper.createArrayNode();
+            collection.forEach(i -> arrayNode.add(i.toString()));
+            node.set(name, arrayNode);
+        }
+        return this;
+    }
+
 }
diff --git a/incubator/api/src/main/java/org/onosproject/incubator/net/config/basics/SubjectFactories.java b/incubator/api/src/main/java/org/onosproject/incubator/net/config/basics/SubjectFactories.java
index a91a352..0ba9459 100644
--- a/incubator/api/src/main/java/org/onosproject/incubator/net/config/basics/SubjectFactories.java
+++ b/incubator/api/src/main/java/org/onosproject/incubator/net/config/basics/SubjectFactories.java
@@ -18,6 +18,7 @@
 import org.onosproject.core.ApplicationId;
 import org.onosproject.core.CoreService;
 import org.onosproject.incubator.net.config.SubjectFactory;
+import org.onosproject.incubator.net.domain.IntentDomainId;
 import org.onosproject.net.ConnectPoint;
 import org.onosproject.net.DeviceId;
 import org.onosproject.net.HostId;
@@ -80,6 +81,14 @@
                 }
             };
 
+    public static final SubjectFactory<IntentDomainId> INTENT_DOMAIN_SUBJECT_FACTORY =
+            new SubjectFactory<IntentDomainId>(IntentDomainId.class, "domains") {
+                @Override
+                public IntentDomainId createSubject(String key) {
+                    return IntentDomainId.valueOf(key);
+                }
+            };
+
     /**
      * Provides reference to the core service, which is required for
      * application subject factory.
diff --git a/incubator/api/src/main/java/org/onosproject/incubator/net/domain/DomainVertex.java b/incubator/api/src/main/java/org/onosproject/incubator/net/domain/DomainVertex.java
index 82b4313..0fdf25a 100644
--- a/incubator/api/src/main/java/org/onosproject/incubator/net/domain/DomainVertex.java
+++ b/incubator/api/src/main/java/org/onosproject/incubator/net/domain/DomainVertex.java
@@ -16,6 +16,7 @@
 package org.onosproject.incubator.net.domain;
 
 import com.google.common.annotations.Beta;
+import com.google.common.base.MoreObjects;
 import org.onlab.graph.Vertex;
 import org.onosproject.net.DeviceId;
 
@@ -30,23 +31,39 @@
     // FIXME we will want to add a type enum or subclasses for the two different types
 
     // A domain vertex is either an intent domain or a device:
-    private final IntentDomainId id;
+    private final IntentDomainId domainId;
     // ----- or -----
     private final DeviceId deviceId;
 
     // Serialization constructor
     private DomainVertex() {
-        this.id = null;
+        this.domainId = null;
         this.deviceId = null;
     }
 
-    DomainVertex(IntentDomainId id) {
-        this.id = checkNotNull(id, "Intent domain ID cannot be null.");
+    public DomainVertex(IntentDomainId id) {
+        this.domainId = checkNotNull(id, "Intent domain ID cannot be null.");
         this.deviceId = null;
     }
 
-    DomainVertex(DeviceId id) {
-        this.id = null;
+    public DomainVertex(DeviceId id) {
+        this.domainId = null;
         this.deviceId = checkNotNull(id, "Device ID cannot be null.");
     }
+
+    @Override
+    public String toString() {
+        if (domainId != null) {
+            return MoreObjects.toStringHelper(this)
+                    .add("domainId", domainId)
+                    .toString();
+        } else if (deviceId != null) {
+            return MoreObjects.toStringHelper(this)
+                    .add("deviceId", deviceId)
+                    .toString();
+        } else {
+            return MoreObjects.toStringHelper(this)
+                    .toString();
+        }
+    }
 }
diff --git a/incubator/api/src/main/java/org/onosproject/incubator/net/domain/IntentDomain.java b/incubator/api/src/main/java/org/onosproject/incubator/net/domain/IntentDomain.java
index 7450114..a52dce6 100644
--- a/incubator/api/src/main/java/org/onosproject/incubator/net/domain/IntentDomain.java
+++ b/incubator/api/src/main/java/org/onosproject/incubator/net/domain/IntentDomain.java
@@ -19,7 +19,6 @@
 import org.onosproject.net.ConnectPoint;
 import org.onosproject.net.DeviceId;
 
-import java.util.Objects;
 import java.util.Set;
 
 /**
@@ -37,7 +36,7 @@
 
     private IntentDomainProvider provider;
 
-    IntentDomain(IntentDomainId id, String name,
+    public IntentDomain(IntentDomainId id, String name,
                  Set<DeviceId> internalDevices,
                  Set<ConnectPoint> edgePorts) {
         this.id = id;
@@ -88,7 +87,7 @@
      *
      * @return intent domain provider
      */
-    IntentDomainProvider provider() {
+    public IntentDomainProvider provider() {
         return provider;
     }
 
@@ -115,16 +114,10 @@
     }
 
     /**
-     * Unsets the provider for the intent domain if the given provider matches
-     * the existing provider.
-     *
-     * @param provider provider to unset
+     * Unsets the provider for the intent domain.
      */
-    public void unsetProvider(IntentDomainProvider provider) {
-        // TODO consider checkState depending on caller
-        if (Objects.equals(this.provider, provider)) {
-            this.provider = null;
-        }
+    public void unsetProvider() {
+        this.provider = null;
     }
 
     //TODO add remaining setters (we will probably want to link this to the network config)
diff --git a/incubator/api/src/main/java/org/onosproject/incubator/net/domain/IntentDomainAdminService.java b/incubator/api/src/main/java/org/onosproject/incubator/net/domain/IntentDomainAdminService.java
index 6833d38..f5ceaa9 100644
--- a/incubator/api/src/main/java/org/onosproject/incubator/net/domain/IntentDomainAdminService.java
+++ b/incubator/api/src/main/java/org/onosproject/incubator/net/domain/IntentDomainAdminService.java
@@ -22,7 +22,7 @@
  * Administrative interface for the intent domain service.
  */
 @Beta
-public interface IntentDomainAdminService {
+public interface IntentDomainAdminService extends IntentDomainService {
 
     /**
      * Register an application that provides intent domain service.
diff --git a/incubator/api/src/main/java/org/onosproject/incubator/net/domain/IntentDomainConfig.java b/incubator/api/src/main/java/org/onosproject/incubator/net/domain/IntentDomainConfig.java
index 19c1c86..6cc6fb8 100644
--- a/incubator/api/src/main/java/org/onosproject/incubator/net/domain/IntentDomainConfig.java
+++ b/incubator/api/src/main/java/org/onosproject/incubator/net/domain/IntentDomainConfig.java
@@ -16,6 +16,7 @@
 package org.onosproject.incubator.net.domain;
 
 import com.google.common.annotations.Beta;
+import com.google.common.collect.ImmutableSet;
 import org.onosproject.incubator.net.config.Config;
 import org.onosproject.net.ConnectPoint;
 import org.onosproject.net.DeviceId;
@@ -27,10 +28,13 @@
  * set of edge ports, and the application bound to control the domain.
  */
 @Beta
-public abstract class IntentDomainConfig extends Config<IntentDomainId> {
+public class IntentDomainConfig extends Config<IntentDomainId> {
 
-    private static final String DOMAIN_NAME = "domainName";
+    private static final String DOMAIN_NAME = "name";
     private static final String APPLICATION_NAME = "applicationName";
+    private static final String INTERNAL_DEVICES = "internalDevices";
+    private static final String EDGE_PORTS = "edgePorts";
+
 
     /**
      * Returns the friendly name for the domain.
@@ -57,7 +61,7 @@
      * @return domain name
      */
     public String applicationName() {
-        return get(APPLICATION_NAME, null); //TODO maybe not null?
+        return get(APPLICATION_NAME, "FIXME"); //TODO maybe not null?
     }
 
     /**
@@ -70,8 +74,42 @@
         return (IntentDomainConfig) setOrClear(APPLICATION_NAME, applicationName);
     }
 
-    //TODO sets
-    abstract Set<DeviceId> internalDevices();
-    abstract Set<ConnectPoint> edgePorts();
+    /**
+     * Returns the set of internal devices.
+     *
+     * @return set of internal devices
+     */
+    public Set<DeviceId> internalDevices() {
+        return ImmutableSet.copyOf(getList(INTERNAL_DEVICES, DeviceId::deviceId));
+    }
+
+    /**
+     * Sets the set of internal devices.
+     *
+     * @param devices set of devices; null to clear
+     * @return self
+     */
+    public IntentDomainConfig internalDevices(Set<DeviceId> devices) {
+        return (IntentDomainConfig) setOrClear(INTERNAL_DEVICES, devices);
+    }
+
+    /**
+     * Returns the set of edge ports.
+     *
+     * @return set of edge ports
+     */
+    public Set<ConnectPoint> edgePorts() {
+        return ImmutableSet.copyOf(getList(EDGE_PORTS, ConnectPoint::deviceConnectPoint));
+    }
+
+    /**
+     * Sets the set of edge ports.
+     *
+     * @param connectPoints set of edge ports; null to clear
+     * @return self
+     */
+    public IntentDomainConfig edgePorts(Set<ConnectPoint> connectPoints) {
+        return (IntentDomainConfig) setOrClear(EDGE_PORTS, connectPoints);
+    }
 
 }
diff --git a/incubator/api/src/main/java/org/onosproject/incubator/net/domain/IntentPrimitive.java b/incubator/api/src/main/java/org/onosproject/incubator/net/domain/IntentPrimitive.java
index d0824e5..7cfd14b 100644
--- a/incubator/api/src/main/java/org/onosproject/incubator/net/domain/IntentPrimitive.java
+++ b/incubator/api/src/main/java/org/onosproject/incubator/net/domain/IntentPrimitive.java
@@ -26,7 +26,7 @@
 
     private final ApplicationId appId;
 
-    IntentPrimitive(ApplicationId appId) {
+    public IntentPrimitive(ApplicationId appId) {
         this.appId = appId;
     }
 }
diff --git a/incubator/api/src/main/java/org/onosproject/incubator/net/domain/RequestContext.java b/incubator/api/src/main/java/org/onosproject/incubator/net/domain/RequestContext.java
index 342f4d0..81f452e 100644
--- a/incubator/api/src/main/java/org/onosproject/incubator/net/domain/RequestContext.java
+++ b/incubator/api/src/main/java/org/onosproject/incubator/net/domain/RequestContext.java
@@ -26,7 +26,7 @@
  * also be automatically cancelled by a provider after a short timeout.
  */
 @Beta
-class RequestContext {
+public class RequestContext {
     IntentDomain domain;
     IntentResource resource;
     //TODO other common parameters: