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