Initial implementation of the intent domain manager

Change-Id: I9721449599a4a67bfad7469173c3b47a681873f6
diff --git a/core/net/src/main/java/org/onosproject/net/intent/impl/IntentManager.java b/core/net/src/main/java/org/onosproject/net/intent/impl/IntentManager.java
index 16404e3..a6e6dec 100644
--- a/core/net/src/main/java/org/onosproject/net/intent/impl/IntentManager.java
+++ b/core/net/src/main/java/org/onosproject/net/intent/impl/IntentManager.java
@@ -70,7 +70,7 @@
 
 
 /**
- * An implementation of Intent Manager.
+ * An implementation of intent service.
  */
 @Component(immediate = true)
 @Service
diff --git a/core/store/serializers/pom.xml b/core/store/serializers/pom.xml
index e1dfd5e..d869f60 100644
--- a/core/store/serializers/pom.xml
+++ b/core/store/serializers/pom.xml
@@ -41,6 +41,10 @@
             <artifactId>guava-testlib</artifactId>
             <scope>test</scope>
         </dependency>
+        <dependency>
+            <groupId>org.onosproject</groupId>
+            <artifactId>onos-incubator-api</artifactId>
+        </dependency>
     </dependencies>
 
 </project>
diff --git a/core/store/serializers/src/main/java/org/onosproject/store/serializers/KryoNamespaces.java b/core/store/serializers/src/main/java/org/onosproject/store/serializers/KryoNamespaces.java
index 874b23f..e609928 100644
--- a/core/store/serializers/src/main/java/org/onosproject/store/serializers/KryoNamespaces.java
+++ b/core/store/serializers/src/main/java/org/onosproject/store/serializers/KryoNamespaces.java
@@ -45,6 +45,7 @@
 import org.onosproject.core.DefaultApplicationId;
 import org.onosproject.core.DefaultGroupId;
 import org.onosproject.core.Version;
+import org.onosproject.incubator.net.domain.IntentDomainId;
 import org.onosproject.mastership.MastershipTerm;
 import org.onosproject.net.Annotations;
 import org.onosproject.net.ChannelSpacing;
@@ -416,7 +417,8 @@
                     Frequency.class,
                     DefaultAnnotations.class,
                     PortStatistics.class,
-                    DefaultPortStatistics.class
+                    DefaultPortStatistics.class,
+                    IntentDomainId.class
             )
             .register(new DefaultApplicationIdSerializer(), DefaultApplicationId.class)
             .register(new URISerializer(), URI.class)
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:
diff --git a/incubator/net/src/main/java/org/onosproject/incubator/net/config/impl/BasicNetworkConfigs.java b/incubator/net/src/main/java/org/onosproject/incubator/net/config/impl/BasicNetworkConfigs.java
index 4196aa8..b2d15b3 100644
--- a/incubator/net/src/main/java/org/onosproject/incubator/net/config/impl/BasicNetworkConfigs.java
+++ b/incubator/net/src/main/java/org/onosproject/incubator/net/config/impl/BasicNetworkConfigs.java
@@ -29,6 +29,8 @@
 import org.onosproject.incubator.net.config.basics.BasicLinkConfig;
 import org.onosproject.incubator.net.config.basics.BasicPortConfig;
 import org.onosproject.incubator.net.config.basics.SubjectFactories;
+import org.onosproject.incubator.net.domain.IntentDomainConfig;
+import org.onosproject.incubator.net.domain.IntentDomainId;
 import org.onosproject.net.ConnectPoint;
 import org.onosproject.net.DeviceId;
 import org.onosproject.net.HostId;
@@ -80,6 +82,14 @@
                 public BasicLinkConfig createConfig() {
                     return new BasicLinkConfig();
                 }
+            },
+            new ConfigFactory<IntentDomainId, IntentDomainConfig>(INTENT_DOMAIN_SUBJECT_FACTORY,
+                                                                  IntentDomainConfig.class,
+                                                                  "basic") {
+                @Override
+                public IntentDomainConfig createConfig() {
+                    return new IntentDomainConfig();
+                }
             }
     );
 
diff --git a/incubator/net/src/main/java/org/onosproject/incubator/net/domain/impl/IntentDomainManager.java b/incubator/net/src/main/java/org/onosproject/incubator/net/domain/impl/IntentDomainManager.java
new file mode 100644
index 0000000..f1b772b
--- /dev/null
+++ b/incubator/net/src/main/java/org/onosproject/incubator/net/domain/impl/IntentDomainManager.java
@@ -0,0 +1,210 @@
+/*
+ * Copyright 2015 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.incubator.net.domain.impl;
+
+import com.google.common.collect.HashMultimap;
+import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.Maps;
+import com.google.common.collect.Multimap;
+import com.google.common.collect.Multimaps;
+import com.google.common.collect.Sets;
+import org.apache.felix.scr.annotations.Activate;
+import org.apache.felix.scr.annotations.Component;
+import org.apache.felix.scr.annotations.Deactivate;
+import org.apache.felix.scr.annotations.Reference;
+import org.apache.felix.scr.annotations.ReferenceCardinality;
+import org.apache.felix.scr.annotations.Service;
+import org.onlab.graph.AdjacencyListsGraph;
+import org.onlab.graph.Graph;
+import org.onosproject.core.ApplicationId;
+import org.onosproject.core.CoreService;
+import org.onosproject.incubator.net.config.NetworkConfigEvent;
+import org.onosproject.incubator.net.config.NetworkConfigListener;
+import org.onosproject.incubator.net.config.NetworkConfigService;
+import org.onosproject.incubator.net.domain.DomainEdge;
+import org.onosproject.incubator.net.domain.DomainVertex;
+import org.onosproject.incubator.net.domain.IntentDomain;
+import org.onosproject.incubator.net.domain.IntentDomainAdminService;
+import org.onosproject.incubator.net.domain.IntentDomainConfig;
+import org.onosproject.incubator.net.domain.IntentDomainId;
+import org.onosproject.incubator.net.domain.IntentDomainListener;
+import org.onosproject.incubator.net.domain.IntentDomainProvider;
+import org.onosproject.incubator.net.domain.IntentDomainService;
+import org.onosproject.net.ConnectPoint;
+import org.onosproject.net.DeviceId;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.ConcurrentMap;
+import java.util.stream.Collectors;
+
+/**
+ * Implementation of the intent domain service.
+ */
+@Component(immediate = true)
+@Service
+public class IntentDomainManager
+        implements IntentDomainService, IntentDomainAdminService {
+
+    private final Logger log = LoggerFactory.getLogger(getClass());
+
+    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+    protected CoreService coreService;
+
+    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+    protected NetworkConfigService configService;
+
+    private NetworkConfigListener cfgListener = new InternalConfigListener();
+
+    private final ConcurrentMap<IntentDomainId, IntentDomain> domains = Maps.newConcurrentMap();
+
+    private final Multimap<String, IntentDomainId> appToDomain =
+            Multimaps.synchronizedSetMultimap(HashMultimap.<String, IntentDomainId>create());
+
+    private Graph<DomainVertex, DomainEdge> graph;
+
+    @Activate
+    protected void activate() {
+        configService.addListener(cfgListener);
+        configService.getSubjects(IntentDomainId.class, IntentDomainConfig.class)
+                     .forEach(this::processConfig);
+        graph = buildGraph();
+        log.debug("Graph: {}", graph);
+        log.info("Started");
+    }
+
+    private void processConfig(IntentDomainId intentDomainId) {
+        IntentDomainConfig cfg = configService.getConfig(intentDomainId,
+                                                         IntentDomainConfig.class);
+
+        domains.put(intentDomainId, createDomain(intentDomainId, cfg));
+        appToDomain.put(cfg.applicationName(), intentDomainId);
+    }
+
+    private IntentDomain createDomain(IntentDomainId id, IntentDomainConfig cfg) {
+        return new IntentDomain(id, cfg.domainName(), cfg.internalDevices(), cfg.edgePorts());
+    }
+
+    private Graph<DomainVertex, DomainEdge> buildGraph() {
+        Set<DomainVertex> vertices = Sets.newHashSet();
+        Set<DomainEdge> edges = Sets.newHashSet();
+
+        Map<DeviceId, DomainVertex> deviceVertices = Maps.newHashMap();
+        domains.forEach((id, domain) -> {
+            DomainVertex domainVertex = new DomainVertex(id);
+
+            // Add vertex for domain
+            vertices.add(domainVertex);
+
+            // Add vertices for connection devices
+            domain.edgePorts().stream()
+                  .map(ConnectPoint::deviceId)
+                  .collect(Collectors.toSet())
+                    .forEach(did -> deviceVertices.putIfAbsent(did, new DomainVertex(did)));
+
+            // Add bi-directional edges between each domain and connection device
+            domain.edgePorts().forEach(cp -> {
+                DomainVertex deviceVertex = deviceVertices.get(cp.deviceId());
+                edges.add(new DomainEdge(domainVertex, deviceVertex, cp));
+                edges.add(new DomainEdge(deviceVertex, domainVertex, cp));
+            });
+        });
+
+        vertices.addAll(deviceVertices.values());
+        //FIXME verify graph integrity...
+        return new AdjacencyListsGraph<>(vertices, edges);
+    }
+
+    @Deactivate
+    protected void deactivate() {
+        configService.removeListener(cfgListener);
+        log.info("Stopped");
+    }
+
+    @Override
+    public IntentDomain getDomain(IntentDomainId id) {
+        return domains.get(id);
+    }
+
+    @Override
+    public Set<IntentDomain> getDomains() {
+        return ImmutableSet.copyOf(domains.values());
+    }
+
+    @Override
+    public Set<IntentDomain> getDomains(DeviceId deviceId) {
+        return domains.values().stream()
+                .filter(domain ->
+                                domain.internalDevices().contains(deviceId) ||
+                                domain.edgePorts().stream()
+                                        .map(ConnectPoint::deviceId)
+                                        .anyMatch(d -> d.equals(deviceId)))
+                .collect(Collectors.toSet());
+    }
+
+    @Override
+    public Graph<DomainVertex, DomainEdge> getDomainGraph() {
+        return graph;
+    }
+
+    @Override
+    public void addListener(IntentDomainListener listener) {
+        //TODO slide in AbstractListenerManager
+    }
+
+    @Override
+    public void removeListener(IntentDomainListener listener) {
+        //TODO slide in AbstractListenerManager
+    }
+
+    @Override
+    public void registerApplication(ApplicationId applicationId, IntentDomainProvider provider) {
+        appToDomain.get(applicationId.name()).forEach(d -> domains.get(d).setProvider(provider));
+    }
+
+    @Override
+    public void unregisterApplication(ApplicationId applicationId) {
+        appToDomain.get(applicationId.name()).forEach(d -> domains.get(d).unsetProvider());
+    }
+
+    private class InternalConfigListener implements NetworkConfigListener {
+        @Override
+        public void event(NetworkConfigEvent event) {
+            switch (event.type()) {
+                case CONFIG_ADDED:
+                case CONFIG_UPDATED:
+                    processConfig((IntentDomainId) event.subject());
+                    graph = buildGraph();
+                    log.debug("Graph: {}", graph);
+                    break;
+
+                case CONFIG_REGISTERED:
+                case CONFIG_UNREGISTERED:
+                case CONFIG_REMOVED:
+                default:
+                    //TODO
+                    break;
+            }
+        }
+
+        @Override
+        public boolean isRelevant(NetworkConfigEvent event) {
+            return event.configClass().equals(IntentDomainConfig.class);
+        }
+    }
+}
diff --git a/incubator/net/src/test/resources/domain-config.json b/incubator/net/src/test/resources/domain-config.json
new file mode 100644
index 0000000..beda11a
--- /dev/null
+++ b/incubator/net/src/test/resources/domain-config.json
@@ -0,0 +1,36 @@
+{
+  "domains" : {
+    "cord" : {
+      "basic" : {
+        "name" : "Core Fabric",
+        "applicationName" : "org.onosproject.testdomain",
+        "internalDevices" : [ "of:1" ],
+        "edgePorts" : [ "of:12/1", "of:14/1" ]
+      }
+    },
+    "mpls" : {
+      "basic" : {
+        "name" : "MPLS Core",
+        "applicationName" : "org.onosproject.testdomain",
+        "internalDevices" : [ "of:2" ],
+        "edgePorts" : [ "of:12/2", "of:23/2" ]
+      }
+    },
+    "dc" : {
+      "basic" : {
+        "name" : "Data Center Fabric",
+        "applicationName" : "org.onosproject.testdomain",
+        "internalDevices" : [ "of:3" ],
+        "edgePorts" : [ "of:23/3", "of:34/3" ]
+      }
+    },
+    "optical" : {
+      "basic" : {
+        "name" : "Optical Core",
+        "applicationName" : "org.onosproject.testdomain",
+        "internalDevices" : [ "of:4" ],
+        "edgePorts" : [ "of:14/4", "of:34/4" ]
+      }
+    }
+  }
+}
\ No newline at end of file