ONOS-4489 - Initial ICONA provider development

- Southbound APIs definition
- Stubs of implementation classes

Change-Id: I5a9b76510ea8d6b43fa615c94db191439555ddc2
diff --git a/icona/domainmgr/pom.xml b/icona/domainmgr/pom.xml
new file mode 100644
index 0000000..29e3f3c
--- /dev/null
+++ b/icona/domainmgr/pom.xml
@@ -0,0 +1,68 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  ~ 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.
+  -->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+    <parent>
+        <groupId>org.onosproject</groupId>
+        <artifactId>onos-icona</artifactId>
+        <version>1.7.0-SNAPSHOT</version>
+        <relativePath>../pom.xml</relativePath>
+    </parent>
+
+    <artifactId>onos-app-icona-domain-manager</artifactId>
+    <packaging>bundle</packaging>
+
+
+    <description>Inter Cluster Onos Network App</description>
+
+    <properties>
+        <onos.app.name>org.onosproject.icona.domainmgr</onos.app.name>
+    </properties>
+
+
+    <dependencies>
+        <dependency>
+            <groupId>org.osgi</groupId>
+            <artifactId>org.osgi.compendium</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>org.onosproject</groupId>
+            <artifactId>onos-api</artifactId>
+            <version>${onos.version}</version>
+        </dependency>
+
+        <dependency>
+            <groupId>org.onosproject</groupId>
+            <artifactId>onos-core-serializers</artifactId>
+            <version>${onos.version}</version>
+        </dependency>
+
+        <dependency>
+            <groupId>org.onosproject</groupId>
+            <artifactId>onlab-osgi</artifactId>
+            <version>${onos.version}</version>
+        </dependency>
+
+        <dependency>
+            <groupId>org.onosproject</groupId>
+            <artifactId>onlab-misc</artifactId>
+            <version>${onos.version}</version>
+        </dependency>
+
+    </dependencies>
+</project>
diff --git a/icona/domainmgr/src/main/java/org/onosproject/icona/domainmgr/api/DomainEvent.java b/icona/domainmgr/src/main/java/org/onosproject/icona/domainmgr/api/DomainEvent.java
new file mode 100644
index 0000000..0ac8358
--- /dev/null
+++ b/icona/domainmgr/src/main/java/org/onosproject/icona/domainmgr/api/DomainEvent.java
@@ -0,0 +1,48 @@
+/*
+ * 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.icona.domainmgr.api;
+
+import org.onosproject.event.AbstractEvent;
+
+/**
+ * Domain event class. The event notifies the presence of a new domain or its disappearance.
+ * Apps can listen for such events and then retrieve the domain topologies through {@link DomainService}
+ */
+public class DomainEvent extends AbstractEvent<DomainEvent.Type, DomainId> {
+
+    /**
+     * Domain event type.
+     */
+    public enum Type {
+
+        /**
+         * Indicates that a new domain ID has been added to the distributed store.
+         */
+        DOMAIN_ADDED,
+
+        /**
+         * Indicates that a domain ID has been removed from the store.
+         */
+        DOMAIN_REMOVED
+
+        // TODO: other state-related event types
+    }
+
+    public DomainEvent(DomainEvent.Type type, DomainId domainId) {
+        super(type, domainId);
+    }
+}
diff --git a/icona/domainmgr/src/main/java/org/onosproject/icona/domainmgr/api/DomainId.java b/icona/domainmgr/src/main/java/org/onosproject/icona/domainmgr/api/DomainId.java
new file mode 100644
index 0000000..e031952
--- /dev/null
+++ b/icona/domainmgr/src/main/java/org/onosproject/icona/domainmgr/api/DomainId.java
@@ -0,0 +1,44 @@
+/*
+ * 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.icona.domainmgr.api;
+
+import org.onlab.util.Identifier;
+
+/**
+ * Representation of a peer domain.
+ */
+public class DomainId extends Identifier<String> {
+
+    /**
+     * Constructor of the peer id.
+     *
+     * @param identifier of the peer
+     */
+    public DomainId(String identifier) {
+        super(identifier);
+    }
+
+    /**
+     * Creates a peer id from the string identifier.
+     *
+     * @param identifier string identifier
+     * @return instance of the class DomainId
+     */
+    public static DomainId domainId(String identifier) {
+        return new DomainId(identifier);
+    }
+}
\ No newline at end of file
diff --git a/icona/domainmgr/src/main/java/org/onosproject/icona/domainmgr/api/DomainListener.java b/icona/domainmgr/src/main/java/org/onosproject/icona/domainmgr/api/DomainListener.java
new file mode 100644
index 0000000..6094ff8
--- /dev/null
+++ b/icona/domainmgr/src/main/java/org/onosproject/icona/domainmgr/api/DomainListener.java
@@ -0,0 +1,26 @@
+/*
+ * 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.icona.domainmgr.api;
+
+import org.onosproject.event.EventListener;
+
+/**
+ * Listeners for domain events. Currently we handle the addition and remotion of a domain.
+ * Domain topology elements events can be sensed through existing Device, Host, Link listener
+ */
+public interface DomainListener extends EventListener<DomainEvent> {
+}
diff --git a/icona/domainmgr/src/main/java/org/onosproject/icona/domainmgr/api/DomainService.java b/icona/domainmgr/src/main/java/org/onosproject/icona/domainmgr/api/DomainService.java
new file mode 100644
index 0000000..4ccaf6a
--- /dev/null
+++ b/icona/domainmgr/src/main/java/org/onosproject/icona/domainmgr/api/DomainService.java
@@ -0,0 +1,93 @@
+/*
+ * 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.icona.domainmgr.api;
+
+import org.apache.commons.lang3.tuple.Pair;
+import org.onosproject.net.Device;
+import org.onosproject.net.DeviceId;
+import org.onosproject.net.Host;
+import org.onosproject.net.HostId;
+import org.onosproject.net.Link;
+
+import java.util.Set;
+
+/**
+ * Service to access domain topology elements.
+ */
+public interface DomainService {
+
+    /**
+     * Adds a new domain id to the store.
+     * @param domainId domain identifier
+     */
+    void registerDomainId(DomainId domainId);
+
+    /**
+     * Removes the specified domain id from the store.
+     * @param domainId domain identifier
+     */
+    void unregisterDomainId(DomainId domainId);
+
+    /**
+     * Returns the set of domains that have an associated topology.
+     *
+     * @return set of domain identifiers
+     */
+    Set<DomainId> getDomainIds();
+
+    /**
+     * Returns the set of the devices of the specified domain.
+     *
+     * @param domainId domain identifier
+     * @return set of device objects
+     */
+    Set<DeviceId> getDeviceIds(DomainId domainId);
+
+    /**
+     * Gets all the devices of the specified domain.
+     * @param domainId domain identifier.
+     * @return set of devices
+     */
+    Set<Device> getDevices(DomainId domainId);
+
+    /**
+     * Returns the set of hosts of the specified domain.
+     * @param domainId domain id
+     * @return set of host objects
+     */
+    Set<HostId> getHostIds(DomainId domainId);
+
+    /**
+     * Gets the hosts of the specified domain.
+     * @param domainId domain id
+     * @return set of host objects
+     */
+    Set<Host> getHosts(DomainId domainId);
+
+    /**
+     * Gets the list of interlinks between the specified domains.
+     * @return set of interlinks
+     */
+    Set<Link> getInterLinks(Pair<DomainId, DomainId> endDomains);
+
+    /**
+     * Gets the list of links within a domain.
+     * @param domainId domain id
+     * @return set of intra-domain link
+     */
+    Set<Link> getIntraLinks(DomainId domainId);
+}
diff --git a/icona/domainmgr/src/main/java/org/onosproject/icona/domainmgr/api/DomainStore.java b/icona/domainmgr/src/main/java/org/onosproject/icona/domainmgr/api/DomainStore.java
new file mode 100644
index 0000000..4501731
--- /dev/null
+++ b/icona/domainmgr/src/main/java/org/onosproject/icona/domainmgr/api/DomainStore.java
@@ -0,0 +1,114 @@
+/*
+ * 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.icona.domainmgr.api;
+
+import org.apache.commons.lang3.tuple.Pair;
+import org.onosproject.net.DeviceId;
+import org.onosproject.net.HostId;
+import org.onosproject.net.Link;
+import org.onosproject.store.Store;
+
+import java.util.Set;
+
+/**
+ * Domain store interface.
+ */
+public interface DomainStore extends Store<DomainEvent, DomainStoreDelegate> {
+
+    /**
+     * Returns the set of domains that have an associated topology.
+     * @return set of domain identifiers
+     */
+    Set<DomainId> getDomainIds();
+
+    /**
+     * Returns the set of the devices of the specified domain.
+     * @param domainId domain identifier
+     * @return set of device objects
+     */
+    Set<DeviceId> getDeviceIds(DomainId domainId);
+
+    //TODO: get the topology of the topologies of all domain
+
+    /**
+     * Adds a new domain ID to the store.
+     * @param domainId domain id
+     */
+    void addDomain(DomainId domainId);
+
+    /**
+     * Removes the specified domain ID from the store.
+     * @param domainId domain identifier
+     */
+    void removeDomain(DomainId domainId);
+
+    /**
+     * Adds a new device to the store.
+     * @param domainId domain ientifier
+     * @param deviceId device identifier
+     */
+    void addDevice(DomainId domainId, DeviceId deviceId);
+
+    /**
+     * Removes a device from the store.
+     * @param domainId domain identifier
+     * @param deviceId device identifier
+     */
+    void removeDevice(DomainId domainId, DeviceId deviceId);
+
+    /**
+     * Gets the set of host identifiers of the specified domain.
+     * @param domainId domain identifier
+     * @return set of host identifiers
+     */
+    Set<HostId> getHostIds(DomainId domainId);
+
+    /**
+     * Adds a host to the domain store.
+     * @param domainId domain identifier
+     * @param hostId host identifier
+     */
+    void addHost(DomainId domainId, HostId hostId);
+
+    /**
+     * Removes a host from a domain.
+     * @param domainId domain identifier
+     * @param hostId host identifier
+     */
+    void removeHost(DomainId domainId, HostId hostId);
+
+    /**
+     * Gets the set of interlinks having source port within the specified domains.
+     * @param endDomains end domains identifier
+     * @return set of links
+     */
+    Set<Link> getInterLinks(Pair<DomainId, DomainId> endDomains);
+
+    /**
+     * Adds an interlink to the store. Link source port is within the specified domain.
+     * @param endDomains end domains identifier
+     * @param link link object
+     */
+    void addOrUpdateInterLink(Pair<DomainId, DomainId> endDomains, Link link);
+
+    /**
+     * Removes an interlink from the store.
+     * @param endDomains end domain identifiers
+     * @param link link object
+     */
+    void removeInterLink(Pair<DomainId, DomainId> endDomains, Link link);
+}
diff --git a/icona/domainmgr/src/main/java/org/onosproject/icona/domainmgr/api/DomainStoreDelegate.java b/icona/domainmgr/src/main/java/org/onosproject/icona/domainmgr/api/DomainStoreDelegate.java
new file mode 100644
index 0000000..edb7d9a
--- /dev/null
+++ b/icona/domainmgr/src/main/java/org/onosproject/icona/domainmgr/api/DomainStoreDelegate.java
@@ -0,0 +1,27 @@
+/*
+ * 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.icona.domainmgr.api;
+
+
+import org.onosproject.store.StoreDelegate;
+
+/**
+ * Domain store delegate.
+ */
+public interface DomainStoreDelegate extends StoreDelegate<DomainEvent> {
+
+}
diff --git a/icona/domainmgr/src/main/java/org/onosproject/icona/domainmgr/api/package-info.java b/icona/domainmgr/src/main/java/org/onosproject/icona/domainmgr/api/package-info.java
new file mode 100644
index 0000000..32e1199
--- /dev/null
+++ b/icona/domainmgr/src/main/java/org/onosproject/icona/domainmgr/api/package-info.java
@@ -0,0 +1,20 @@
+/*
+ * 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.
+ */
+
+/**
+ * Icona manager APIs.
+ */
+package org.onosproject.icona.domainmgr.api;
\ No newline at end of file
diff --git a/icona/domainmgr/src/main/java/org/onosproject/icona/domainmgr/impl/DistributedDomainStore.java b/icona/domainmgr/src/main/java/org/onosproject/icona/domainmgr/impl/DistributedDomainStore.java
new file mode 100644
index 0000000..4c28802
--- /dev/null
+++ b/icona/domainmgr/src/main/java/org/onosproject/icona/domainmgr/impl/DistributedDomainStore.java
@@ -0,0 +1,280 @@
+/*
+ * 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.icona.domainmgr.impl;
+
+import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.Sets;
+import org.apache.commons.lang3.tuple.Pair;
+import org.apache.felix.scr.annotations.Activate;
+import org.apache.felix.scr.annotations.Deactivate;
+import org.apache.felix.scr.annotations.Reference;
+import org.apache.felix.scr.annotations.ReferenceCardinality;
+import org.onlab.util.Identifier;
+import org.onlab.util.KryoNamespace;
+import org.onosproject.icona.domainmgr.api.DomainId;
+import org.onosproject.icona.domainmgr.api.DomainEvent;
+import org.onosproject.icona.domainmgr.api.DomainStore;
+import org.onosproject.icona.domainmgr.api.DomainStoreDelegate;
+import org.onosproject.net.DeviceId;
+import org.onosproject.net.HostId;
+import org.onosproject.net.Link;
+import org.onosproject.store.AbstractStore;
+import org.onosproject.store.serializers.KryoNamespaces;
+import org.onosproject.store.service.StorageService;
+import org.onosproject.store.service.DistributedSet;
+import org.onosproject.store.service.ConsistentMap;
+import org.onosproject.store.service.SetEventListener;
+import org.onosproject.store.service.SetEvent;
+import org.onosproject.store.service.Serializer;
+
+import org.slf4j.Logger;
+
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+
+import static org.onosproject.icona.domainmgr.api.DomainEvent.Type;
+import static com.google.common.base.Preconditions.checkNotNull;
+import static com.google.common.base.Preconditions.checkState;
+
+import static org.onosproject.icona.domainmgr.api.DomainEvent.Type.DOMAIN_ADDED;
+import static org.onosproject.icona.domainmgr.api.DomainEvent.Type.DOMAIN_REMOVED;
+import static org.slf4j.LoggerFactory.getLogger;
+
+/**
+ * Distributed domain store implementation.
+ */
+public class DistributedDomainStore extends AbstractStore<DomainEvent, DomainStoreDelegate>
+        implements DomainStore {
+
+    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+    protected StorageService storageService;
+
+    private final Logger log = getLogger(getClass());
+
+    private DistributedSet<DomainId> domainIds;
+    private final SetEventListener<DomainId> domainIdSetEventListener = new InternalMapListener();
+
+    private ConsistentMap<DomainId, Set<DeviceId>> domainIdDeviceIdsConsistentMap;
+    private Map<DomainId, Set<DeviceId>> domainIdDeviceIdsMap;
+
+    private ConsistentMap<DomainId, Set<HostId>> domainIdHostsIdsConsistentMap;
+    private Map<DomainId, Set<HostId>> domainIdHostIdsMap;
+
+    private ConsistentMap<Pair<DomainId, DomainId>, Set<Link>> domainIdLinkSetConsistentMap;
+    private Map<Pair<DomainId, DomainId>, Set<Link>> domainIdLinkSetMap;
+
+    private static final Serializer SERIALIZER = Serializer
+            .using(new KryoNamespace.Builder().register(KryoNamespaces.API)
+                    .register(Identifier.class)
+                    .register(DomainId.class)
+                    .build());
+
+    @Activate
+    public void activate() {
+
+        domainIds = storageService.<DomainId>setBuilder()
+                .withSerializer(SERIALIZER)
+                .withName("onos-domainId")
+                .withRelaxedReadConsistency()
+                .build()
+                .asDistributedSet();
+        domainIds.addListener(domainIdSetEventListener);
+
+        domainIdDeviceIdsConsistentMap = storageService.<DomainId, Set<DeviceId>>consistentMapBuilder()
+                .withSerializer(SERIALIZER)
+                .withName("onos-domain-device-ids")
+                .withRelaxedReadConsistency()
+                .build();
+        domainIdDeviceIdsMap = domainIdDeviceIdsConsistentMap.asJavaMap();
+
+        domainIdHostsIdsConsistentMap = storageService.<DomainId, Set<HostId>>consistentMapBuilder()
+                .withSerializer(SERIALIZER)
+                .withName("onos-domain-host-ids")
+                .withRelaxedReadConsistency()
+                .build();
+        domainIdHostIdsMap = domainIdHostsIdsConsistentMap.asJavaMap();
+
+        domainIdLinkSetConsistentMap = storageService.<Pair<DomainId, DomainId>, Set<Link>>
+                consistentMapBuilder()
+                .withSerializer(SERIALIZER)
+                .withName("onos-domain-links")
+                .withRelaxedReadConsistency()
+                .build();
+        domainIdLinkSetMap = domainIdLinkSetConsistentMap.asJavaMap();
+
+        log.info("Started");
+
+    }
+
+    @Deactivate
+    public void deactivate() {
+        domainIds.removeListener(domainIdSetEventListener);
+        log.info("Stopped");
+
+    }
+
+    @Override
+    public Set<DomainId> getDomainIds() {
+        return ImmutableSet.copyOf(domainIds);
+    }
+
+    @Override
+    public Set<DeviceId> getDeviceIds(DomainId domainId) {
+        checkState(domainExists(domainId), "Domain id unknown");
+        return ImmutableSet.copyOf(domainIdDeviceIdsMap.get(domainId));
+    }
+
+    @Override
+    public void addDomain(DomainId domainId) {
+        domainIds.add(domainId);
+    }
+
+    @Override
+    public void removeDomain(DomainId domainId) {
+        domainIds.remove(domainId);
+        clear(domainId);
+    }
+
+    @Override
+    public void addDevice(DomainId domainId, DeviceId deviceId) {
+        checkState(domainExists(domainId), "Domain id unknown");
+        domainIdDeviceIdsMap.compute(domainId, (k, set) -> {
+            if (set == null) {
+               set = Sets.newConcurrentHashSet();
+            }
+            set.add(deviceId);
+            return set;
+        });
+    }
+
+    @Override
+    public void removeDevice(DomainId domainId, DeviceId deviceId) {
+        checkState(domainExists(domainId), "Domain id unknown");
+        domainIdDeviceIdsMap.computeIfPresent(domainId, (k, existingSet) -> {
+            if (existingSet.contains(deviceId)) {
+                existingSet.remove(deviceId);
+                return existingSet;
+            } else {
+                return existingSet;
+            }
+        });
+    }
+
+    @Override
+    public Set<HostId> getHostIds(DomainId domainId) {
+        checkState(domainExists(domainId), "Domain id unknown");
+        return ImmutableSet.copyOf(domainIdHostIdsMap.get(domainId));
+    }
+
+    @Override
+    public void addHost(DomainId domainId, HostId hostId) {
+        checkState(domainExists(domainId), "Domain id unknown");
+        domainIdHostIdsMap.compute(domainId, (k, set) -> {
+            if (set == null) {
+                set = Sets.newConcurrentHashSet();
+            }
+            set.add(hostId);
+            return set;
+        });
+    }
+
+    @Override
+    public void removeHost(DomainId domainId, HostId hostId) {
+        checkState(domainExists(domainId), "Domain id unknown");
+        domainIdHostIdsMap.computeIfPresent(domainId, (k, existingSet) -> {
+            if (existingSet.contains(hostId)) {
+                existingSet.remove(hostId);
+                return existingSet;
+            } else {
+                return existingSet;
+            }
+        });
+    }
+
+    @Override
+    public Set<Link> getInterLinks(Pair<DomainId, DomainId> endDomains) {
+        checkState(domainExists(endDomains.getLeft()), "Domain id unknown");
+        checkState(domainExists(endDomains.getRight()), "Domain id unknown");
+        return ImmutableSet.copyOf(domainIdLinkSetMap.get(endDomains));
+    }
+
+    @Override
+    public void addOrUpdateInterLink(Pair<DomainId, DomainId> endDomains, Link link) {
+        checkState(domainExists(endDomains.getLeft()), "Domain id unknown");
+        checkState(domainExists(endDomains.getRight()), "Domain id unknown");
+        domainIdLinkSetMap.compute(endDomains, (k, set) -> {
+           if (set == null) {
+               set = Sets.newConcurrentHashSet();
+           }
+           set.add(link);
+            return set;
+        });
+    }
+
+    @Override
+    public void removeInterLink(Pair<DomainId, DomainId> endDomains, Link link) {
+        checkState(domainExists(endDomains.getLeft()), "Domain id unknown");
+        checkState(domainExists(endDomains.getRight()), "Domain id unknown");
+        domainIdLinkSetMap.computeIfPresent(endDomains, (k, existingSet) -> {
+            if (existingSet.contains(link)) {
+                existingSet.remove(link);
+                return existingSet;
+            } else {
+                return existingSet;
+            }
+        });
+    }
+
+    private void clear(DomainId domainId) {
+        Set<Pair<DomainId, DomainId>> domainPairs = new HashSet<>();
+        // find all domains connected with the one to be removed and remove related links
+        domainIdLinkSetMap.keySet().forEach(endDomains -> {
+            if (endDomains.getLeft().equals(domainId) ||
+                    endDomains.getRight().equals(domainId)) {
+                domainPairs.add(endDomains);
+            }
+        });
+        domainPairs.forEach(pair -> domainIdLinkSetMap.remove(pair));
+        domainIdDeviceIdsMap.remove(domainId);
+        domainIdHostIdsMap.remove(domainId);
+    }
+
+    private class InternalMapListener implements SetEventListener<DomainId> {
+        @Override
+        public void event(SetEvent<DomainId> event) {
+            Type type;
+            switch (event.type()) {
+                case ADD:
+                    type = DOMAIN_ADDED;
+                    break;
+                case REMOVE:
+                    type = DOMAIN_REMOVED;
+                    break;
+                default:
+                    log.error("Unsupported event type: " + event.type());
+                    return;
+            }
+            notifyDelegate(new DomainEvent(type, event.entry()));
+        }
+    }
+
+    private boolean domainExists(DomainId domainId) {
+        checkNotNull(domainId, "domain identifier is null");
+        return domainIds.contains(domainId);
+    }
+}
\ No newline at end of file
diff --git a/icona/domainmgr/src/main/java/org/onosproject/icona/domainmgr/impl/DomainManager.java b/icona/domainmgr/src/main/java/org/onosproject/icona/domainmgr/impl/DomainManager.java
new file mode 100644
index 0000000..e554f59
--- /dev/null
+++ b/icona/domainmgr/src/main/java/org/onosproject/icona/domainmgr/impl/DomainManager.java
@@ -0,0 +1,246 @@
+/*
+ * 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.icona.domainmgr.impl;
+
+import com.google.common.collect.ImmutableSet;
+import org.apache.commons.lang3.tuple.Pair;
+import org.apache.felix.scr.annotations.Component;
+import org.apache.felix.scr.annotations.Service;
+import org.apache.felix.scr.annotations.Activate;
+import org.apache.felix.scr.annotations.Deactivate;
+import org.apache.felix.scr.annotations.ReferenceCardinality;
+import org.apache.felix.scr.annotations.Reference;
+import org.onosproject.event.AbstractListenerManager;
+import org.onosproject.icona.domainmgr.api.DomainEvent;
+import org.onosproject.icona.domainmgr.api.DomainListener;
+import org.onosproject.icona.domainmgr.api.DomainService;
+import org.onosproject.icona.domainmgr.api.DomainStore;
+import org.onosproject.icona.domainmgr.api.DomainStoreDelegate;
+import org.onosproject.icona.domainmgr.api.DomainId;
+import org.onosproject.net.HostId;
+import org.onosproject.net.Host;
+import org.onosproject.net.DeviceId;
+import org.onosproject.net.Link;
+import org.onosproject.net.Device;
+import org.onosproject.net.device.DeviceEvent;
+import org.onosproject.net.device.DeviceListener;
+import org.onosproject.net.device.DeviceService;
+import org.onosproject.net.host.HostEvent;
+import org.onosproject.net.host.HostListener;
+import org.onosproject.net.host.HostService;
+import org.onosproject.net.link.LinkEvent;
+import org.onosproject.net.link.LinkListener;
+import org.onosproject.net.link.LinkService;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.HashSet;
+import java.util.Set;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+/**
+ * Exposes domain topology elements and listen for updates of such elements.
+ */
+@Component(immediate = true)
+@Service
+public class DomainManager extends AbstractListenerManager<DomainEvent, DomainListener>
+        implements DomainService {
+
+    private final Logger log = LoggerFactory.getLogger(getClass());
+    private static final String DOMAIN_ID = "domainId";
+    private static final String SRC_DOMAIN_ID = "srcDomainId";
+    private static final String DST_DOMAIN_ID = "dstDomainId";
+
+    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+    protected DomainStore domainStore;
+
+    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+    protected DeviceService deviceService;
+
+    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+    protected HostService hostService;
+
+    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+    protected LinkService linkService;
+
+    protected DomainStoreDelegate delegate = this::post;
+
+    private final DeviceListener deviceListener = new InternalDeviceListener();
+    private final HostListener hostListener = new InternalHostListener();
+    private final LinkListener linkListener = new InternalLinkListener();
+
+    @Activate
+    public void activate() {
+        deviceService.addListener(deviceListener);
+        hostService.addListener(hostListener);
+        linkService.addListener(linkListener);
+        domainStore.setDelegate(delegate);
+        log.info("Started");
+    }
+
+    @Deactivate
+    public void deactivate() {
+        deviceService.removeListener(deviceListener);
+        hostService.removeListener(hostListener);
+        linkService.removeListener(linkListener);
+        domainStore.unsetDelegate(delegate);
+        log.info("Stopped");
+    }
+
+    @Override
+    public void registerDomainId(DomainId domainId) {
+        checkNotNull(domainId);
+        domainStore.addDomain(domainId);
+    }
+
+    @Override
+    public void unregisterDomainId(DomainId domainId) {
+        checkNotNull(domainId);
+        domainStore.removeDomain(domainId);
+    }
+
+    @Override
+    public Set<DomainId> getDomainIds() {
+        return domainStore.getDomainIds();
+    }
+
+    @Override
+    public Set<DeviceId> getDeviceIds(DomainId domainId) {
+        return domainStore.getDeviceIds(domainId);
+    }
+
+    @Override
+    public Set<Device> getDevices(DomainId domainId) {
+        Set<DeviceId> deviceIds = domainStore.getDeviceIds(domainId);
+        Set<Device> devices = new HashSet<>();
+        deviceService.getDevices().forEach(device -> {
+            if (deviceIds.contains(device.id())) {
+                devices.add(device);
+            }
+        });
+        return ImmutableSet.copyOf(devices);
+    }
+
+    @Override
+    public Set<HostId> getHostIds(DomainId domainId) {
+        return domainStore.getHostIds(domainId);
+    }
+
+    @Override
+    public Set<Host> getHosts(DomainId domainId) {
+        Set<HostId> hostIds = domainStore.getHostIds(domainId);
+        Set<Host> hosts = new HashSet<>();
+        hostService.getHosts().forEach(host -> {
+            if (hostIds.contains(host.id())) {
+                hosts.add(host);
+            }
+        });
+        return ImmutableSet.copyOf(hosts);
+    }
+
+    @Override
+    public Set<Link> getInterLinks(Pair<DomainId, DomainId> endDomains) {
+        return domainStore.getInterLinks(endDomains);
+    }
+
+    @Override
+    public Set<Link> getIntraLinks(DomainId domainId) {
+        Set<Device> domDevices = getDevices(domainId);
+        Set<Link> intralinks = new HashSet<>();
+        domDevices.forEach(device -> {
+            Set<Link> devLinks = linkService.getDeviceLinks(device.id());
+            devLinks.forEach(link -> {
+                if (!link.annotations().keys().contains(SRC_DOMAIN_ID)) {
+                    intralinks.add(link);
+                }
+            });
+        });
+        return ImmutableSet.copyOf(intralinks);
+    }
+
+    private class InternalDeviceListener implements DeviceListener {
+        @Override
+        public void event(DeviceEvent event) {
+            Device device = event.subject();
+            if (!device.annotations().keys().contains(DOMAIN_ID)) {
+                return;
+            }
+            DomainId domainId = DomainId.domainId(
+                    device.annotations().value(DOMAIN_ID));
+            switch (event.type()) {
+                case DEVICE_ADDED:
+                    domainStore.addDevice(domainId, device.id());
+                    break;
+                case DEVICE_REMOVED:
+                    domainStore.removeDevice(domainId, device.id());
+                    break;
+                default:
+                    log.error("Unsupported event type: " + event.type());
+            }
+        }
+    }
+
+    private class InternalHostListener implements HostListener {
+        @Override
+        public void event(HostEvent event) {
+            Host host = event.subject();
+            if (!host.annotations().keys().contains(DOMAIN_ID)) {
+                return;
+            }
+            DomainId domainId = DomainId.domainId(
+                    host.annotations().value(DOMAIN_ID));
+            switch (event.type()) {
+                case HOST_ADDED:
+                    domainStore.addHost(domainId, host.id());
+                    break;
+                case HOST_REMOVED:
+                    domainStore.removeHost(domainId, host.id());
+                    break;
+                default:
+                    log.error("Unsupported event type: " + event.type());
+            }
+        }
+    }
+
+    private class InternalLinkListener implements LinkListener {
+        @Override
+        public void event(LinkEvent event) {
+            Link link = event.subject();
+            if (!link.annotations().keys().contains(SRC_DOMAIN_ID) ||
+                    !link.annotations().keys().contains(DST_DOMAIN_ID)) {
+                return;
+            }
+            DomainId srcDomainId = DomainId.domainId(
+                    link.annotations().value(SRC_DOMAIN_ID));
+            DomainId dstDomainId = DomainId.domainId(
+                    link.annotations().value(DST_DOMAIN_ID));
+            Pair<DomainId, DomainId> endDomains = Pair.of(srcDomainId, dstDomainId);
+            switch (event.type()) {
+                case LINK_ADDED:
+                case LINK_UPDATED:
+                    domainStore.addOrUpdateInterLink(endDomains, link);
+                    break;
+                case LINK_REMOVED:
+                    domainStore.removeInterLink(endDomains, link);
+                    break;
+                default:
+                    log.error("Unsupported event type: " + event.type());
+            }
+        }
+    }
+}
\ No newline at end of file
diff --git a/icona/domainmgr/src/main/java/org/onosproject/icona/domainmgr/impl/package-info.java b/icona/domainmgr/src/main/java/org/onosproject/icona/domainmgr/impl/package-info.java
new file mode 100644
index 0000000..5f9144e
--- /dev/null
+++ b/icona/domainmgr/src/main/java/org/onosproject/icona/domainmgr/impl/package-info.java
@@ -0,0 +1,20 @@
+/*
+ * 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.
+ */
+
+/**
+ * Icona manager implementation.
+ */
+package org.onosproject.icona.domainmgr.impl;
\ No newline at end of file