Introducing concept of a physical or logical region to facilitate
support of geographically distributed cluster and to lay ground for multiple/filtered topology layouts. Added implementation of manager and store; unit-tests included. Change-Id: Ia01673a0b711b8785c0ea68768552c2f61d7ea6d
Showing
22 changed files
with
1678 additions
and
83 deletions
| ... | @@ -15,14 +15,19 @@ | ... | @@ -15,14 +15,19 @@ |
| 15 | */ | 15 | */ |
| 16 | package org.onosproject.cluster; | 16 | package org.onosproject.cluster; |
| 17 | 17 | ||
| 18 | -import java.util.Objects; | 18 | +import org.onlab.util.Identifier; |
| 19 | 19 | ||
| 20 | /** | 20 | /** |
| 21 | * Controller cluster identity. | 21 | * Controller cluster identity. |
| 22 | */ | 22 | */ |
| 23 | -public class NodeId implements Comparable<NodeId> { | 23 | +public final class NodeId extends Identifier<String> implements Comparable<NodeId> { |
| 24 | 24 | ||
| 25 | - private final String id; | 25 | + /** |
| 26 | + * Constructor for serialization. | ||
| 27 | + */ | ||
| 28 | + private NodeId() { | ||
| 29 | + super(""); | ||
| 30 | + } | ||
| 26 | 31 | ||
| 27 | /** | 32 | /** |
| 28 | * Creates a new cluster node identifier from the specified string. | 33 | * Creates a new cluster node identifier from the specified string. |
| ... | @@ -30,34 +35,22 @@ public class NodeId implements Comparable<NodeId> { | ... | @@ -30,34 +35,22 @@ public class NodeId implements Comparable<NodeId> { |
| 30 | * @param id string identifier | 35 | * @param id string identifier |
| 31 | */ | 36 | */ |
| 32 | public NodeId(String id) { | 37 | public NodeId(String id) { |
| 33 | - this.id = id; | 38 | + super(id); |
| 34 | - } | ||
| 35 | - | ||
| 36 | - @Override | ||
| 37 | - public int hashCode() { | ||
| 38 | - return id.hashCode(); | ||
| 39 | } | 39 | } |
| 40 | 40 | ||
| 41 | - @Override | 41 | + /** |
| 42 | - public boolean equals(Object obj) { | 42 | + * Creates a new cluster node identifier from the specified string. |
| 43 | - if (this == obj) { | 43 | + * |
| 44 | - return true; | 44 | + * @param id string identifier |
| 45 | - } | 45 | + * @return node id |
| 46 | - if (obj instanceof NodeId) { | 46 | + */ |
| 47 | - final NodeId other = (NodeId) obj; | 47 | + public static NodeId nodeId(String id) { |
| 48 | - return Objects.equals(this.id, other.id); | 48 | + return new NodeId(id); |
| 49 | - } | ||
| 50 | - return false; | ||
| 51 | - } | ||
| 52 | - | ||
| 53 | - @Override | ||
| 54 | - public String toString() { | ||
| 55 | - return id; | ||
| 56 | } | 49 | } |
| 57 | 50 | ||
| 58 | @Override | 51 | @Override |
| 59 | public int compareTo(NodeId that) { | 52 | public int compareTo(NodeId that) { |
| 60 | - return this.id.compareTo(that.id); | 53 | + return identifier.compareTo(that.identifier); |
| 61 | } | 54 | } |
| 62 | 55 | ||
| 63 | } | 56 | } | ... | ... |
| ... | @@ -16,21 +16,18 @@ | ... | @@ -16,21 +16,18 @@ |
| 16 | 16 | ||
| 17 | package org.onosproject.net.key; | 17 | package org.onosproject.net.key; |
| 18 | 18 | ||
| 19 | -import java.util.Objects; | 19 | +import org.onlab.util.Identifier; |
| 20 | - | ||
| 21 | -import static com.google.common.base.Preconditions.checkNotNull; | ||
| 22 | 20 | ||
| 23 | /** | 21 | /** |
| 24 | - * Device key Id definition. | 22 | + * Device key identifier backed by a string value. |
| 25 | */ | 23 | */ |
| 26 | -public final class DeviceKeyId { | 24 | +public final class DeviceKeyId extends Identifier<String> { |
| 27 | - private final String identifier; | ||
| 28 | 25 | ||
| 29 | /** | 26 | /** |
| 30 | * Constructor for serialization. | 27 | * Constructor for serialization. |
| 31 | */ | 28 | */ |
| 32 | private DeviceKeyId() { | 29 | private DeviceKeyId() { |
| 33 | - this.identifier = null; | 30 | + super(); |
| 34 | } | 31 | } |
| 35 | 32 | ||
| 36 | /** | 33 | /** |
| ... | @@ -39,63 +36,17 @@ public final class DeviceKeyId { | ... | @@ -39,63 +36,17 @@ public final class DeviceKeyId { |
| 39 | * @param value the underlying value of this ID | 36 | * @param value the underlying value of this ID |
| 40 | */ | 37 | */ |
| 41 | private DeviceKeyId(String value) { | 38 | private DeviceKeyId(String value) { |
| 42 | - this.identifier = checkNotNull(value, "Device Key Id cannot be null."); | 39 | + super(value); |
| 43 | } | 40 | } |
| 44 | 41 | ||
| 45 | /** | 42 | /** |
| 46 | - * Static method to construct a device key identifier. | 43 | + * Creates a new device key identifier. |
| 47 | * | 44 | * |
| 48 | - * @param id for the device key identifier | 45 | + * @param id backing identifier value |
| 49 | * @return device key identifier | 46 | * @return device key identifier |
| 50 | */ | 47 | */ |
| 51 | - public static final DeviceKeyId deviceKeyId(String id) { | 48 | + public static DeviceKeyId deviceKeyId(String id) { |
| 52 | return new DeviceKeyId(id); | 49 | return new DeviceKeyId(id); |
| 53 | } | 50 | } |
| 54 | 51 | ||
| 55 | - /** | ||
| 56 | - * Returns the identifier of the device key identifier. | ||
| 57 | - * | ||
| 58 | - * @return identifier | ||
| 59 | - */ | ||
| 60 | - public String id() { | ||
| 61 | - return identifier; | ||
| 62 | - } | ||
| 63 | - | ||
| 64 | - /** | ||
| 65 | - * Returns the hashcode of the identifier. | ||
| 66 | - * | ||
| 67 | - * @return hashcode | ||
| 68 | - */ | ||
| 69 | - @Override | ||
| 70 | - public int hashCode() { | ||
| 71 | - return identifier.hashCode(); | ||
| 72 | - } | ||
| 73 | - | ||
| 74 | - /** | ||
| 75 | - * Compares two device key identifiers for equality. | ||
| 76 | - * | ||
| 77 | - * @param obj to compare against | ||
| 78 | - * @return true if the objects are equal, false otherwise. | ||
| 79 | - */ | ||
| 80 | - @Override | ||
| 81 | - public boolean equals(Object obj) { | ||
| 82 | - if (this == obj) { | ||
| 83 | - return true; | ||
| 84 | - } | ||
| 85 | - if (obj instanceof DeviceKeyId) { | ||
| 86 | - final DeviceKeyId that = (DeviceKeyId) obj; | ||
| 87 | - return this.getClass() == that.getClass() && | ||
| 88 | - Objects.equals(this.identifier, that.identifier); | ||
| 89 | - } | ||
| 90 | - return false; | ||
| 91 | - } | ||
| 92 | - | ||
| 93 | - /** | ||
| 94 | - * Returns a string representation of a DeviceKeyId. | ||
| 95 | - * | ||
| 96 | - * @return string | ||
| 97 | - */ | ||
| 98 | - public String toString() { | ||
| 99 | - return identifier; | ||
| 100 | - } | ||
| 101 | } | 52 | } | ... | ... |
| 1 | +/* | ||
| 2 | + * Copyright 2016 Open Networking Laboratory | ||
| 3 | + * | ||
| 4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | ||
| 5 | + * you may not use this file except in compliance with the License. | ||
| 6 | + * You may obtain a copy of the License at | ||
| 7 | + * | ||
| 8 | + * http://www.apache.org/licenses/LICENSE-2.0 | ||
| 9 | + * | ||
| 10 | + * Unless required by applicable law or agreed to in writing, software | ||
| 11 | + * distributed under the License is distributed on an "AS IS" BASIS, | ||
| 12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
| 13 | + * See the License for the specific language governing permissions and | ||
| 14 | + * limitations under the License. | ||
| 15 | + */ | ||
| 16 | + | ||
| 17 | +package org.onosproject.net.region; | ||
| 18 | + | ||
| 19 | +import com.google.common.base.MoreObjects; | ||
| 20 | +import com.google.common.collect.ImmutableList; | ||
| 21 | +import org.onosproject.cluster.NodeId; | ||
| 22 | + | ||
| 23 | +import java.util.List; | ||
| 24 | +import java.util.Objects; | ||
| 25 | +import java.util.Set; | ||
| 26 | + | ||
| 27 | +/** | ||
| 28 | + * Default implementation of a region. | ||
| 29 | + */ | ||
| 30 | +public final class DefaultRegion implements Region { | ||
| 31 | + | ||
| 32 | + private final RegionId id; | ||
| 33 | + private final String name; | ||
| 34 | + private final Type type; | ||
| 35 | + private final List<Set<NodeId>> masters; | ||
| 36 | + | ||
| 37 | + /** | ||
| 38 | + * Creates a region using the supplied information. | ||
| 39 | + * | ||
| 40 | + * @param id region identifier | ||
| 41 | + * @param name friendly name | ||
| 42 | + * @param type region type | ||
| 43 | + * @param masters list of sets of cluster node identifiers; in order of mastership | ||
| 44 | + */ | ||
| 45 | + public DefaultRegion(RegionId id, String name, Type type, List<Set<NodeId>> masters) { | ||
| 46 | + this.id = id; | ||
| 47 | + this.name = name; | ||
| 48 | + this.type = type; | ||
| 49 | + this.masters = masters != null ? ImmutableList.copyOf(masters) : ImmutableList.of(); | ||
| 50 | + } | ||
| 51 | + | ||
| 52 | + @Override | ||
| 53 | + public RegionId id() { | ||
| 54 | + return id; | ||
| 55 | + } | ||
| 56 | + | ||
| 57 | + @Override | ||
| 58 | + public String name() { | ||
| 59 | + return name; | ||
| 60 | + } | ||
| 61 | + | ||
| 62 | + @Override | ||
| 63 | + public Type type() { | ||
| 64 | + return type; | ||
| 65 | + } | ||
| 66 | + | ||
| 67 | + @Override | ||
| 68 | + public List<Set<NodeId>> masters() { | ||
| 69 | + return masters; | ||
| 70 | + } | ||
| 71 | + | ||
| 72 | + @Override | ||
| 73 | + public int hashCode() { | ||
| 74 | + return Objects.hash(id, name, type, masters); | ||
| 75 | + } | ||
| 76 | + | ||
| 77 | + @Override | ||
| 78 | + public boolean equals(Object obj) { | ||
| 79 | + if (this == obj) { | ||
| 80 | + return true; | ||
| 81 | + } | ||
| 82 | + if (obj instanceof DefaultRegion) { | ||
| 83 | + final DefaultRegion that = (DefaultRegion) obj; | ||
| 84 | + return Objects.equals(this.id, that.id) | ||
| 85 | + && Objects.equals(this.name, that.name) | ||
| 86 | + && Objects.equals(this.type, that.type) | ||
| 87 | + && Objects.equals(this.masters, that.masters); | ||
| 88 | + } | ||
| 89 | + return false; | ||
| 90 | + } | ||
| 91 | + | ||
| 92 | + @Override | ||
| 93 | + public String toString() { | ||
| 94 | + return MoreObjects.toStringHelper(this) | ||
| 95 | + .add("id", id) | ||
| 96 | + .add("name", name) | ||
| 97 | + .add("type", type) | ||
| 98 | + .add("masters", masters) | ||
| 99 | + .toString(); | ||
| 100 | + } | ||
| 101 | + | ||
| 102 | +} |
| 1 | +/* | ||
| 2 | + * Copyright 2016 Open Networking Laboratory | ||
| 3 | + * | ||
| 4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | ||
| 5 | + * you may not use this file except in compliance with the License. | ||
| 6 | + * You may obtain a copy of the License at | ||
| 7 | + * | ||
| 8 | + * http://www.apache.org/licenses/LICENSE-2.0 | ||
| 9 | + * | ||
| 10 | + * Unless required by applicable law or agreed to in writing, software | ||
| 11 | + * distributed under the License is distributed on an "AS IS" BASIS, | ||
| 12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
| 13 | + * See the License for the specific language governing permissions and | ||
| 14 | + * limitations under the License. | ||
| 15 | + */ | ||
| 16 | + | ||
| 17 | +package org.onosproject.net.region; | ||
| 18 | + | ||
| 19 | +import org.onosproject.cluster.NodeId; | ||
| 20 | + | ||
| 21 | +import java.util.List; | ||
| 22 | +import java.util.Set; | ||
| 23 | + | ||
| 24 | +/** | ||
| 25 | + * Representation of a group of devices located in a common physical or | ||
| 26 | + * logical region. Optionally, devices in the region can share the same | ||
| 27 | + * cluster nodes mastership affinities. | ||
| 28 | + */ | ||
| 29 | +public interface Region { | ||
| 30 | + | ||
| 31 | + /** | ||
| 32 | + * Coarse representation of the type of the region. | ||
| 33 | + */ | ||
| 34 | + enum Type { | ||
| 35 | + /** | ||
| 36 | + * Region represents an entire continent. | ||
| 37 | + */ | ||
| 38 | + CONTINENT, | ||
| 39 | + | ||
| 40 | + /** | ||
| 41 | + * Region represents an entire country. | ||
| 42 | + */ | ||
| 43 | + COUNTRY, | ||
| 44 | + | ||
| 45 | + /** | ||
| 46 | + * Region represents a metropolitan area. | ||
| 47 | + */ | ||
| 48 | + METRO, | ||
| 49 | + | ||
| 50 | + /** | ||
| 51 | + * Region represents a campus. | ||
| 52 | + */ | ||
| 53 | + CAMPUS, | ||
| 54 | + | ||
| 55 | + /** | ||
| 56 | + * Region represents a building. | ||
| 57 | + */ | ||
| 58 | + BUILDING, | ||
| 59 | + | ||
| 60 | + /** | ||
| 61 | + * Region represents a building floor. | ||
| 62 | + */ | ||
| 63 | + FLOOR, | ||
| 64 | + | ||
| 65 | + /** | ||
| 66 | + * Region represents a room. | ||
| 67 | + */ | ||
| 68 | + ROOM, | ||
| 69 | + | ||
| 70 | + /** | ||
| 71 | + * Region represents a rack. | ||
| 72 | + */ | ||
| 73 | + RACK, | ||
| 74 | + | ||
| 75 | + /** | ||
| 76 | + * Region represents a logical grouping. | ||
| 77 | + */ | ||
| 78 | + LOGICAL_GROUP | ||
| 79 | + } | ||
| 80 | + | ||
| 81 | + /** | ||
| 82 | + * Returns the unique identifier of the region. | ||
| 83 | + * | ||
| 84 | + * @return region identifier | ||
| 85 | + */ | ||
| 86 | + RegionId id(); | ||
| 87 | + | ||
| 88 | + /** | ||
| 89 | + * Returns the friendly region name that can be used for display purposes. | ||
| 90 | + * | ||
| 91 | + * @return friendly name of the region | ||
| 92 | + */ | ||
| 93 | + String name(); | ||
| 94 | + | ||
| 95 | + /** | ||
| 96 | + * Returns the region type. | ||
| 97 | + * | ||
| 98 | + * @return region type | ||
| 99 | + */ | ||
| 100 | + Type type(); | ||
| 101 | + | ||
| 102 | + /** | ||
| 103 | + * Returns the list of master node sets. The sets of cluster node identifiers | ||
| 104 | + * should be listed in the order of preferred mastership. Nodes specified | ||
| 105 | + * in each sets should be considered with equally priority and devices in | ||
| 106 | + * the region can be balanced between them based on other criteria, e.g. load. | ||
| 107 | + * | ||
| 108 | + * @return list of preferred master node sets | ||
| 109 | + */ | ||
| 110 | + List<Set<NodeId>> masters(); | ||
| 111 | + | ||
| 112 | +} |
| 1 | +/* | ||
| 2 | + * Copyright 2016 Open Networking Laboratory | ||
| 3 | + * | ||
| 4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | ||
| 5 | + * you may not use this file except in compliance with the License. | ||
| 6 | + * You may obtain a copy of the License at | ||
| 7 | + * | ||
| 8 | + * http://www.apache.org/licenses/LICENSE-2.0 | ||
| 9 | + * | ||
| 10 | + * Unless required by applicable law or agreed to in writing, software | ||
| 11 | + * distributed under the License is distributed on an "AS IS" BASIS, | ||
| 12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
| 13 | + * See the License for the specific language governing permissions and | ||
| 14 | + * limitations under the License. | ||
| 15 | + */ | ||
| 16 | + | ||
| 17 | +package org.onosproject.net.region; | ||
| 18 | + | ||
| 19 | +import org.onosproject.cluster.NodeId; | ||
| 20 | +import org.onosproject.net.DeviceId; | ||
| 21 | + | ||
| 22 | +import java.util.Collection; | ||
| 23 | +import java.util.List; | ||
| 24 | +import java.util.Set; | ||
| 25 | + | ||
| 26 | +/** | ||
| 27 | + * Service for interacting with inventory of network control regions. | ||
| 28 | + */ | ||
| 29 | +public interface RegionAdminService extends RegionService { | ||
| 30 | + | ||
| 31 | + /** | ||
| 32 | + * Creates a new region using the supplied data. | ||
| 33 | + * | ||
| 34 | + * @param regionId region identifier | ||
| 35 | + * @param name friendly name | ||
| 36 | + * @param type region type | ||
| 37 | + * @param masterNodeIds list of sets of master nodes; null implies empty list | ||
| 38 | + * @return new region descriptor | ||
| 39 | + * @throws IllegalArgumentException if region already exists | ||
| 40 | + */ | ||
| 41 | + Region createRegion(RegionId regionId, String name, Region.Type type, | ||
| 42 | + List<Set<NodeId>> masterNodeIds); | ||
| 43 | + | ||
| 44 | + /** | ||
| 45 | + * Update the specified region using the new set of data. | ||
| 46 | + * | ||
| 47 | + * @param regionId region identifier | ||
| 48 | + * @param name friendly name | ||
| 49 | + * @param type region type | ||
| 50 | + * @param masterNodeIds list of sets of master nodes; null implies empty list | ||
| 51 | + * @return new region descriptor | ||
| 52 | + */ | ||
| 53 | + Region updateRegion(RegionId regionId, String name, Region.Type type, | ||
| 54 | + List<Set<NodeId>> masterNodeIds); | ||
| 55 | + | ||
| 56 | + /** | ||
| 57 | + * Removes the specified region using the new set of data. | ||
| 58 | + * | ||
| 59 | + * @param regionId region identifier | ||
| 60 | + */ | ||
| 61 | + void removeRegion(RegionId regionId); | ||
| 62 | + | ||
| 63 | + /** | ||
| 64 | + * Adds the specified collection of devices to the region. | ||
| 65 | + * | ||
| 66 | + * @param regionId region identifier | ||
| 67 | + * @param deviceIds list of device identifiers | ||
| 68 | + */ | ||
| 69 | + void addDevices(RegionId regionId, Collection<DeviceId> deviceIds); | ||
| 70 | + | ||
| 71 | + /** | ||
| 72 | + * Removes the specified collection of devices from the region. | ||
| 73 | + * | ||
| 74 | + * @param regionId region identifier | ||
| 75 | + * @param deviceIds list of device identifiers | ||
| 76 | + */ | ||
| 77 | + void removeDevices(RegionId regionId, Collection<DeviceId> deviceIds); | ||
| 78 | + | ||
| 79 | +} |
| 1 | +/* | ||
| 2 | + * Copyright 2016 Open Networking Laboratory | ||
| 3 | + * | ||
| 4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | ||
| 5 | + * you may not use this file except in compliance with the License. | ||
| 6 | + * You may obtain a copy of the License at | ||
| 7 | + * | ||
| 8 | + * http://www.apache.org/licenses/LICENSE-2.0 | ||
| 9 | + * | ||
| 10 | + * Unless required by applicable law or agreed to in writing, software | ||
| 11 | + * distributed under the License is distributed on an "AS IS" BASIS, | ||
| 12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
| 13 | + * See the License for the specific language governing permissions and | ||
| 14 | + * limitations under the License. | ||
| 15 | + */ | ||
| 16 | + | ||
| 17 | +package org.onosproject.net.region; | ||
| 18 | + | ||
| 19 | +import com.google.common.collect.ImmutableSet; | ||
| 20 | +import org.onosproject.event.AbstractEvent; | ||
| 21 | +import org.onosproject.net.DeviceId; | ||
| 22 | + | ||
| 23 | +import java.util.Set; | ||
| 24 | + | ||
| 25 | +/** | ||
| 26 | + * Describes region event. | ||
| 27 | + */ | ||
| 28 | +public class RegionEvent extends AbstractEvent<RegionEvent.Type, Region> { | ||
| 29 | + | ||
| 30 | + private final Set<DeviceId> deviceIds; | ||
| 31 | + | ||
| 32 | + public enum Type { | ||
| 33 | + /** | ||
| 34 | + * Signifies that a new region was created. | ||
| 35 | + */ | ||
| 36 | + REGION_ADDED, | ||
| 37 | + | ||
| 38 | + /** | ||
| 39 | + * Signifies that a region was updated. | ||
| 40 | + */ | ||
| 41 | + REGION_REMOVED, | ||
| 42 | + | ||
| 43 | + /** | ||
| 44 | + * Signifies that a region was removed. | ||
| 45 | + */ | ||
| 46 | + REGION_UPDATED, | ||
| 47 | + | ||
| 48 | + /** | ||
| 49 | + * Signifies that a region device membership has changed. | ||
| 50 | + */ | ||
| 51 | + REGION_MEMBERSHIP_CHANGED | ||
| 52 | + } | ||
| 53 | + | ||
| 54 | + /** | ||
| 55 | + * Creates an event of a given type and for the specified region and the | ||
| 56 | + * current time. | ||
| 57 | + * | ||
| 58 | + * @param type device event type | ||
| 59 | + * @param region event region subject | ||
| 60 | + */ | ||
| 61 | + public RegionEvent(Type type, Region region) { | ||
| 62 | + this(type, region, null); | ||
| 63 | + } | ||
| 64 | + | ||
| 65 | + /** | ||
| 66 | + * Creates an event of a given type and for the specified region, device | ||
| 67 | + * id list and the current time. | ||
| 68 | + * | ||
| 69 | + * @param type device event type | ||
| 70 | + * @param region event region subject | ||
| 71 | + * @param deviceIds optional set of device ids | ||
| 72 | + */ | ||
| 73 | + public RegionEvent(Type type, Region region, Set<DeviceId> deviceIds) { | ||
| 74 | + super(type, region); | ||
| 75 | + this.deviceIds = deviceIds != null ? ImmutableSet.copyOf(deviceIds) : ImmutableSet.of(); | ||
| 76 | + } | ||
| 77 | + | ||
| 78 | + /** | ||
| 79 | + * Creates an event of a given type and for the specified device and time. | ||
| 80 | + * | ||
| 81 | + * @param type device event type | ||
| 82 | + * @param region event region subject | ||
| 83 | + * @param deviceIds optional set of device ids | ||
| 84 | + * @param time occurrence time | ||
| 85 | + */ | ||
| 86 | + public RegionEvent(Type type, Region region, Set<DeviceId> deviceIds, long time) { | ||
| 87 | + super(type, region, time); | ||
| 88 | + this.deviceIds = deviceIds != null ? ImmutableSet.copyOf(deviceIds) : ImmutableSet.of(); | ||
| 89 | + } | ||
| 90 | + | ||
| 91 | +} |
| 1 | +/* | ||
| 2 | + * Copyright 2016 Open Networking Laboratory | ||
| 3 | + * | ||
| 4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | ||
| 5 | + * you may not use this file except in compliance with the License. | ||
| 6 | + * You may obtain a copy of the License at | ||
| 7 | + * | ||
| 8 | + * http://www.apache.org/licenses/LICENSE-2.0 | ||
| 9 | + * | ||
| 10 | + * Unless required by applicable law or agreed to in writing, software | ||
| 11 | + * distributed under the License is distributed on an "AS IS" BASIS, | ||
| 12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
| 13 | + * See the License for the specific language governing permissions and | ||
| 14 | + * limitations under the License. | ||
| 15 | + */ | ||
| 16 | + | ||
| 17 | +package org.onosproject.net.region; | ||
| 18 | + | ||
| 19 | +import org.onlab.util.Identifier; | ||
| 20 | + | ||
| 21 | +/** | ||
| 22 | + * Region identifier backed by a string value. | ||
| 23 | + */ | ||
| 24 | +public final class RegionId extends Identifier<String> { | ||
| 25 | + | ||
| 26 | + /** | ||
| 27 | + * Constructor for serialization. | ||
| 28 | + */ | ||
| 29 | + private RegionId() { | ||
| 30 | + super(); | ||
| 31 | + } | ||
| 32 | + | ||
| 33 | + /** | ||
| 34 | + * Constructs the ID corresponding to a given string value. | ||
| 35 | + * | ||
| 36 | + * @param value the underlying value of this ID | ||
| 37 | + */ | ||
| 38 | + private RegionId(String value) { | ||
| 39 | + super(value); | ||
| 40 | + } | ||
| 41 | + | ||
| 42 | + /** | ||
| 43 | + * Creates a new region identifier. | ||
| 44 | + * | ||
| 45 | + * @param id backing identifier value | ||
| 46 | + * @return region identifier | ||
| 47 | + */ | ||
| 48 | + public static RegionId regionId(String id) { | ||
| 49 | + return new RegionId(id); | ||
| 50 | + } | ||
| 51 | + | ||
| 52 | +} |
| 1 | +/* | ||
| 2 | + * Copyright 2016 Open Networking Laboratory | ||
| 3 | + * | ||
| 4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | ||
| 5 | + * you may not use this file except in compliance with the License. | ||
| 6 | + * You may obtain a copy of the License at | ||
| 7 | + * | ||
| 8 | + * http://www.apache.org/licenses/LICENSE-2.0 | ||
| 9 | + * | ||
| 10 | + * Unless required by applicable law or agreed to in writing, software | ||
| 11 | + * distributed under the License is distributed on an "AS IS" BASIS, | ||
| 12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
| 13 | + * See the License for the specific language governing permissions and | ||
| 14 | + * limitations under the License. | ||
| 15 | + */ | ||
| 16 | +package org.onosproject.net.region; | ||
| 17 | + | ||
| 18 | +import org.onosproject.event.EventListener; | ||
| 19 | + | ||
| 20 | +/** | ||
| 21 | + * Entity capable of receiving region related events. | ||
| 22 | + */ | ||
| 23 | +public interface RegionListener extends EventListener<RegionEvent> { | ||
| 24 | +} |
| 1 | +/* | ||
| 2 | + * Copyright 2016 Open Networking Laboratory | ||
| 3 | + * | ||
| 4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | ||
| 5 | + * you may not use this file except in compliance with the License. | ||
| 6 | + * You may obtain a copy of the License at | ||
| 7 | + * | ||
| 8 | + * http://www.apache.org/licenses/LICENSE-2.0 | ||
| 9 | + * | ||
| 10 | + * Unless required by applicable law or agreed to in writing, software | ||
| 11 | + * distributed under the License is distributed on an "AS IS" BASIS, | ||
| 12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
| 13 | + * See the License for the specific language governing permissions and | ||
| 14 | + * limitations under the License. | ||
| 15 | + */ | ||
| 16 | + | ||
| 17 | +package org.onosproject.net.region; | ||
| 18 | + | ||
| 19 | +import org.onosproject.net.DeviceId; | ||
| 20 | + | ||
| 21 | +import java.util.Set; | ||
| 22 | + | ||
| 23 | +/** | ||
| 24 | + * Service for interacting with inventory of network control regions. | ||
| 25 | + */ | ||
| 26 | +public interface RegionService { | ||
| 27 | + | ||
| 28 | + /** | ||
| 29 | + * Returns set of all regions. | ||
| 30 | + * | ||
| 31 | + * @return set of regions | ||
| 32 | + */ | ||
| 33 | + Set<Region> getRegions(); | ||
| 34 | + | ||
| 35 | + /** | ||
| 36 | + * Returns the region with the specified identifier. | ||
| 37 | + * | ||
| 38 | + * @param regionId region identifier | ||
| 39 | + * @return region | ||
| 40 | + * @throws org.onlab.util.ItemNotFoundException if region with given | ||
| 41 | + * id does not exist | ||
| 42 | + */ | ||
| 43 | + Region getRegion(RegionId regionId); | ||
| 44 | + | ||
| 45 | + /** | ||
| 46 | + * Returns the region to which the specified device belongs. | ||
| 47 | + * | ||
| 48 | + * @param deviceId device identifier | ||
| 49 | + * @return region or null if device does not belong to any region | ||
| 50 | + */ | ||
| 51 | + Region getRegionForDevice(DeviceId deviceId); | ||
| 52 | + | ||
| 53 | + /** | ||
| 54 | + * Returns the set of devices that belong to the specified region. | ||
| 55 | + * | ||
| 56 | + * @param regionId region identifier | ||
| 57 | + * @return set of identifiers for devices in the given region | ||
| 58 | + */ | ||
| 59 | + Set<DeviceId> getRegionDevices(RegionId regionId); | ||
| 60 | + | ||
| 61 | +} |
| 1 | +/* | ||
| 2 | + * Copyright 2016 Open Networking Laboratory | ||
| 3 | + * | ||
| 4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | ||
| 5 | + * you may not use this file except in compliance with the License. | ||
| 6 | + * You may obtain a copy of the License at | ||
| 7 | + * | ||
| 8 | + * http://www.apache.org/licenses/LICENSE-2.0 | ||
| 9 | + * | ||
| 10 | + * Unless required by applicable law or agreed to in writing, software | ||
| 11 | + * distributed under the License is distributed on an "AS IS" BASIS, | ||
| 12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
| 13 | + * See the License for the specific language governing permissions and | ||
| 14 | + * limitations under the License. | ||
| 15 | + */ | ||
| 16 | +package org.onosproject.net.region; | ||
| 17 | + | ||
| 18 | +import org.onosproject.cluster.NodeId; | ||
| 19 | +import org.onosproject.net.DeviceId; | ||
| 20 | +import org.onosproject.store.Store; | ||
| 21 | + | ||
| 22 | +import java.util.Collection; | ||
| 23 | +import java.util.List; | ||
| 24 | +import java.util.Set; | ||
| 25 | + | ||
| 26 | +/** | ||
| 27 | + * Manages inventory of regions of devices; not intended for direct use. | ||
| 28 | + */ | ||
| 29 | +public interface RegionStore extends Store<RegionEvent, RegionStoreDelegate> { | ||
| 30 | + | ||
| 31 | + /** | ||
| 32 | + * Returns set of all regions. | ||
| 33 | + * | ||
| 34 | + * @return set of regions | ||
| 35 | + */ | ||
| 36 | + Set<Region> getRegions(); | ||
| 37 | + | ||
| 38 | + /** | ||
| 39 | + * Returns the region with the specified identifier. | ||
| 40 | + * | ||
| 41 | + * @param regionId region identifier | ||
| 42 | + * @return region | ||
| 43 | + * @throws org.onlab.util.ItemNotFoundException if region with given | ||
| 44 | + * id does not exist | ||
| 45 | + */ | ||
| 46 | + Region getRegion(RegionId regionId); | ||
| 47 | + | ||
| 48 | + /** | ||
| 49 | + * Returns the region to which the specified device belongs. | ||
| 50 | + * | ||
| 51 | + * @param deviceId device identifier | ||
| 52 | + * @return region or null if device does not belong to any region | ||
| 53 | + */ | ||
| 54 | + Region getRegionForDevice(DeviceId deviceId); | ||
| 55 | + | ||
| 56 | + /** | ||
| 57 | + * Returns the set of devices that belong to the specified region. | ||
| 58 | + * | ||
| 59 | + * @param regionId region identifier | ||
| 60 | + * @return set of identifiers for devices in the given region | ||
| 61 | + */ | ||
| 62 | + Set<DeviceId> getRegionDevices(RegionId regionId); | ||
| 63 | + | ||
| 64 | + /** | ||
| 65 | + * Creates a new region using the supplied data. | ||
| 66 | + * | ||
| 67 | + * @param regionId region identifier | ||
| 68 | + * @param name friendly name | ||
| 69 | + * @param type region type | ||
| 70 | + * @param masterNodeIds list of master nodes; null implies empty list | ||
| 71 | + * @return new region descriptor | ||
| 72 | + * @throws IllegalArgumentException if item already exists | ||
| 73 | + */ | ||
| 74 | + Region createRegion(RegionId regionId, String name, Region.Type type, | ||
| 75 | + List<Set<NodeId>> masterNodeIds); | ||
| 76 | + | ||
| 77 | + /** | ||
| 78 | + * Updates the specified new region using the supplied data. | ||
| 79 | + * | ||
| 80 | + * @param regionId region identifier | ||
| 81 | + * @param name friendly name | ||
| 82 | + * @param type region type | ||
| 83 | + * @param masterNodeIds list of master nodes; null implies empty list | ||
| 84 | + * @return new region descriptor | ||
| 85 | + * @throws IllegalArgumentException if item already exists | ||
| 86 | + */ | ||
| 87 | + Region updateRegion(RegionId regionId, String name, Region.Type type, | ||
| 88 | + List<Set<NodeId>> masterNodeIds); | ||
| 89 | + | ||
| 90 | + /** | ||
| 91 | + * Removes the specified region using the new set of data. | ||
| 92 | + * | ||
| 93 | + * @param regionId region identifier | ||
| 94 | + */ | ||
| 95 | + void removeRegion(RegionId regionId); | ||
| 96 | + | ||
| 97 | + /** | ||
| 98 | + * Adds the specified collection of devices to the region. | ||
| 99 | + * | ||
| 100 | + * @param regionId region identifier | ||
| 101 | + * @param deviceIds list of device identifiers | ||
| 102 | + */ | ||
| 103 | + void addDevices(RegionId regionId, Collection<DeviceId> deviceIds); | ||
| 104 | + | ||
| 105 | + /** | ||
| 106 | + * Removes the specified collection of devices from the region. | ||
| 107 | + * | ||
| 108 | + * @param regionId region identifier | ||
| 109 | + * @param deviceIds list of device identifiers | ||
| 110 | + */ | ||
| 111 | + void removeDevices(RegionId regionId, Collection<DeviceId> deviceIds); | ||
| 112 | + | ||
| 113 | +} |
| 1 | +/* | ||
| 2 | + * Copyright 2016 Open Networking Laboratory | ||
| 3 | + * | ||
| 4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | ||
| 5 | + * you may not use this file except in compliance with the License. | ||
| 6 | + * You may obtain a copy of the License at | ||
| 7 | + * | ||
| 8 | + * http://www.apache.org/licenses/LICENSE-2.0 | ||
| 9 | + * | ||
| 10 | + * Unless required by applicable law or agreed to in writing, software | ||
| 11 | + * distributed under the License is distributed on an "AS IS" BASIS, | ||
| 12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
| 13 | + * See the License for the specific language governing permissions and | ||
| 14 | + * limitations under the License. | ||
| 15 | + */ | ||
| 16 | +package org.onosproject.net.region; | ||
| 17 | + | ||
| 18 | +import org.onosproject.store.StoreDelegate; | ||
| 19 | + | ||
| 20 | +/** | ||
| 21 | + * Region store delegate abstraction. | ||
| 22 | + */ | ||
| 23 | +public interface RegionStoreDelegate extends StoreDelegate<RegionEvent> { | ||
| 24 | +} |
| 1 | +/* | ||
| 2 | + * Copyright 2016 Open Networking Laboratory | ||
| 3 | + * | ||
| 4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | ||
| 5 | + * you may not use this file except in compliance with the License. | ||
| 6 | + * You may obtain a copy of the License at | ||
| 7 | + * | ||
| 8 | + * http://www.apache.org/licenses/LICENSE-2.0 | ||
| 9 | + * | ||
| 10 | + * Unless required by applicable law or agreed to in writing, software | ||
| 11 | + * distributed under the License is distributed on an "AS IS" BASIS, | ||
| 12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
| 13 | + * See the License for the specific language governing permissions and | ||
| 14 | + * limitations under the License. | ||
| 15 | + */ | ||
| 16 | + | ||
| 17 | +/** | ||
| 18 | + * Subsystem for tracking inventory of network control regions. | ||
| 19 | + */ | ||
| 20 | +package org.onosproject.net.region; | ||
| ... | \ No newline at end of file | ... | \ No newline at end of file |
| 1 | +/* | ||
| 2 | + * Copyright 2014-2016 Open Networking Laboratory | ||
| 3 | + * | ||
| 4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | ||
| 5 | + * you may not use this file except in compliance with the License. | ||
| 6 | + * You may obtain a copy of the License at | ||
| 7 | + * | ||
| 8 | + * http://www.apache.org/licenses/LICENSE-2.0 | ||
| 9 | + * | ||
| 10 | + * Unless required by applicable law or agreed to in writing, software | ||
| 11 | + * distributed under the License is distributed on an "AS IS" BASIS, | ||
| 12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
| 13 | + * See the License for the specific language governing permissions and | ||
| 14 | + * limitations under the License. | ||
| 15 | + */ | ||
| 16 | + | ||
| 17 | +package org.onosproject.net.region; | ||
| 18 | + | ||
| 19 | +import com.google.common.collect.ImmutableList; | ||
| 20 | +import com.google.common.collect.ImmutableSet; | ||
| 21 | +import com.google.common.testing.EqualsTester; | ||
| 22 | +import org.junit.Test; | ||
| 23 | +import org.onosproject.cluster.NodeId; | ||
| 24 | + | ||
| 25 | +import java.util.Set; | ||
| 26 | + | ||
| 27 | +import static org.junit.Assert.assertEquals; | ||
| 28 | +import static org.onosproject.cluster.NodeId.nodeId; | ||
| 29 | +import static org.onosproject.net.region.Region.Type.METRO; | ||
| 30 | + | ||
| 31 | +/** | ||
| 32 | + * Suite of tests of the default region implementation. | ||
| 33 | + */ | ||
| 34 | +public class DefaultRegionTest { | ||
| 35 | + | ||
| 36 | + private static final RegionId ID1 = RegionId.regionId("r1"); | ||
| 37 | + | ||
| 38 | + @Test | ||
| 39 | + public void basics() { | ||
| 40 | + ImmutableList<Set<NodeId>> masters = ImmutableList | ||
| 41 | + .of(ImmutableSet.of(nodeId("n1"), nodeId("n2")), | ||
| 42 | + ImmutableSet.of(nodeId("n3"), nodeId("n4"))); | ||
| 43 | + Region r = new DefaultRegion(ID1, "R1", METRO, masters); | ||
| 44 | + assertEquals("incorrect id", ID1, r.id()); | ||
| 45 | + assertEquals("incorrect name", "R1", r.name()); | ||
| 46 | + assertEquals("incorrect type", METRO, r.type()); | ||
| 47 | + assertEquals("incorrect masters", masters, r.masters()); | ||
| 48 | + } | ||
| 49 | + | ||
| 50 | + @Test | ||
| 51 | + public void equality() { | ||
| 52 | + Region a = new DefaultRegion(ID1, "R1", METRO, null); | ||
| 53 | + Region b = new DefaultRegion(ID1, "R1", METRO, null); | ||
| 54 | + Region c = new DefaultRegion(ID1, "R2", METRO, null); | ||
| 55 | + | ||
| 56 | + new EqualsTester().addEqualityGroup(a, b).addEqualityGroup(c).testEquals(); | ||
| 57 | + } | ||
| 58 | + | ||
| 59 | +} | ||
| ... | \ No newline at end of file | ... | \ No newline at end of file |
| 1 | +/* | ||
| 2 | + * Copyright 2016 Open Networking Laboratory | ||
| 3 | + * | ||
| 4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | ||
| 5 | + * you may not use this file except in compliance with the License. | ||
| 6 | + * You may obtain a copy of the License at | ||
| 7 | + * | ||
| 8 | + * http://www.apache.org/licenses/LICENSE-2.0 | ||
| 9 | + * | ||
| 10 | + * Unless required by applicable law or agreed to in writing, software | ||
| 11 | + * distributed under the License is distributed on an "AS IS" BASIS, | ||
| 12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
| 13 | + * See the License for the specific language governing permissions and | ||
| 14 | + * limitations under the License. | ||
| 15 | + */ | ||
| 16 | + | ||
| 17 | +package org.onosproject.net.region.impl; | ||
| 18 | + | ||
| 19 | +import org.apache.felix.scr.annotations.Activate; | ||
| 20 | +import org.apache.felix.scr.annotations.Deactivate; | ||
| 21 | +import org.apache.felix.scr.annotations.Reference; | ||
| 22 | +import org.apache.felix.scr.annotations.ReferenceCardinality; | ||
| 23 | +import org.onosproject.cluster.NodeId; | ||
| 24 | +import org.onosproject.event.AbstractListenerManager; | ||
| 25 | +import org.onosproject.net.DeviceId; | ||
| 26 | +import org.onosproject.net.region.Region; | ||
| 27 | +import org.onosproject.net.region.RegionAdminService; | ||
| 28 | +import org.onosproject.net.region.RegionEvent; | ||
| 29 | +import org.onosproject.net.region.RegionId; | ||
| 30 | +import org.onosproject.net.region.RegionListener; | ||
| 31 | +import org.onosproject.net.region.RegionService; | ||
| 32 | +import org.onosproject.net.region.RegionStore; | ||
| 33 | +import org.onosproject.net.region.RegionStoreDelegate; | ||
| 34 | +import org.slf4j.Logger; | ||
| 35 | + | ||
| 36 | +import java.util.Collection; | ||
| 37 | +import java.util.List; | ||
| 38 | +import java.util.Set; | ||
| 39 | + | ||
| 40 | +import static com.google.common.base.Preconditions.checkNotNull; | ||
| 41 | +import static com.google.common.base.Preconditions.checkState; | ||
| 42 | +import static com.google.common.collect.ImmutableList.of; | ||
| 43 | +import static org.slf4j.LoggerFactory.getLogger; | ||
| 44 | + | ||
| 45 | +/** | ||
| 46 | + * Provides implementation of the region service APIs. | ||
| 47 | + */ | ||
| 48 | +public class RegionManager extends AbstractListenerManager<RegionEvent, RegionListener> | ||
| 49 | + implements RegionAdminService, RegionService { | ||
| 50 | + | ||
| 51 | + private static final String REGION_ID_NULL = "Region ID cannot be null"; | ||
| 52 | + private static final String REGION_TYPE_NULL = "Region type cannot be null"; | ||
| 53 | + private static final String DEVICE_ID_NULL = "Device ID cannot be null"; | ||
| 54 | + private static final String DEVICE_IDS_NULL = "Device IDs cannot be null"; | ||
| 55 | + private static final String DEVICE_IDS_EMPTY = "Device IDs cannot be empty"; | ||
| 56 | + private static final String NAME_NULL = "Name cannot be null"; | ||
| 57 | + | ||
| 58 | + private final Logger log = getLogger(getClass()); | ||
| 59 | + | ||
| 60 | + private RegionStoreDelegate delegate = this::post; | ||
| 61 | + | ||
| 62 | + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) | ||
| 63 | + protected RegionStore store; | ||
| 64 | + | ||
| 65 | + @Activate | ||
| 66 | + public void activate() { | ||
| 67 | + store.setDelegate(delegate); | ||
| 68 | + eventDispatcher.addSink(RegionEvent.class, listenerRegistry); | ||
| 69 | + log.info("Started"); | ||
| 70 | + } | ||
| 71 | + | ||
| 72 | + @Deactivate | ||
| 73 | + public void deactivate() { | ||
| 74 | + store.unsetDelegate(delegate); | ||
| 75 | + eventDispatcher.removeSink(RegionEvent.class); | ||
| 76 | + log.info("Stopped"); | ||
| 77 | + } | ||
| 78 | + | ||
| 79 | + @Override | ||
| 80 | + public Region createRegion(RegionId regionId, String name, Region.Type type, | ||
| 81 | + List<Set<NodeId>> masterNodeIds) { | ||
| 82 | + checkNotNull(regionId, REGION_ID_NULL); | ||
| 83 | + checkNotNull(name, NAME_NULL); | ||
| 84 | + checkNotNull(name, REGION_TYPE_NULL); | ||
| 85 | + return store.createRegion(regionId, name, type, masterNodeIds == null ? of() : masterNodeIds); | ||
| 86 | + } | ||
| 87 | + | ||
| 88 | + @Override | ||
| 89 | + public Region updateRegion(RegionId regionId, String name, Region.Type type, | ||
| 90 | + List<Set<NodeId>> masterNodeIds) { | ||
| 91 | + checkNotNull(regionId, REGION_ID_NULL); | ||
| 92 | + checkNotNull(name, NAME_NULL); | ||
| 93 | + checkNotNull(name, REGION_TYPE_NULL); | ||
| 94 | + return store.updateRegion(regionId, name, type, masterNodeIds == null ? of() : masterNodeIds); | ||
| 95 | + } | ||
| 96 | + | ||
| 97 | + @Override | ||
| 98 | + public void removeRegion(RegionId regionId) { | ||
| 99 | + checkNotNull(regionId, REGION_ID_NULL); | ||
| 100 | + store.removeRegion(regionId); | ||
| 101 | + } | ||
| 102 | + | ||
| 103 | + @Override | ||
| 104 | + public void addDevices(RegionId regionId, Collection<DeviceId> deviceIds) { | ||
| 105 | + checkNotNull(regionId, REGION_ID_NULL); | ||
| 106 | + checkNotNull(deviceIds, DEVICE_IDS_NULL); | ||
| 107 | + checkState(!deviceIds.isEmpty(), DEVICE_IDS_EMPTY); | ||
| 108 | + store.addDevices(regionId, deviceIds); | ||
| 109 | + } | ||
| 110 | + | ||
| 111 | + @Override | ||
| 112 | + public void removeDevices(RegionId regionId, Collection<DeviceId> deviceIds) { | ||
| 113 | + checkNotNull(regionId, REGION_ID_NULL); | ||
| 114 | + checkNotNull(deviceIds, DEVICE_IDS_NULL); | ||
| 115 | + checkState(!deviceIds.isEmpty(), DEVICE_IDS_EMPTY); | ||
| 116 | + store.removeDevices(regionId, deviceIds); | ||
| 117 | + } | ||
| 118 | + | ||
| 119 | + @Override | ||
| 120 | + public Set<Region> getRegions() { | ||
| 121 | + return store.getRegions(); | ||
| 122 | + } | ||
| 123 | + | ||
| 124 | + @Override | ||
| 125 | + public Region getRegion(RegionId regionId) { | ||
| 126 | + checkNotNull(regionId, REGION_ID_NULL); | ||
| 127 | + return store.getRegion(regionId); | ||
| 128 | + } | ||
| 129 | + | ||
| 130 | + @Override | ||
| 131 | + public Region getRegionForDevice(DeviceId deviceId) { | ||
| 132 | + checkNotNull(deviceId, DEVICE_ID_NULL); | ||
| 133 | + return store.getRegionForDevice(deviceId); | ||
| 134 | + } | ||
| 135 | + | ||
| 136 | + @Override | ||
| 137 | + public Set<DeviceId> getRegionDevices(RegionId regionId) { | ||
| 138 | + checkNotNull(regionId, REGION_ID_NULL); | ||
| 139 | + return store.getRegionDevices(regionId); | ||
| 140 | + } | ||
| 141 | + | ||
| 142 | +} |
| 1 | +/* | ||
| 2 | + * Copyright 2016 Open Networking Laboratory | ||
| 3 | + * | ||
| 4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | ||
| 5 | + * you may not use this file except in compliance with the License. | ||
| 6 | + * You may obtain a copy of the License at | ||
| 7 | + * | ||
| 8 | + * http://www.apache.org/licenses/LICENSE-2.0 | ||
| 9 | + * | ||
| 10 | + * Unless required by applicable law or agreed to in writing, software | ||
| 11 | + * distributed under the License is distributed on an "AS IS" BASIS, | ||
| 12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
| 13 | + * See the License for the specific language governing permissions and | ||
| 14 | + * limitations under the License. | ||
| 15 | + */ | ||
| 16 | + | ||
| 17 | +/** | ||
| 18 | + * Core subsystem for managing region definitions. | ||
| 19 | + */ | ||
| 20 | +package org.onosproject.net.region.impl; | ||
| ... | \ No newline at end of file | ... | \ No newline at end of file |
| 1 | +/* | ||
| 2 | + * Copyright 2016 Open Networking Laboratory | ||
| 3 | + * | ||
| 4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | ||
| 5 | + * you may not use this file except in compliance with the License. | ||
| 6 | + * You may obtain a copy of the License at | ||
| 7 | + * | ||
| 8 | + * http://www.apache.org/licenses/LICENSE-2.0 | ||
| 9 | + * | ||
| 10 | + * Unless required by applicable law or agreed to in writing, software | ||
| 11 | + * distributed under the License is distributed on an "AS IS" BASIS, | ||
| 12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
| 13 | + * See the License for the specific language governing permissions and | ||
| 14 | + * limitations under the License. | ||
| 15 | + */ | ||
| 16 | + | ||
| 17 | +package org.onosproject.net.region.impl; | ||
| 18 | + | ||
| 19 | +import com.google.common.collect.ImmutableList; | ||
| 20 | +import com.google.common.collect.ImmutableSet; | ||
| 21 | +import org.junit.After; | ||
| 22 | +import org.junit.Before; | ||
| 23 | +import org.junit.Test; | ||
| 24 | +import org.onlab.junit.TestUtils; | ||
| 25 | +import org.onlab.util.ItemNotFoundException; | ||
| 26 | +import org.onosproject.cluster.NodeId; | ||
| 27 | +import org.onosproject.common.event.impl.TestEventDispatcher; | ||
| 28 | +import org.onosproject.net.DeviceId; | ||
| 29 | +import org.onosproject.net.NetTestTools; | ||
| 30 | +import org.onosproject.net.region.Region; | ||
| 31 | +import org.onosproject.net.region.RegionAdminService; | ||
| 32 | +import org.onosproject.net.region.RegionEvent; | ||
| 33 | +import org.onosproject.net.region.RegionId; | ||
| 34 | +import org.onosproject.net.region.RegionListener; | ||
| 35 | +import org.onosproject.store.region.impl.DistributedRegionStore; | ||
| 36 | +import org.onosproject.store.service.TestStorageService; | ||
| 37 | + | ||
| 38 | +import java.util.List; | ||
| 39 | +import java.util.Set; | ||
| 40 | + | ||
| 41 | +import static org.junit.Assert.*; | ||
| 42 | +import static org.onosproject.net.region.Region.Type.*; | ||
| 43 | +import static org.onosproject.net.region.RegionEvent.Type.*; | ||
| 44 | + | ||
| 45 | +/** | ||
| 46 | + * Tests of the region service implementation. | ||
| 47 | + */ | ||
| 48 | +public class RegionManagerTest { | ||
| 49 | + | ||
| 50 | + private static final RegionId RID1 = RegionId.regionId("r1"); | ||
| 51 | + private static final RegionId RID2 = RegionId.regionId("r2"); | ||
| 52 | + | ||
| 53 | + private static final DeviceId DID1 = DeviceId.deviceId("foo:d1"); | ||
| 54 | + private static final DeviceId DID2 = DeviceId.deviceId("foo:d2"); | ||
| 55 | + private static final DeviceId DID3 = DeviceId.deviceId("foo:d3"); | ||
| 56 | + | ||
| 57 | + private static final NodeId NID1 = NodeId.nodeId("n1"); | ||
| 58 | + | ||
| 59 | + private static final List<Set<NodeId>> MASTERS = ImmutableList.of(ImmutableSet.of(NID1)); | ||
| 60 | + | ||
| 61 | + private TestManager manager = new TestManager(); | ||
| 62 | + private RegionAdminService service; | ||
| 63 | + private TestStore store = new TestStore(); | ||
| 64 | + private TestListener listener = new TestListener(); | ||
| 65 | + | ||
| 66 | + @Before | ||
| 67 | + public void setUp() throws Exception { | ||
| 68 | + TestUtils.setField(store, "storageService", new TestStorageService()); | ||
| 69 | + store.activate(); | ||
| 70 | + | ||
| 71 | + manager.store = store; | ||
| 72 | + manager.addListener(listener); | ||
| 73 | + NetTestTools.injectEventDispatcher(manager, new TestEventDispatcher()); | ||
| 74 | + manager.activate(); | ||
| 75 | + service = manager; | ||
| 76 | + } | ||
| 77 | + | ||
| 78 | + @After | ||
| 79 | + public void tearDown() { | ||
| 80 | + store.deactivate(); | ||
| 81 | + manager.removeListener(listener); | ||
| 82 | + manager.deactivate(); | ||
| 83 | + NetTestTools.injectEventDispatcher(manager, null); | ||
| 84 | + } | ||
| 85 | + | ||
| 86 | + @Test | ||
| 87 | + public void basics() { | ||
| 88 | + Region r1 = service.createRegion(RID1, "R1", METRO, MASTERS); | ||
| 89 | + assertEquals("incorrect id", RID1, r1.id()); | ||
| 90 | + assertEquals("incorrect event", REGION_ADDED, listener.event.type()); | ||
| 91 | + | ||
| 92 | + Region r2 = service.createRegion(RID2, "R2", CAMPUS, MASTERS); | ||
| 93 | + assertEquals("incorrect id", RID2, r2.id()); | ||
| 94 | + assertEquals("incorrect type", CAMPUS, r2.type()); | ||
| 95 | + assertEquals("incorrect event", REGION_ADDED, listener.event.type()); | ||
| 96 | + | ||
| 97 | + r2 = service.updateRegion(RID2, "R2", COUNTRY, MASTERS); | ||
| 98 | + assertEquals("incorrect type", COUNTRY, r2.type()); | ||
| 99 | + assertEquals("incorrect event", REGION_UPDATED, listener.event.type()); | ||
| 100 | + | ||
| 101 | + Set<Region> regions = service.getRegions(); | ||
| 102 | + assertEquals("incorrect size", 2, regions.size()); | ||
| 103 | + assertTrue("missing r1", regions.contains(r1)); | ||
| 104 | + assertTrue("missing r2", regions.contains(r2)); | ||
| 105 | + | ||
| 106 | + r1 = service.getRegion(RID1); | ||
| 107 | + assertEquals("incorrect id", RID1, r1.id()); | ||
| 108 | + | ||
| 109 | + service.removeRegion(RID1); | ||
| 110 | + regions = service.getRegions(); | ||
| 111 | + assertEquals("incorrect size", 1, regions.size()); | ||
| 112 | + assertTrue("missing r2", regions.contains(r2)); | ||
| 113 | + assertEquals("incorrect event", REGION_REMOVED, listener.event.type()); | ||
| 114 | + } | ||
| 115 | + | ||
| 116 | + @Test(expected = IllegalArgumentException.class) | ||
| 117 | + public void duplicateCreate() { | ||
| 118 | + service.createRegion(RID1, "R1", METRO, MASTERS); | ||
| 119 | + service.createRegion(RID1, "R2", CAMPUS, MASTERS); | ||
| 120 | + } | ||
| 121 | + | ||
| 122 | + @Test(expected = ItemNotFoundException.class) | ||
| 123 | + public void missingUpdate() { | ||
| 124 | + service.updateRegion(RID1, "R1", METRO, MASTERS); | ||
| 125 | + } | ||
| 126 | + | ||
| 127 | + @Test | ||
| 128 | + public void membership() { | ||
| 129 | + Region r = service.createRegion(RID1, "R1", METRO, MASTERS); | ||
| 130 | + assertTrue("no devices expected", service.getRegionDevices(RID1).isEmpty()); | ||
| 131 | + assertNull("no region expected", service.getRegionForDevice(DID1)); | ||
| 132 | + | ||
| 133 | + service.addDevices(RID1, ImmutableSet.of(DID1, DID2)); | ||
| 134 | + Set<DeviceId> deviceIds = service.getRegionDevices(RID1); | ||
| 135 | + assertEquals("incorrect device count", 2, deviceIds.size()); | ||
| 136 | + assertTrue("missing d1", deviceIds.contains(DID1)); | ||
| 137 | + assertTrue("missing d2", deviceIds.contains(DID2)); | ||
| 138 | + assertEquals("wrong region", r, service.getRegionForDevice(DID1)); | ||
| 139 | + assertEquals("incorrect event", REGION_MEMBERSHIP_CHANGED, listener.event.type()); | ||
| 140 | + | ||
| 141 | + service.addDevices(RID1, ImmutableSet.of(DID3)); | ||
| 142 | + deviceIds = service.getRegionDevices(RID1); | ||
| 143 | + assertEquals("incorrect device count", 3, deviceIds.size()); | ||
| 144 | + assertTrue("missing d3", deviceIds.contains(DID3)); | ||
| 145 | + assertEquals("incorrect event", REGION_MEMBERSHIP_CHANGED, listener.event.type()); | ||
| 146 | + | ||
| 147 | + service.addDevices(RID1, ImmutableSet.of(DID3, DID1)); | ||
| 148 | + deviceIds = service.getRegionDevices(RID1); | ||
| 149 | + assertEquals("incorrect device count", 3, deviceIds.size()); | ||
| 150 | + | ||
| 151 | + service.removeDevices(RID1, ImmutableSet.of(DID2, DID3)); | ||
| 152 | + deviceIds = service.getRegionDevices(RID1); | ||
| 153 | + assertEquals("incorrect device count", 1, deviceIds.size()); | ||
| 154 | + assertTrue("missing d1", deviceIds.contains(DID1)); | ||
| 155 | + | ||
| 156 | + service.removeDevices(RID1, ImmutableSet.of(DID1, DID3)); | ||
| 157 | + assertTrue("no devices expected", service.getRegionDevices(RID1).isEmpty()); | ||
| 158 | + | ||
| 159 | + service.removeDevices(RID1, ImmutableSet.of(DID2)); | ||
| 160 | + assertTrue("no devices expected", service.getRegionDevices(RID1).isEmpty()); | ||
| 161 | + } | ||
| 162 | + | ||
| 163 | + private class TestStore extends DistributedRegionStore { | ||
| 164 | + @Override | ||
| 165 | + protected void activate() { | ||
| 166 | + super.activate(); | ||
| 167 | + } | ||
| 168 | + | ||
| 169 | + @Override | ||
| 170 | + protected void deactivate() { | ||
| 171 | + super.deactivate(); | ||
| 172 | + } | ||
| 173 | + } | ||
| 174 | + | ||
| 175 | + private class TestManager extends RegionManager { | ||
| 176 | + TestManager() { | ||
| 177 | + eventDispatcher = new TestEventDispatcher(); | ||
| 178 | + } | ||
| 179 | + } | ||
| 180 | + | ||
| 181 | + private class TestListener implements RegionListener { | ||
| 182 | + RegionEvent event; | ||
| 183 | + | ||
| 184 | + @Override | ||
| 185 | + public void event(RegionEvent event) { | ||
| 186 | + this.event = event; | ||
| 187 | + } | ||
| 188 | + } | ||
| 189 | +} | ||
| ... | \ No newline at end of file | ... | \ No newline at end of file |
core/store/dist/src/main/java/org/onosproject/store/region/impl/DistributedRegionStore.java
0 → 100644
| 1 | +/* | ||
| 2 | + * Copyright 2016 Open Networking Laboratory | ||
| 3 | + * | ||
| 4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | ||
| 5 | + * you may not use this file except in compliance with the License. | ||
| 6 | + * You may obtain a copy of the License at | ||
| 7 | + * | ||
| 8 | + * http://www.apache.org/licenses/LICENSE-2.0 | ||
| 9 | + * | ||
| 10 | + * Unless required by applicable law or agreed to in writing, software | ||
| 11 | + * distributed under the License is distributed on an "AS IS" BASIS, | ||
| 12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
| 13 | + * See the License for the specific language governing permissions and | ||
| 14 | + * limitations under the License. | ||
| 15 | + */ | ||
| 16 | + | ||
| 17 | +package org.onosproject.store.region.impl; | ||
| 18 | + | ||
| 19 | +import com.google.common.collect.ImmutableSet; | ||
| 20 | +import com.google.common.collect.Sets; | ||
| 21 | +import org.apache.felix.scr.annotations.Activate; | ||
| 22 | +import org.apache.felix.scr.annotations.Component; | ||
| 23 | +import org.apache.felix.scr.annotations.Deactivate; | ||
| 24 | +import org.apache.felix.scr.annotations.Reference; | ||
| 25 | +import org.apache.felix.scr.annotations.ReferenceCardinality; | ||
| 26 | +import org.apache.felix.scr.annotations.Service; | ||
| 27 | +import org.onlab.util.Identifier; | ||
| 28 | +import org.onosproject.cluster.NodeId; | ||
| 29 | +import org.onosproject.net.DeviceId; | ||
| 30 | +import org.onosproject.net.region.DefaultRegion; | ||
| 31 | +import org.onosproject.net.region.Region; | ||
| 32 | +import org.onosproject.net.region.RegionEvent; | ||
| 33 | +import org.onosproject.net.region.RegionId; | ||
| 34 | +import org.onosproject.net.region.RegionStore; | ||
| 35 | +import org.onosproject.net.region.RegionStoreDelegate; | ||
| 36 | +import org.onosproject.store.AbstractStore; | ||
| 37 | +import org.onosproject.store.serializers.KryoNamespaces; | ||
| 38 | +import org.onosproject.store.service.ConsistentMap; | ||
| 39 | +import org.onosproject.store.service.MapEvent; | ||
| 40 | +import org.onosproject.store.service.MapEventListener; | ||
| 41 | +import org.onosproject.store.service.Serializer; | ||
| 42 | +import org.onosproject.store.service.StorageService; | ||
| 43 | +import org.slf4j.Logger; | ||
| 44 | + | ||
| 45 | +import java.util.Arrays; | ||
| 46 | +import java.util.Collection; | ||
| 47 | +import java.util.HashMap; | ||
| 48 | +import java.util.List; | ||
| 49 | +import java.util.Map; | ||
| 50 | +import java.util.Set; | ||
| 51 | + | ||
| 52 | +import static com.google.common.base.Preconditions.checkArgument; | ||
| 53 | +import static com.google.common.base.Preconditions.checkNotNull; | ||
| 54 | +import static org.onlab.util.Tools.nullIsNotFound; | ||
| 55 | +import static org.onosproject.net.region.RegionEvent.Type.REGION_MEMBERSHIP_CHANGED; | ||
| 56 | +import static org.slf4j.LoggerFactory.getLogger; | ||
| 57 | + | ||
| 58 | +/** | ||
| 59 | + * Consistent store implementation for tracking region definitions and device | ||
| 60 | + * region affiliation. | ||
| 61 | + */ | ||
| 62 | +@Component(immediate = true) | ||
| 63 | +@Service | ||
| 64 | +public class DistributedRegionStore | ||
| 65 | + extends AbstractStore<RegionEvent, RegionStoreDelegate> | ||
| 66 | + implements RegionStore { | ||
| 67 | + | ||
| 68 | + private static final String NO_REGION = "Region does not exist"; | ||
| 69 | + private static final String DUPLICATE_REGION = "Region already exists"; | ||
| 70 | + | ||
| 71 | + private final Logger log = getLogger(getClass()); | ||
| 72 | + | ||
| 73 | + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) | ||
| 74 | + protected StorageService storageService; | ||
| 75 | + | ||
| 76 | + private ConsistentMap<RegionId, Region> regionsRepo; | ||
| 77 | + private Map<RegionId, Region> regionsById; | ||
| 78 | + | ||
| 79 | + private ConsistentMap<RegionId, Set<DeviceId>> membershipRepo; | ||
| 80 | + private Map<RegionId, Set<DeviceId>> regionDevices; | ||
| 81 | + | ||
| 82 | + private Map<DeviceId, Region> regionsByDevice = new HashMap<>(); | ||
| 83 | + | ||
| 84 | + private final MapEventListener<RegionId, Region> listener = | ||
| 85 | + new InternalRegionListener(); | ||
| 86 | + private final MapEventListener<RegionId, Set<DeviceId>> membershipListener = | ||
| 87 | + new InternalMembershipListener(); | ||
| 88 | + | ||
| 89 | + @Activate | ||
| 90 | + protected void activate() { | ||
| 91 | + Serializer serializer = | ||
| 92 | + Serializer.using(Arrays.asList(KryoNamespaces.API), | ||
| 93 | + Identifier.class, | ||
| 94 | + RegionId.class, | ||
| 95 | + Region.class, | ||
| 96 | + DefaultRegion.class, | ||
| 97 | + Region.Type.class); | ||
| 98 | + | ||
| 99 | + regionsRepo = storageService.<RegionId, Region>consistentMapBuilder() | ||
| 100 | + .withSerializer(serializer) | ||
| 101 | + .withName("onos-regions") | ||
| 102 | + .withRelaxedReadConsistency() | ||
| 103 | + .build(); | ||
| 104 | + regionsRepo.addListener(listener); | ||
| 105 | + regionsById = regionsRepo.asJavaMap(); | ||
| 106 | + | ||
| 107 | + membershipRepo = storageService.<RegionId, Set<DeviceId>>consistentMapBuilder() | ||
| 108 | + .withSerializer(serializer) | ||
| 109 | + .withName("onos-region-devices") | ||
| 110 | + .withRelaxedReadConsistency() | ||
| 111 | + .build(); | ||
| 112 | + membershipRepo.addListener(membershipListener); | ||
| 113 | + regionDevices = membershipRepo.asJavaMap(); | ||
| 114 | + log.info("Started"); | ||
| 115 | + } | ||
| 116 | + | ||
| 117 | + @Deactivate | ||
| 118 | + protected void deactivate() { | ||
| 119 | + regionsRepo.removeListener(listener); | ||
| 120 | + membershipRepo.removeListener(membershipListener); | ||
| 121 | + regionsByDevice.clear(); | ||
| 122 | + log.info("Stopped"); | ||
| 123 | + } | ||
| 124 | + | ||
| 125 | + @Override | ||
| 126 | + public Set<Region> getRegions() { | ||
| 127 | + return ImmutableSet.copyOf(regionsById.values()); | ||
| 128 | + } | ||
| 129 | + | ||
| 130 | + @Override | ||
| 131 | + public Region getRegion(RegionId regionId) { | ||
| 132 | + return nullIsNotFound(regionsById.get(regionId), NO_REGION); | ||
| 133 | + } | ||
| 134 | + | ||
| 135 | + @Override | ||
| 136 | + public Region getRegionForDevice(DeviceId deviceId) { | ||
| 137 | + return regionsByDevice.get(deviceId); | ||
| 138 | + } | ||
| 139 | + | ||
| 140 | + @Override | ||
| 141 | + public Set<DeviceId> getRegionDevices(RegionId regionId) { | ||
| 142 | + Set<DeviceId> deviceIds = regionDevices.get(regionId); | ||
| 143 | + return deviceIds != null ? ImmutableSet.copyOf(deviceIds) : ImmutableSet.of(); | ||
| 144 | + } | ||
| 145 | + | ||
| 146 | + @Override | ||
| 147 | + public Region createRegion(RegionId regionId, String name, Region.Type type, | ||
| 148 | + List<Set<NodeId>> masterNodeIds) { | ||
| 149 | + return regionsRepo.compute(regionId, (id, region) -> { | ||
| 150 | + checkArgument(region == null, DUPLICATE_REGION); | ||
| 151 | + return new DefaultRegion(regionId, name, type, masterNodeIds); | ||
| 152 | + }).value(); | ||
| 153 | + } | ||
| 154 | + | ||
| 155 | + @Override | ||
| 156 | + public Region updateRegion(RegionId regionId, String name, Region.Type type, | ||
| 157 | + List<Set<NodeId>> masterNodeIds) { | ||
| 158 | + return regionsRepo.compute(regionId, (id, region) -> { | ||
| 159 | + nullIsNotFound(region, NO_REGION); | ||
| 160 | + return new DefaultRegion(regionId, name, type, masterNodeIds); | ||
| 161 | + }).value(); | ||
| 162 | + } | ||
| 163 | + | ||
| 164 | + @Override | ||
| 165 | + public void removeRegion(RegionId regionId) { | ||
| 166 | + membershipRepo.remove(regionId); | ||
| 167 | + regionsRepo.remove(regionId); | ||
| 168 | + } | ||
| 169 | + | ||
| 170 | + @Override | ||
| 171 | + public void addDevices(RegionId regionId, Collection<DeviceId> deviceIds) { | ||
| 172 | + membershipRepo.compute(regionId, (id, existingDevices) -> { | ||
| 173 | + if (existingDevices == null) { | ||
| 174 | + return ImmutableSet.copyOf(deviceIds); | ||
| 175 | + } else if (!existingDevices.containsAll(deviceIds)) { | ||
| 176 | + return ImmutableSet.<DeviceId>builder() | ||
| 177 | + .addAll(existingDevices) | ||
| 178 | + .addAll(deviceIds) | ||
| 179 | + .build(); | ||
| 180 | + } else { | ||
| 181 | + return existingDevices; | ||
| 182 | + } | ||
| 183 | + }); | ||
| 184 | + | ||
| 185 | + Region region = regionsById.get(regionId); | ||
| 186 | + deviceIds.forEach(deviceId -> regionsByDevice.put(deviceId, region)); | ||
| 187 | + } | ||
| 188 | + | ||
| 189 | + @Override | ||
| 190 | + public void removeDevices(RegionId regionId, Collection<DeviceId> deviceIds) { | ||
| 191 | + membershipRepo.compute(regionId, (id, existingDevices) -> { | ||
| 192 | + if (existingDevices == null || existingDevices.isEmpty()) { | ||
| 193 | + return ImmutableSet.of(); | ||
| 194 | + } else { | ||
| 195 | + return ImmutableSet.<DeviceId>builder() | ||
| 196 | + .addAll(Sets.difference(existingDevices, | ||
| 197 | + ImmutableSet.copyOf(deviceIds))) | ||
| 198 | + .build(); | ||
| 199 | + } | ||
| 200 | + }); | ||
| 201 | + | ||
| 202 | + deviceIds.forEach(deviceId -> regionsByDevice.remove(deviceId)); | ||
| 203 | + } | ||
| 204 | + | ||
| 205 | + /** | ||
| 206 | + * Listener class to map listener events to the region inventory events. | ||
| 207 | + */ | ||
| 208 | + private class InternalRegionListener implements MapEventListener<RegionId, Region> { | ||
| 209 | + @Override | ||
| 210 | + public void event(MapEvent<RegionId, Region> event) { | ||
| 211 | + Region region = null; | ||
| 212 | + RegionEvent.Type type = null; | ||
| 213 | + switch (event.type()) { | ||
| 214 | + case INSERT: | ||
| 215 | + type = RegionEvent.Type.REGION_ADDED; | ||
| 216 | + region = checkNotNull(event.newValue().value()); | ||
| 217 | + break; | ||
| 218 | + case UPDATE: | ||
| 219 | + type = RegionEvent.Type.REGION_UPDATED; | ||
| 220 | + region = checkNotNull(event.newValue().value()); | ||
| 221 | + break; | ||
| 222 | + case REMOVE: | ||
| 223 | + type = RegionEvent.Type.REGION_REMOVED; | ||
| 224 | + region = checkNotNull(event.oldValue().value()); | ||
| 225 | + break; | ||
| 226 | + default: | ||
| 227 | + log.error("Unsupported event type: " + event.type()); | ||
| 228 | + } | ||
| 229 | + notifyDelegate(new RegionEvent(type, region)); | ||
| 230 | + } | ||
| 231 | + } | ||
| 232 | + | ||
| 233 | + /** | ||
| 234 | + * Listener class to map listener events to the region membership events. | ||
| 235 | + */ | ||
| 236 | + private class InternalMembershipListener implements MapEventListener<RegionId, Set<DeviceId>> { | ||
| 237 | + @Override | ||
| 238 | + public void event(MapEvent<RegionId, Set<DeviceId>> event) { | ||
| 239 | + if (event.type() != MapEvent.Type.REMOVE) { | ||
| 240 | + notifyDelegate(new RegionEvent(REGION_MEMBERSHIP_CHANGED, | ||
| 241 | + regionsById.get(event.key()), | ||
| 242 | + event.newValue().value())); | ||
| 243 | + } | ||
| 244 | + } | ||
| 245 | + } | ||
| 246 | +} |
| 1 | +/* | ||
| 2 | + * Copyright 2016 Open Networking Laboratory | ||
| 3 | + * | ||
| 4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | ||
| 5 | + * you may not use this file except in compliance with the License. | ||
| 6 | + * You may obtain a copy of the License at | ||
| 7 | + * | ||
| 8 | + * http://www.apache.org/licenses/LICENSE-2.0 | ||
| 9 | + * | ||
| 10 | + * Unless required by applicable law or agreed to in writing, software | ||
| 11 | + * distributed under the License is distributed on an "AS IS" BASIS, | ||
| 12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
| 13 | + * See the License for the specific language governing permissions and | ||
| 14 | + * limitations under the License. | ||
| 15 | + */ | ||
| 16 | + | ||
| 17 | +/** | ||
| 18 | + * A distributed store implementation for tracking region definitions | ||
| 19 | + * consistently across the cluster. | ||
| 20 | + */ | ||
| 21 | +package org.onosproject.store.region.impl; | ||
| ... | \ No newline at end of file | ... | \ No newline at end of file |
core/store/dist/src/test/java/org/onosproject/store/region/impl/DistributedRegionStoreTest.java
0 → 100644
| 1 | +/* | ||
| 2 | + * Copyright 2016 Open Networking Laboratory | ||
| 3 | + * | ||
| 4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | ||
| 5 | + * you may not use this file except in compliance with the License. | ||
| 6 | + * You may obtain a copy of the License at | ||
| 7 | + * | ||
| 8 | + * http://www.apache.org/licenses/LICENSE-2.0 | ||
| 9 | + * | ||
| 10 | + * Unless required by applicable law or agreed to in writing, software | ||
| 11 | + * distributed under the License is distributed on an "AS IS" BASIS, | ||
| 12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
| 13 | + * See the License for the specific language governing permissions and | ||
| 14 | + * limitations under the License. | ||
| 15 | + */ | ||
| 16 | + | ||
| 17 | +package org.onosproject.store.region.impl; | ||
| 18 | + | ||
| 19 | +import com.google.common.collect.ImmutableList; | ||
| 20 | +import com.google.common.collect.ImmutableSet; | ||
| 21 | +import org.junit.After; | ||
| 22 | +import org.junit.Before; | ||
| 23 | +import org.junit.Test; | ||
| 24 | +import org.onlab.util.ItemNotFoundException; | ||
| 25 | +import org.onosproject.cluster.NodeId; | ||
| 26 | +import org.onosproject.net.DeviceId; | ||
| 27 | +import org.onosproject.net.region.Region; | ||
| 28 | +import org.onosproject.net.region.RegionEvent; | ||
| 29 | +import org.onosproject.net.region.RegionId; | ||
| 30 | +import org.onosproject.store.service.TestStorageService; | ||
| 31 | + | ||
| 32 | +import java.util.List; | ||
| 33 | +import java.util.Set; | ||
| 34 | + | ||
| 35 | +import static org.junit.Assert.*; | ||
| 36 | +import static org.onosproject.net.region.Region.Type.*; | ||
| 37 | +import static org.onosproject.net.region.RegionEvent.Type.*; | ||
| 38 | + | ||
| 39 | +/** | ||
| 40 | + * Test of the distributed region store implementation. | ||
| 41 | + */ | ||
| 42 | +public class DistributedRegionStoreTest { | ||
| 43 | + | ||
| 44 | + private static final RegionId RID1 = RegionId.regionId("r1"); | ||
| 45 | + private static final RegionId RID2 = RegionId.regionId("r2"); | ||
| 46 | + | ||
| 47 | + private static final DeviceId DID1 = DeviceId.deviceId("foo:d1"); | ||
| 48 | + private static final DeviceId DID2 = DeviceId.deviceId("foo:d2"); | ||
| 49 | + private static final DeviceId DID3 = DeviceId.deviceId("foo:d3"); | ||
| 50 | + | ||
| 51 | + private static final NodeId NID1 = NodeId.nodeId("n1"); | ||
| 52 | + | ||
| 53 | + private static final List<Set<NodeId>> MASTERS = ImmutableList.of(ImmutableSet.of(NID1)); | ||
| 54 | + | ||
| 55 | + private TestStore store; | ||
| 56 | + private RegionEvent event; | ||
| 57 | + | ||
| 58 | + /** | ||
| 59 | + * Sets up the device key store and the storage service test harness. | ||
| 60 | + */ | ||
| 61 | + @Before | ||
| 62 | + public void setUp() { | ||
| 63 | + store = new TestStore(); | ||
| 64 | + store.storageService = new TestStorageService(); | ||
| 65 | + store.setDelegate(e -> this.event = e); | ||
| 66 | + store.activate(); | ||
| 67 | + } | ||
| 68 | + | ||
| 69 | + /** | ||
| 70 | + * Tears down the device key store. | ||
| 71 | + */ | ||
| 72 | + @After | ||
| 73 | + public void tearDown() { | ||
| 74 | + store.deactivate(); | ||
| 75 | + } | ||
| 76 | + | ||
| 77 | + @Test | ||
| 78 | + public void basics() { | ||
| 79 | + Region r1 = store.createRegion(RID1, "R1", METRO, MASTERS); | ||
| 80 | + assertEquals("incorrect id", RID1, r1.id()); | ||
| 81 | + assertEquals("incorrect event", REGION_ADDED, event.type()); | ||
| 82 | + | ||
| 83 | + Region r2 = store.createRegion(RID2, "R2", CAMPUS, MASTERS); | ||
| 84 | + assertEquals("incorrect id", RID2, r2.id()); | ||
| 85 | + assertEquals("incorrect type", CAMPUS, r2.type()); | ||
| 86 | + assertEquals("incorrect event", REGION_ADDED, event.type()); | ||
| 87 | + | ||
| 88 | + r2 = store.updateRegion(RID2, "R2", COUNTRY, MASTERS); | ||
| 89 | + assertEquals("incorrect type", COUNTRY, r2.type()); | ||
| 90 | + assertEquals("incorrect event", REGION_UPDATED, event.type()); | ||
| 91 | + | ||
| 92 | + Set<Region> regions = store.getRegions(); | ||
| 93 | + assertEquals("incorrect size", 2, regions.size()); | ||
| 94 | + assertTrue("missing r1", regions.contains(r1)); | ||
| 95 | + assertTrue("missing r2", regions.contains(r2)); | ||
| 96 | + | ||
| 97 | + r1 = store.getRegion(RID1); | ||
| 98 | + assertEquals("incorrect id", RID1, r1.id()); | ||
| 99 | + | ||
| 100 | + store.removeRegion(RID1); | ||
| 101 | + regions = store.getRegions(); | ||
| 102 | + assertEquals("incorrect size", 1, regions.size()); | ||
| 103 | + assertTrue("missing r2", regions.contains(r2)); | ||
| 104 | + assertEquals("incorrect event", REGION_REMOVED, event.type()); | ||
| 105 | + } | ||
| 106 | + | ||
| 107 | + @Test(expected = IllegalArgumentException.class) | ||
| 108 | + public void duplicateCreate() { | ||
| 109 | + store.createRegion(RID1, "R1", METRO, MASTERS); | ||
| 110 | + store.createRegion(RID1, "R2", CAMPUS, MASTERS); | ||
| 111 | + } | ||
| 112 | + | ||
| 113 | + @Test(expected = ItemNotFoundException.class) | ||
| 114 | + public void missingUpdate() { | ||
| 115 | + store.updateRegion(RID1, "R1", METRO, MASTERS); | ||
| 116 | + } | ||
| 117 | + | ||
| 118 | + @Test | ||
| 119 | + public void membership() { | ||
| 120 | + Region r = store.createRegion(RID1, "R1", METRO, MASTERS); | ||
| 121 | + assertTrue("no devices expected", store.getRegionDevices(RID1).isEmpty()); | ||
| 122 | + assertNull("no region expected", store.getRegionForDevice(DID1)); | ||
| 123 | + | ||
| 124 | + store.addDevices(RID1, ImmutableSet.of(DID1, DID2)); | ||
| 125 | + Set<DeviceId> deviceIds = store.getRegionDevices(RID1); | ||
| 126 | + assertEquals("incorrect device count", 2, deviceIds.size()); | ||
| 127 | + assertTrue("missing d1", deviceIds.contains(DID1)); | ||
| 128 | + assertTrue("missing d2", deviceIds.contains(DID2)); | ||
| 129 | + assertEquals("wrong region", r, store.getRegionForDevice(DID1)); | ||
| 130 | + | ||
| 131 | + store.addDevices(RID1, ImmutableSet.of(DID3)); | ||
| 132 | + deviceIds = store.getRegionDevices(RID1); | ||
| 133 | + assertEquals("incorrect device count", 3, deviceIds.size()); | ||
| 134 | + assertTrue("missing d3", deviceIds.contains(DID3)); | ||
| 135 | + | ||
| 136 | + store.addDevices(RID1, ImmutableSet.of(DID3, DID1)); | ||
| 137 | + deviceIds = store.getRegionDevices(RID1); | ||
| 138 | + assertEquals("incorrect device count", 3, deviceIds.size()); | ||
| 139 | + | ||
| 140 | + store.removeDevices(RID1, ImmutableSet.of(DID2, DID3)); | ||
| 141 | + deviceIds = store.getRegionDevices(RID1); | ||
| 142 | + assertEquals("incorrect device count", 1, deviceIds.size()); | ||
| 143 | + assertTrue("missing d1", deviceIds.contains(DID1)); | ||
| 144 | + | ||
| 145 | + store.removeDevices(RID1, ImmutableSet.of(DID1, DID3)); | ||
| 146 | + assertTrue("no devices expected", store.getRegionDevices(RID1).isEmpty()); | ||
| 147 | + | ||
| 148 | + store.removeDevices(RID1, ImmutableSet.of(DID2)); | ||
| 149 | + assertTrue("no devices expected", store.getRegionDevices(RID1).isEmpty()); | ||
| 150 | + } | ||
| 151 | + | ||
| 152 | + class TestStore extends DistributedRegionStore { | ||
| 153 | + } | ||
| 154 | +} | ||
| ... | \ No newline at end of file | ... | \ No newline at end of file |
| 1 | -Copyright 2014-$today.year Open Networking Laboratory | 1 | +Copyright $today.year Open Networking Laboratory |
| 2 | 2 | ||
| 3 | Licensed under the Apache License, Version 2.0 (the "License"); | 3 | Licensed under the Apache License, Version 2.0 (the "License"); |
| 4 | you may not use this file except in compliance with the License. | 4 | you may not use this file except in compliance with the License. | ... | ... |
| 1 | +/* | ||
| 2 | + * Copyright 2014-2016 Open Networking Laboratory | ||
| 3 | + * | ||
| 4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | ||
| 5 | + * you may not use this file except in compliance with the License. | ||
| 6 | + * You may obtain a copy of the License at | ||
| 7 | + * | ||
| 8 | + * http://www.apache.org/licenses/LICENSE-2.0 | ||
| 9 | + * | ||
| 10 | + * Unless required by applicable law or agreed to in writing, software | ||
| 11 | + * distributed under the License is distributed on an "AS IS" BASIS, | ||
| 12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
| 13 | + * See the License for the specific language governing permissions and | ||
| 14 | + * limitations under the License. | ||
| 15 | + */ | ||
| 16 | + | ||
| 17 | +package org.onlab.util; | ||
| 18 | + | ||
| 19 | +import java.util.Objects; | ||
| 20 | + | ||
| 21 | +import static com.google.common.base.Preconditions.checkNotNull; | ||
| 22 | + | ||
| 23 | +/** | ||
| 24 | + * Abstract identifier backed by another value, e.g. string, int. | ||
| 25 | + */ | ||
| 26 | +public class Identifier<T> { | ||
| 27 | + | ||
| 28 | + protected final T identifier; // backing identifier value | ||
| 29 | + | ||
| 30 | + /** | ||
| 31 | + * Constructor for serialization. | ||
| 32 | + */ | ||
| 33 | + protected Identifier() { | ||
| 34 | + this.identifier = null; | ||
| 35 | + } | ||
| 36 | + | ||
| 37 | + /** | ||
| 38 | + * Constructs an identifier backed by the specified value. | ||
| 39 | + * | ||
| 40 | + * @param value the backing value | ||
| 41 | + */ | ||
| 42 | + protected Identifier(T value) { | ||
| 43 | + this.identifier = checkNotNull(value, "Identifier cannot be null."); | ||
| 44 | + } | ||
| 45 | + | ||
| 46 | + /** | ||
| 47 | + * Returns the backing identifier value. | ||
| 48 | + * | ||
| 49 | + * @return identifier | ||
| 50 | + */ | ||
| 51 | + public T id() { | ||
| 52 | + return identifier; | ||
| 53 | + } | ||
| 54 | + | ||
| 55 | + /** | ||
| 56 | + * Returns the hashcode of the identifier. | ||
| 57 | + * | ||
| 58 | + * @return hashcode | ||
| 59 | + */ | ||
| 60 | + @Override | ||
| 61 | + public int hashCode() { | ||
| 62 | + return identifier.hashCode(); | ||
| 63 | + } | ||
| 64 | + | ||
| 65 | + /** | ||
| 66 | + * Compares two device key identifiers for equality. | ||
| 67 | + * | ||
| 68 | + * @param obj to compare against | ||
| 69 | + * @return true if the objects are equal, false otherwise. | ||
| 70 | + */ | ||
| 71 | + @Override | ||
| 72 | + public boolean equals(Object obj) { | ||
| 73 | + if (this == obj) { | ||
| 74 | + return true; | ||
| 75 | + } | ||
| 76 | + if (obj instanceof Identifier) { | ||
| 77 | + Identifier that = (Identifier) obj; | ||
| 78 | + return this.getClass() == that.getClass() && | ||
| 79 | + Objects.equals(this.identifier, that.identifier); | ||
| 80 | + } | ||
| 81 | + return false; | ||
| 82 | + } | ||
| 83 | + | ||
| 84 | + /** | ||
| 85 | + * Returns a string representation of a DeviceKeyId. | ||
| 86 | + * | ||
| 87 | + * @return string | ||
| 88 | + */ | ||
| 89 | + public String toString() { | ||
| 90 | + return identifier.toString(); | ||
| 91 | + } | ||
| 92 | + | ||
| 93 | +} |
| 1 | +/* | ||
| 2 | + * Copyright 2014-2016 Open Networking Laboratory | ||
| 3 | + * | ||
| 4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | ||
| 5 | + * you may not use this file except in compliance with the License. | ||
| 6 | + * You may obtain a copy of the License at | ||
| 7 | + * | ||
| 8 | + * http://www.apache.org/licenses/LICENSE-2.0 | ||
| 9 | + * | ||
| 10 | + * Unless required by applicable law or agreed to in writing, software | ||
| 11 | + * distributed under the License is distributed on an "AS IS" BASIS, | ||
| 12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
| 13 | + * See the License for the specific language governing permissions and | ||
| 14 | + * limitations under the License. | ||
| 15 | + */ | ||
| 16 | + | ||
| 17 | +package org.onlab.util; | ||
| 18 | + | ||
| 19 | +import com.google.common.testing.EqualsTester; | ||
| 20 | +import org.junit.Test; | ||
| 21 | + | ||
| 22 | +import static org.junit.Assert.*; | ||
| 23 | + | ||
| 24 | +/** | ||
| 25 | + * Test of the base identifier. | ||
| 26 | + */ | ||
| 27 | +public class IdentifierTest { | ||
| 28 | + | ||
| 29 | + @Test | ||
| 30 | + public void basics() { | ||
| 31 | + FooId id = new FooId(123); | ||
| 32 | + assertEquals("incorrect value", 123, (int) id.id()); | ||
| 33 | + } | ||
| 34 | + | ||
| 35 | + @Test | ||
| 36 | + public void equality() { | ||
| 37 | + FooId a = new FooId(1); | ||
| 38 | + FooId b = new FooId(1); | ||
| 39 | + FooId c = new FooId(2); | ||
| 40 | + new EqualsTester().addEqualityGroup(a, b).addEqualityGroup(c).testEquals(); | ||
| 41 | + } | ||
| 42 | + | ||
| 43 | + static class FooId extends Identifier<Integer> { | ||
| 44 | + FooId(int id) { | ||
| 45 | + super(id); | ||
| 46 | + } | ||
| 47 | + } | ||
| 48 | + | ||
| 49 | +} | ||
| ... | \ No newline at end of file | ... | \ No newline at end of file |
-
Please register or login to post a comment