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 | } | 39 | } |
35 | 40 | ||
36 | - @Override | 41 | + /** |
37 | - public int hashCode() { | 42 | + * Creates a new cluster node identifier from the specified string. |
38 | - return id.hashCode(); | 43 | + * |
39 | - } | 44 | + * @param id string identifier |
40 | - | 45 | + * @return node id |
41 | - @Override | 46 | + */ |
42 | - public boolean equals(Object obj) { | 47 | + public static NodeId nodeId(String id) { |
43 | - if (this == obj) { | 48 | + return new NodeId(id); |
44 | - return true; | ||
45 | - } | ||
46 | - if (obj instanceof NodeId) { | ||
47 | - final NodeId other = (NodeId) obj; | ||
48 | - return Objects.equals(this.id, other.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