Committed by
Gerrit Code Review
ONOS-4971: Synthetic Link Data -- WIP
- Breaking out UiLink to subclasses for device links, host links, region links, region-device links, - (soon, also peer links). - Augmenting UiLinkId to include regions as endpoints. - Introduced UiSynthLink to encapsulate synthetic links bound to regions. - Model Cache now computes synthetic links from the underlying link data. - Added endPointA/B() and type() methods to UiLink. - Updated topo2CurrentRegion response to include synth-links for the region. Change-Id: Ifa62a15fbe0a58b134d92278b201fa7a72cbfa83
Showing
21 changed files
with
1502 additions
and
308 deletions
1 | +/* | ||
2 | + * Copyright 2016-present 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.ui.model.topo; | ||
18 | + | ||
19 | +import org.onosproject.net.DeviceId; | ||
20 | +import org.onosproject.net.Link; | ||
21 | +import org.onosproject.net.PortNumber; | ||
22 | + | ||
23 | +/** | ||
24 | + * Represents a link between two devices; that is, an infrastructure link. | ||
25 | + */ | ||
26 | +public class UiDeviceLink extends UiLink { | ||
27 | + | ||
28 | + private static final String E_UNASSOC = | ||
29 | + "backing link not associated with this UI device link: "; | ||
30 | + | ||
31 | + // devices and ports at either end of this link | ||
32 | + private DeviceId deviceA; | ||
33 | + private DeviceId deviceB; | ||
34 | + private PortNumber portA; | ||
35 | + private PortNumber portB; | ||
36 | + | ||
37 | + // two unidirectional links underlying this link... | ||
38 | + private Link linkAtoB; | ||
39 | + private Link linkBtoA; | ||
40 | + | ||
41 | + | ||
42 | + /** | ||
43 | + * Creates a device to device UI link. | ||
44 | + * | ||
45 | + * @param topology parent topology | ||
46 | + * @param id canonicalized link identifier | ||
47 | + */ | ||
48 | + public UiDeviceLink(UiTopology topology, UiLinkId id) { | ||
49 | + super(topology, id); | ||
50 | + } | ||
51 | + | ||
52 | + @Override | ||
53 | + public String endPointA() { | ||
54 | + return deviceA + UiLinkId.ID_PORT_DELIMITER + portA; | ||
55 | + } | ||
56 | + | ||
57 | + @Override | ||
58 | + public String endPointB() { | ||
59 | + return deviceB + UiLinkId.ID_PORT_DELIMITER + portB; | ||
60 | + } | ||
61 | + | ||
62 | + | ||
63 | + @Override | ||
64 | + protected void destroy() { | ||
65 | + deviceA = null; | ||
66 | + deviceB = null; | ||
67 | + portA = null; | ||
68 | + portB = null; | ||
69 | + linkAtoB = null; | ||
70 | + linkBtoA = null; | ||
71 | + } | ||
72 | + | ||
73 | + | ||
74 | + /** | ||
75 | + * Attaches the given backing link to this UI link. This method will | ||
76 | + * throw an exception if this UI link is not representative of the | ||
77 | + * supplied link. | ||
78 | + * | ||
79 | + * @param link backing link to attach | ||
80 | + * @throws IllegalArgumentException if the link is not appropriate | ||
81 | + */ | ||
82 | + public void attachBackingLink(Link link) { | ||
83 | + UiLinkId.Direction d = id.directionOf(link); | ||
84 | + | ||
85 | + if (d == UiLinkId.Direction.A_TO_B) { | ||
86 | + linkAtoB = link; | ||
87 | + deviceA = link.src().deviceId(); | ||
88 | + portA = link.src().port(); | ||
89 | + deviceB = link.dst().deviceId(); | ||
90 | + portB = link.dst().port(); | ||
91 | + | ||
92 | + } else if (d == UiLinkId.Direction.B_TO_A) { | ||
93 | + linkBtoA = link; | ||
94 | + deviceB = link.src().deviceId(); | ||
95 | + portB = link.src().port(); | ||
96 | + deviceA = link.dst().deviceId(); | ||
97 | + portA = link.dst().port(); | ||
98 | + | ||
99 | + } else { | ||
100 | + throw new IllegalArgumentException(E_UNASSOC + link); | ||
101 | + } | ||
102 | + } | ||
103 | + | ||
104 | + /** | ||
105 | + * Detaches the given backing link from this UI link, returning true if the | ||
106 | + * reverse link is still attached, or false otherwise. | ||
107 | + * | ||
108 | + * @param link the backing link to detach | ||
109 | + * @return true if other link still attached, false otherwise | ||
110 | + * @throws IllegalArgumentException if the link is not appropriate | ||
111 | + */ | ||
112 | + public boolean detachBackingLink(Link link) { | ||
113 | + UiLinkId.Direction d = id.directionOf(link); | ||
114 | + if (d == UiLinkId.Direction.A_TO_B) { | ||
115 | + linkAtoB = null; | ||
116 | + return linkBtoA != null; | ||
117 | + } | ||
118 | + if (d == UiLinkId.Direction.B_TO_A) { | ||
119 | + linkBtoA = null; | ||
120 | + return linkAtoB != null; | ||
121 | + } | ||
122 | + throw new IllegalArgumentException(E_UNASSOC + link); | ||
123 | + } | ||
124 | + | ||
125 | + | ||
126 | + /** | ||
127 | + * Returns the identity of device A. | ||
128 | + * | ||
129 | + * @return device A ID | ||
130 | + */ | ||
131 | + public DeviceId deviceA() { | ||
132 | + return deviceA; | ||
133 | + } | ||
134 | + | ||
135 | + /** | ||
136 | + * Returns the port number of device A. | ||
137 | + * | ||
138 | + * @return port A | ||
139 | + */ | ||
140 | + public PortNumber portA() { | ||
141 | + return portA; | ||
142 | + } | ||
143 | + | ||
144 | + /** | ||
145 | + * Returns the identity of device B. | ||
146 | + * | ||
147 | + * @return device B ID | ||
148 | + */ | ||
149 | + public DeviceId deviceB() { | ||
150 | + return deviceB; | ||
151 | + } | ||
152 | + | ||
153 | + /** | ||
154 | + * Returns the port number of device B. | ||
155 | + * | ||
156 | + * @return port B | ||
157 | + */ | ||
158 | + public PortNumber portB() { | ||
159 | + return portB; | ||
160 | + } | ||
161 | + | ||
162 | + /** | ||
163 | + * Returns backing link from A to B. | ||
164 | + * | ||
165 | + * @return backing link A to B | ||
166 | + */ | ||
167 | + public Link linkAtoB() { | ||
168 | + return linkAtoB; | ||
169 | + } | ||
170 | + | ||
171 | + /** | ||
172 | + * Returns backing link from B to A. | ||
173 | + * | ||
174 | + * @return backing link B to A | ||
175 | + */ | ||
176 | + public Link linkBtoA() { | ||
177 | + return linkBtoA; | ||
178 | + } | ||
179 | + | ||
180 | +} |
1 | +/* | ||
2 | + * Copyright 2016-present 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.ui.model.topo; | ||
18 | + | ||
19 | +import org.onosproject.net.DeviceId; | ||
20 | +import org.onosproject.net.EdgeLink; | ||
21 | +import org.onosproject.net.PortNumber; | ||
22 | + | ||
23 | +/** | ||
24 | + * Designates a link between a device and a host; that is, an edge link. | ||
25 | + */ | ||
26 | +public class UiEdgeLink extends UiLink { | ||
27 | + | ||
28 | + private static final String E_UNASSOC = | ||
29 | + "backing link not associated with this UI edge link: "; | ||
30 | + | ||
31 | + // private (synthetic) host link | ||
32 | + private DeviceId edgeDevice; | ||
33 | + private PortNumber edgePort; | ||
34 | + private EdgeLink edgeLink; | ||
35 | + | ||
36 | + /** | ||
37 | + * Creates a UI link. | ||
38 | + * | ||
39 | + * @param topology parent topology | ||
40 | + * @param id canonicalized link identifier | ||
41 | + */ | ||
42 | + public UiEdgeLink(UiTopology topology, UiLinkId id) { | ||
43 | + super(topology, id); | ||
44 | + } | ||
45 | + | ||
46 | + @Override | ||
47 | + public String endPointA() { | ||
48 | + return edgeLink.hostId().toString(); | ||
49 | + } | ||
50 | + | ||
51 | + @Override | ||
52 | + public String endPointB() { | ||
53 | + return edgeDevice + UiLinkId.ID_PORT_DELIMITER + edgePort; | ||
54 | + } | ||
55 | + | ||
56 | + @Override | ||
57 | + protected void destroy() { | ||
58 | + edgeDevice = null; | ||
59 | + edgePort = null; | ||
60 | + edgeLink = null; | ||
61 | + } | ||
62 | + | ||
63 | + /** | ||
64 | + * Attaches the given edge link to this UI link. This method will | ||
65 | + * throw an exception if this UI link is not representative of the | ||
66 | + * supplied link. | ||
67 | + * | ||
68 | + * @param elink edge link to attach | ||
69 | + * @throws IllegalArgumentException if the link is not appropriate | ||
70 | + */ | ||
71 | + public void attachEdgeLink(EdgeLink elink) { | ||
72 | + UiLinkId.Direction d = id.directionOf(elink); | ||
73 | + // Expected direction of edge links is A-to-B (Host to device) | ||
74 | + // but checking not null is a sufficient test | ||
75 | + if (d == null) { | ||
76 | + throw new IllegalArgumentException(E_UNASSOC + elink); | ||
77 | + } | ||
78 | + | ||
79 | + edgeLink = elink; | ||
80 | + edgeDevice = elink.hostLocation().deviceId(); | ||
81 | + edgePort = elink.hostLocation().port(); | ||
82 | + } | ||
83 | + | ||
84 | +} |
... | @@ -16,17 +16,11 @@ | ... | @@ -16,17 +16,11 @@ |
16 | 16 | ||
17 | package org.onosproject.ui.model.topo; | 17 | package org.onosproject.ui.model.topo; |
18 | 18 | ||
19 | -import org.onosproject.net.DeviceId; | ||
20 | -import org.onosproject.net.EdgeLink; | ||
21 | -import org.onosproject.net.Link; | ||
22 | - | ||
23 | -import java.util.Set; | ||
24 | - | ||
25 | import static com.google.common.base.MoreObjects.toStringHelper; | 19 | import static com.google.common.base.MoreObjects.toStringHelper; |
26 | 20 | ||
27 | /** | 21 | /** |
28 | - * Represents a link (line between two elements). This may have one of | 22 | + * Represents a link (line between two elements). This may be one of |
29 | - * several forms: | 23 | + * several concrete subclasses: |
30 | * <ul> | 24 | * <ul> |
31 | * <li> | 25 | * <li> |
32 | * An infrastructure link: | 26 | * An infrastructure link: |
... | @@ -38,17 +32,15 @@ import static com.google.common.base.MoreObjects.toStringHelper; | ... | @@ -38,17 +32,15 @@ import static com.google.common.base.MoreObjects.toStringHelper; |
38 | * </li> | 32 | * </li> |
39 | * <li> | 33 | * <li> |
40 | * An aggregation link: | 34 | * An aggregation link: |
41 | - * representing multiple underlying UI link instances. | 35 | + * representing multiple underlying UI link instances, for example |
36 | + * the link between two sub-regions in a region (layout). | ||
42 | * </li> | 37 | * </li> |
43 | * </ul> | 38 | * </ul> |
44 | */ | 39 | */ |
45 | -public class UiLink extends UiElement { | 40 | +public abstract class UiLink extends UiElement { |
46 | - | ||
47 | - private static final String E_UNASSOC = | ||
48 | - "backing link not associated with this UI link: "; | ||
49 | 41 | ||
50 | - private final UiTopology topology; | 42 | + protected final UiTopology topology; |
51 | - private final UiLinkId id; | 43 | + protected final UiLinkId id; |
52 | 44 | ||
53 | /** | 45 | /** |
54 | * Creates a UI link. | 46 | * Creates a UI link. |
... | @@ -61,22 +53,6 @@ public class UiLink extends UiElement { | ... | @@ -61,22 +53,6 @@ public class UiLink extends UiElement { |
61 | this.id = id; | 53 | this.id = id; |
62 | } | 54 | } |
63 | 55 | ||
64 | - // devices at either end of this link | ||
65 | - private DeviceId deviceA; | ||
66 | - private DeviceId deviceB; | ||
67 | - | ||
68 | - // two unidirectional links underlying this link... | ||
69 | - private Link linkAtoB; | ||
70 | - private Link linkBtoA; | ||
71 | - | ||
72 | - // ==OR== : private (synthetic) host link | ||
73 | - private DeviceId edgeDevice; | ||
74 | - private EdgeLink edgeLink; | ||
75 | - | ||
76 | - // ==OR== : set of underlying UI links that this link aggregates | ||
77 | - private Set<UiLink> children; | ||
78 | - | ||
79 | - | ||
80 | @Override | 56 | @Override |
81 | public String toString() { | 57 | public String toString() { |
82 | return toStringHelper(this) | 58 | return toStringHelper(this) |
... | @@ -84,19 +60,6 @@ public class UiLink extends UiElement { | ... | @@ -84,19 +60,6 @@ public class UiLink extends UiElement { |
84 | .toString(); | 60 | .toString(); |
85 | } | 61 | } |
86 | 62 | ||
87 | - @Override | ||
88 | - protected void destroy() { | ||
89 | - deviceA = null; | ||
90 | - deviceB = null; | ||
91 | - linkAtoB = null; | ||
92 | - linkBtoA = null; | ||
93 | - edgeLink = null; | ||
94 | - if (children != null) { | ||
95 | - children.clear(); | ||
96 | - children = null; | ||
97 | - } | ||
98 | - } | ||
99 | - | ||
100 | /** | 63 | /** |
101 | * Returns the canonicalized link identifier for this link. | 64 | * Returns the canonicalized link identifier for this link. |
102 | * | 65 | * |
... | @@ -112,107 +75,25 @@ public class UiLink extends UiElement { | ... | @@ -112,107 +75,25 @@ public class UiLink extends UiElement { |
112 | } | 75 | } |
113 | 76 | ||
114 | /** | 77 | /** |
115 | - * Attaches the given backing link to this UI link. This method will | 78 | + * Returns the implementing class name as the type of link. |
116 | - * throw an exception if this UI link is not representative of the | ||
117 | - * supplied link. | ||
118 | * | 79 | * |
119 | - * @param link backing link to attach | 80 | + * @return link type |
120 | - * @throws IllegalArgumentException if the link is not appropriate | ||
121 | */ | 81 | */ |
122 | - public void attachBackingLink(Link link) { | 82 | + public String type() { |
123 | - UiLinkId.Direction d = id.directionOf(link); | 83 | + return getClass().getSimpleName(); |
124 | - | ||
125 | - if (d == UiLinkId.Direction.A_TO_B) { | ||
126 | - linkAtoB = link; | ||
127 | - deviceA = link.src().deviceId(); | ||
128 | - deviceB = link.dst().deviceId(); | ||
129 | - | ||
130 | - } else if (d == UiLinkId.Direction.B_TO_A) { | ||
131 | - linkBtoA = link; | ||
132 | - deviceB = link.src().deviceId(); | ||
133 | - deviceA = link.dst().deviceId(); | ||
134 | - | ||
135 | - } else { | ||
136 | - throw new IllegalArgumentException(E_UNASSOC + link); | ||
137 | - } | ||
138 | } | 84 | } |
139 | 85 | ||
140 | /** | 86 | /** |
141 | - * Detaches the given backing link from this UI link, returning true if the | 87 | + * Returns the identifier of end-point A in string form. |
142 | - * reverse link is still attached, or false otherwise. | ||
143 | * | 88 | * |
144 | - * @param link the backing link to detach | 89 | + * @return end point A identifier |
145 | - * @return true if other link still attached, false otherwise | ||
146 | - * @throws IllegalArgumentException if the link is not appropriate | ||
147 | */ | 90 | */ |
148 | - public boolean detachBackingLink(Link link) { | 91 | + public abstract String endPointA(); |
149 | - UiLinkId.Direction d = id.directionOf(link); | ||
150 | - if (d == UiLinkId.Direction.A_TO_B) { | ||
151 | - linkAtoB = null; | ||
152 | - return linkBtoA != null; | ||
153 | - } | ||
154 | - if (d == UiLinkId.Direction.B_TO_A) { | ||
155 | - linkBtoA = null; | ||
156 | - return linkAtoB != null; | ||
157 | - } | ||
158 | - throw new IllegalArgumentException(E_UNASSOC + link); | ||
159 | - } | ||
160 | 92 | ||
161 | /** | 93 | /** |
162 | - * Attaches the given edge link to this UI link. This method will | 94 | + * Returns the identifier of end-point B in string form. |
163 | - * throw an exception if this UI link is not representative of the | ||
164 | - * supplied link. | ||
165 | * | 95 | * |
166 | - * @param elink edge link to attach | 96 | + * @return end point B identifier |
167 | - * @throws IllegalArgumentException if the link is not appropriate | ||
168 | */ | 97 | */ |
169 | - public void attachEdgeLink(EdgeLink elink) { | 98 | + public abstract String endPointB(); |
170 | - UiLinkId.Direction d = id.directionOf(elink); | ||
171 | - // Expected direction of edge links is A-to-B (Host to device) | ||
172 | - // but checking not null is sufficient | ||
173 | - if (d == null) { | ||
174 | - throw new IllegalArgumentException(E_UNASSOC + elink); | ||
175 | - } | ||
176 | - | ||
177 | - edgeLink = elink; | ||
178 | - edgeDevice = elink.hostLocation().deviceId(); | ||
179 | - } | ||
180 | - | ||
181 | - | ||
182 | - /** | ||
183 | - * Returns the identity of device A. | ||
184 | - * | ||
185 | - * @return device A ID | ||
186 | - */ | ||
187 | - public DeviceId deviceA() { | ||
188 | - return deviceA; | ||
189 | - } | ||
190 | - | ||
191 | - /** | ||
192 | - * Returns the identity of device B. | ||
193 | - * | ||
194 | - * @return device B ID | ||
195 | - */ | ||
196 | - public DeviceId deviceB() { | ||
197 | - return deviceB; | ||
198 | - } | ||
199 | - | ||
200 | - /** | ||
201 | - * Returns backing link from A to B. | ||
202 | - * | ||
203 | - * @return backing link A to B | ||
204 | - */ | ||
205 | - public Link linkAtoB() { | ||
206 | - return linkAtoB; | ||
207 | - } | ||
208 | - | ||
209 | - /** | ||
210 | - * Returns backing link from B to A. | ||
211 | - * | ||
212 | - * @return backing link B to A | ||
213 | - */ | ||
214 | - public Link linkBtoA() { | ||
215 | - return linkBtoA; | ||
216 | - } | ||
217 | - | ||
218 | } | 99 | } | ... | ... |
... | @@ -17,15 +17,30 @@ | ... | @@ -17,15 +17,30 @@ |
17 | package org.onosproject.ui.model.topo; | 17 | package org.onosproject.ui.model.topo; |
18 | 18 | ||
19 | import org.onosproject.net.ConnectPoint; | 19 | import org.onosproject.net.ConnectPoint; |
20 | +import org.onosproject.net.DeviceId; | ||
20 | import org.onosproject.net.ElementId; | 21 | import org.onosproject.net.ElementId; |
21 | import org.onosproject.net.Link; | 22 | import org.onosproject.net.Link; |
22 | import org.onosproject.net.PortNumber; | 23 | import org.onosproject.net.PortNumber; |
24 | +import org.onosproject.net.region.RegionId; | ||
25 | + | ||
26 | +import java.util.Comparator; | ||
27 | + | ||
28 | +import static com.google.common.base.Preconditions.checkArgument; | ||
29 | +import static com.google.common.base.Preconditions.checkNotNull; | ||
23 | 30 | ||
24 | /** | 31 | /** |
25 | * A canonical representation of an identifier for {@link UiLink}s. | 32 | * A canonical representation of an identifier for {@link UiLink}s. |
26 | */ | 33 | */ |
27 | public final class UiLinkId { | 34 | public final class UiLinkId { |
28 | 35 | ||
36 | + private static final String E_PORT_NULL = "Port number cannot be null"; | ||
37 | + private static final String E_DEVICE_ID_NULL = "Device ID cannot be null"; | ||
38 | + private static final String E_REGION_ID_NULL = "Region ID cannot be null"; | ||
39 | + private static final String E_IDENTICAL = "Region IDs cannot be same"; | ||
40 | + | ||
41 | + private static final Comparator<RegionId> REGION_ID_COMPARATOR = | ||
42 | + (o1, o2) -> o1.toString().compareTo(o2.toString()); | ||
43 | + | ||
29 | /** | 44 | /** |
30 | * Designates the directionality of an underlying (uni-directional) link. | 45 | * Designates the directionality of an underlying (uni-directional) link. |
31 | */ | 46 | */ |
... | @@ -34,12 +49,15 @@ public final class UiLinkId { | ... | @@ -34,12 +49,15 @@ public final class UiLinkId { |
34 | B_TO_A | 49 | B_TO_A |
35 | } | 50 | } |
36 | 51 | ||
37 | - private static final String CP_DELIMITER = "~"; | 52 | + static final String CP_DELIMITER = "~"; |
38 | - private static final String ID_PORT_DELIMITER = "/"; | 53 | + static final String ID_PORT_DELIMITER = "/"; |
39 | 54 | ||
40 | - private final ElementId idA; | 55 | + private final RegionId regionA; |
56 | + private final ElementId elementA; | ||
41 | private final PortNumber portA; | 57 | private final PortNumber portA; |
42 | - private final ElementId idB; | 58 | + |
59 | + private final RegionId regionB; | ||
60 | + private final ElementId elementB; | ||
43 | private final PortNumber portB; | 61 | private final PortNumber portB; |
44 | 62 | ||
45 | private final String idStr; | 63 | private final String idStr; |
... | @@ -50,37 +68,81 @@ public final class UiLinkId { | ... | @@ -50,37 +68,81 @@ public final class UiLinkId { |
50 | * which is invariant to whether A or B is source or destination of the | 68 | * which is invariant to whether A or B is source or destination of the |
51 | * underlying link. | 69 | * underlying link. |
52 | * | 70 | * |
53 | - * @param a first element ID | 71 | + * @param a first element ID |
54 | * @param pa first element port | 72 | * @param pa first element port |
55 | - * @param b second element ID | 73 | + * @param b second element ID |
56 | * @param pb second element port | 74 | * @param pb second element port |
57 | */ | 75 | */ |
58 | private UiLinkId(ElementId a, PortNumber pa, ElementId b, PortNumber pb) { | 76 | private UiLinkId(ElementId a, PortNumber pa, ElementId b, PortNumber pb) { |
59 | - idA = a; | 77 | + elementA = a; |
60 | portA = pa; | 78 | portA = pa; |
61 | - idB = b; | 79 | + elementB = b; |
62 | portB = pb; | 80 | portB = pb; |
63 | 81 | ||
82 | + regionA = null; | ||
83 | + regionB = null; | ||
84 | + | ||
64 | idStr = a + ID_PORT_DELIMITER + pa + CP_DELIMITER + | 85 | idStr = a + ID_PORT_DELIMITER + pa + CP_DELIMITER + |
65 | b + ID_PORT_DELIMITER + pb; | 86 | b + ID_PORT_DELIMITER + pb; |
66 | } | 87 | } |
67 | 88 | ||
89 | + /** | ||
90 | + * Creates a UI link identifier. It is expected that A comes before B when | ||
91 | + * the two identifiers are naturally sorted. | ||
92 | + * | ||
93 | + * @param a first region ID | ||
94 | + * @param b second region ID | ||
95 | + */ | ||
96 | + private UiLinkId(RegionId a, RegionId b) { | ||
97 | + regionA = a; | ||
98 | + regionB = b; | ||
99 | + | ||
100 | + elementA = null; | ||
101 | + elementB = null; | ||
102 | + portA = null; | ||
103 | + portB = null; | ||
104 | + | ||
105 | + idStr = a + CP_DELIMITER + b; | ||
106 | + } | ||
107 | + | ||
108 | + /** | ||
109 | + * Creates a UI link identifier, with region at one end and a device/port | ||
110 | + * at the other. | ||
111 | + * | ||
112 | + * @param r region ID | ||
113 | + * @param d device ID | ||
114 | + * @param p port number | ||
115 | + */ | ||
116 | + private UiLinkId(RegionId r, DeviceId d, PortNumber p) { | ||
117 | + regionA = r; | ||
118 | + elementB = d; | ||
119 | + portB = p; | ||
120 | + | ||
121 | + regionB = null; | ||
122 | + elementA = null; | ||
123 | + portA = null; | ||
124 | + | ||
125 | + idStr = r + CP_DELIMITER + elementB + ID_PORT_DELIMITER + portB; | ||
126 | + } | ||
127 | + | ||
68 | @Override | 128 | @Override |
69 | public String toString() { | 129 | public String toString() { |
70 | return idStr; | 130 | return idStr; |
71 | } | 131 | } |
72 | 132 | ||
73 | /** | 133 | /** |
74 | - * Returns the identifier of the first element. | 134 | + * Returns the identifier of the first element. Note that the returned |
135 | + * value will be null if this identifier is for a region-region link. | ||
75 | * | 136 | * |
76 | * @return first element identity | 137 | * @return first element identity |
77 | */ | 138 | */ |
78 | public ElementId elementA() { | 139 | public ElementId elementA() { |
79 | - return idA; | 140 | + return elementA; |
80 | } | 141 | } |
81 | 142 | ||
82 | /** | 143 | /** |
83 | - * Returns the port of the first element. | 144 | + * Returns the port of the first element. Note that the returned |
145 | + * value will be null if this identifier is for a region-region link. | ||
84 | * | 146 | * |
85 | * @return first element port | 147 | * @return first element port |
86 | */ | 148 | */ |
... | @@ -89,16 +151,18 @@ public final class UiLinkId { | ... | @@ -89,16 +151,18 @@ public final class UiLinkId { |
89 | } | 151 | } |
90 | 152 | ||
91 | /** | 153 | /** |
92 | - * Returns the identifier of the second element. | 154 | + * Returns the identifier of the second element. Note that the returned |
155 | + * value will be null if this identifier is for a region-region link. | ||
93 | * | 156 | * |
94 | * @return second element identity | 157 | * @return second element identity |
95 | */ | 158 | */ |
96 | public ElementId elementB() { | 159 | public ElementId elementB() { |
97 | - return idB; | 160 | + return elementB; |
98 | } | 161 | } |
99 | 162 | ||
100 | /** | 163 | /** |
101 | - * Returns the port of the second element. | 164 | + * Returns the port of the second element. Note that the returned |
165 | + * value will be null if this identifier is for a region-region link. | ||
102 | * | 166 | * |
103 | * @return second element port | 167 | * @return second element port |
104 | */ | 168 | */ |
... | @@ -106,6 +170,28 @@ public final class UiLinkId { | ... | @@ -106,6 +170,28 @@ public final class UiLinkId { |
106 | return portB; | 170 | return portB; |
107 | } | 171 | } |
108 | 172 | ||
173 | + /** | ||
174 | + * Returns the identity of the first region. Note that the returned value | ||
175 | + * will be null if this identifier is for a device-device or device-host | ||
176 | + * link. | ||
177 | + * | ||
178 | + * @return first region ID | ||
179 | + */ | ||
180 | + public RegionId regionA() { | ||
181 | + return regionA; | ||
182 | + } | ||
183 | + | ||
184 | + /** | ||
185 | + * Returns the identity of the second region. Note that the returned value | ||
186 | + * will be null if this identifier is for a device-device or device-host | ||
187 | + * link. | ||
188 | + * | ||
189 | + * @return second region ID | ||
190 | + */ | ||
191 | + public RegionId regionB() { | ||
192 | + return regionB; | ||
193 | + } | ||
194 | + | ||
109 | @Override | 195 | @Override |
110 | public boolean equals(Object o) { | 196 | public boolean equals(Object o) { |
111 | if (this == o) { | 197 | if (this == o) { |
... | @@ -134,8 +220,8 @@ public final class UiLinkId { | ... | @@ -134,8 +220,8 @@ public final class UiLinkId { |
134 | Direction directionOf(Link link) { | 220 | Direction directionOf(Link link) { |
135 | ConnectPoint src = link.src(); | 221 | ConnectPoint src = link.src(); |
136 | ElementId srcId = src.elementId(); | 222 | ElementId srcId = src.elementId(); |
137 | - return idA.equals(srcId) ? Direction.A_TO_B | 223 | + return elementA.equals(srcId) ? Direction.A_TO_B |
138 | - : idB.equals(srcId) ? Direction.B_TO_A | 224 | + : elementB.equals(srcId) ? Direction.B_TO_A |
139 | : null; | 225 | : null; |
140 | } | 226 | } |
141 | 227 | ||
... | @@ -161,4 +247,42 @@ public final class UiLinkId { | ... | @@ -161,4 +247,42 @@ public final class UiLinkId { |
161 | return comp <= 0 ? new UiLinkId(srcId, src.port(), dstId, dst.port()) | 247 | return comp <= 0 ? new UiLinkId(srcId, src.port(), dstId, dst.port()) |
162 | : new UiLinkId(dstId, dst.port(), srcId, src.port()); | 248 | : new UiLinkId(dstId, dst.port(), srcId, src.port()); |
163 | } | 249 | } |
250 | + | ||
251 | + /** | ||
252 | + * Generates the canonical link identifier for a link between the | ||
253 | + * specified region nodes. | ||
254 | + * | ||
255 | + * @param one the first region ID | ||
256 | + * @param two the second region ID | ||
257 | + * @return link identifier | ||
258 | + * @throws NullPointerException if any of the required fields are null | ||
259 | + * @throws IllegalArgumentException if the identifiers are identical | ||
260 | + */ | ||
261 | + public static UiLinkId uiLinkId(RegionId one, RegionId two) { | ||
262 | + checkNotNull(one, E_REGION_ID_NULL); | ||
263 | + checkNotNull(two, E_REGION_ID_NULL); | ||
264 | + checkArgument(!one.equals(two), E_IDENTICAL); | ||
265 | + | ||
266 | + boolean flip = REGION_ID_COMPARATOR.compare(one, two) > 0; | ||
267 | + return flip ? new UiLinkId(two, one) : new UiLinkId(one, two); | ||
268 | + } | ||
269 | + | ||
270 | + /** | ||
271 | + * Generates the canonical link identifier for a link between the specified | ||
272 | + * region and device/port. | ||
273 | + * | ||
274 | + * @param regionId region ID | ||
275 | + * @param deviceId device ID | ||
276 | + * @param portNumber port number | ||
277 | + * @return link identifier | ||
278 | + * @throws NullPointerException if any of the required fields are null | ||
279 | + */ | ||
280 | + public static UiLinkId uiLinkId(RegionId regionId, DeviceId deviceId, | ||
281 | + PortNumber portNumber) { | ||
282 | + checkNotNull(regionId, E_REGION_ID_NULL); | ||
283 | + checkNotNull(deviceId, E_DEVICE_ID_NULL); | ||
284 | + checkNotNull(portNumber, E_PORT_NULL); | ||
285 | + | ||
286 | + return new UiLinkId(regionId, deviceId, portNumber); | ||
287 | + } | ||
164 | } | 288 | } | ... | ... |
... | @@ -53,7 +53,6 @@ public class UiRegion extends UiNode { | ... | @@ -53,7 +53,6 @@ public class UiRegion extends UiNode { |
53 | // loose bindings to things in this region | 53 | // loose bindings to things in this region |
54 | private final Set<DeviceId> deviceIds = new HashSet<>(); | 54 | private final Set<DeviceId> deviceIds = new HashSet<>(); |
55 | private final Set<HostId> hostIds = new HashSet<>(); | 55 | private final Set<HostId> hostIds = new HashSet<>(); |
56 | - private final Set<UiLinkId> uiLinkIds = new HashSet<>(); | ||
57 | 56 | ||
58 | private final List<String> layerOrder = new ArrayList<>(); | 57 | private final List<String> layerOrder = new ArrayList<>(); |
59 | 58 | ||
... | @@ -84,7 +83,6 @@ public class UiRegion extends UiNode { | ... | @@ -84,7 +83,6 @@ public class UiRegion extends UiNode { |
84 | protected void destroy() { | 83 | protected void destroy() { |
85 | deviceIds.clear(); | 84 | deviceIds.clear(); |
86 | hostIds.clear(); | 85 | hostIds.clear(); |
87 | - uiLinkIds.clear(); | ||
88 | } | 86 | } |
89 | 87 | ||
90 | /** | 88 | /** |
... | @@ -135,6 +133,15 @@ public class UiRegion extends UiNode { | ... | @@ -135,6 +133,15 @@ public class UiRegion extends UiNode { |
135 | } | 133 | } |
136 | 134 | ||
137 | /** | 135 | /** |
136 | + * Returns the UI region that is the parent of this region. | ||
137 | + * | ||
138 | + * @return the parent region | ||
139 | + */ | ||
140 | + public UiRegion parentRegion() { | ||
141 | + return topology.findRegion(parent); | ||
142 | + } | ||
143 | + | ||
144 | + /** | ||
138 | * Sets the parent ID for this region. | 145 | * Sets the parent ID for this region. |
139 | * | 146 | * |
140 | * @param parentId parent ID | 147 | * @param parentId parent ID |
... | @@ -192,7 +199,6 @@ public class UiRegion extends UiNode { | ... | @@ -192,7 +199,6 @@ public class UiRegion extends UiNode { |
192 | .add("kids", kids) | 199 | .add("kids", kids) |
193 | .add("devices", deviceIds) | 200 | .add("devices", deviceIds) |
194 | .add("#hosts", hostIds.size()) | 201 | .add("#hosts", hostIds.size()) |
195 | - .add("#links", uiLinkIds.size()) | ||
196 | .toString(); | 202 | .toString(); |
197 | } | 203 | } |
198 | 204 | ||
... | @@ -252,24 +258,6 @@ public class UiRegion extends UiNode { | ... | @@ -252,24 +258,6 @@ public class UiRegion extends UiNode { |
252 | } | 258 | } |
253 | 259 | ||
254 | /** | 260 | /** |
255 | - * Returns the set of link identifiers for this region. | ||
256 | - * | ||
257 | - * @return link identifiers for this region | ||
258 | - */ | ||
259 | - public Set<UiLinkId> linkIds() { | ||
260 | - return ImmutableSet.copyOf(uiLinkIds); | ||
261 | - } | ||
262 | - | ||
263 | - /** | ||
264 | - * Returns the links in this region. | ||
265 | - * | ||
266 | - * @return the links in this region | ||
267 | - */ | ||
268 | - public Set<UiLink> links() { | ||
269 | - return topology.linkSet(uiLinkIds); | ||
270 | - } | ||
271 | - | ||
272 | - /** | ||
273 | * Returns the order in which layers should be rendered. Lower layers | 261 | * Returns the order in which layers should be rendered. Lower layers |
274 | * come earlier in the list. For example, to indicate that nodes in the | 262 | * come earlier in the list. For example, to indicate that nodes in the |
275 | * optical layer should be rendered "below" nodes in the packet layer, | 263 | * optical layer should be rendered "below" nodes in the packet layer, | ... | ... |
1 | +/* | ||
2 | + * Copyright 2016-present 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.ui.model.topo; | ||
18 | + | ||
19 | +import org.onosproject.net.DeviceId; | ||
20 | +import org.onosproject.net.PortNumber; | ||
21 | +import org.onosproject.net.region.RegionId; | ||
22 | + | ||
23 | + | ||
24 | +/** | ||
25 | + * Designates a link between a region node and a device. | ||
26 | + */ | ||
27 | +public class UiRegionDeviceLink extends UiLink { | ||
28 | + | ||
29 | + private static final String E_NOT_REGION_DEVICE_ID = | ||
30 | + "UI link identifier not region to device"; | ||
31 | + | ||
32 | + // private (synthetic) region-device link | ||
33 | + private final RegionId region; | ||
34 | + private final DeviceId device; | ||
35 | + private final PortNumber port; | ||
36 | + | ||
37 | + /** | ||
38 | + * Creates a region to device UI link. Note that it is expected that the | ||
39 | + * link identifier is one that has a region ID at one end, and a device | ||
40 | + * ID at the other | ||
41 | + * | ||
42 | + * @param topology parent topology | ||
43 | + * @param id canonicalized link identifier | ||
44 | + * @throws IllegalArgumentException if the link ID is not region-region | ||
45 | + */ | ||
46 | + public UiRegionDeviceLink(UiTopology topology, UiLinkId id) { | ||
47 | + super(topology, id); | ||
48 | + region = id.regionA(); | ||
49 | + device = (DeviceId) id.elementB(); | ||
50 | + port = id.portB(); | ||
51 | + if (region == null || device == null || port == null) { | ||
52 | + throw new IllegalArgumentException(E_NOT_REGION_DEVICE_ID); | ||
53 | + } | ||
54 | + } | ||
55 | + | ||
56 | + @Override | ||
57 | + public String endPointA() { | ||
58 | + return region.id(); | ||
59 | + } | ||
60 | + | ||
61 | + @Override | ||
62 | + public String endPointB() { | ||
63 | + return device + UiLinkId.ID_PORT_DELIMITER + port; | ||
64 | + } | ||
65 | + | ||
66 | + /** | ||
67 | + * Returns the identity of the region. | ||
68 | + * | ||
69 | + * @return region ID | ||
70 | + */ | ||
71 | + public RegionId region() { | ||
72 | + return region; | ||
73 | + } | ||
74 | + | ||
75 | + /** | ||
76 | + * Returns the identity of the device. | ||
77 | + * | ||
78 | + * @return device ID | ||
79 | + */ | ||
80 | + public DeviceId device() { | ||
81 | + return device; | ||
82 | + } | ||
83 | + | ||
84 | + /** | ||
85 | + * Returns the identity of the device port. | ||
86 | + * | ||
87 | + * @return device port number | ||
88 | + */ | ||
89 | + public PortNumber port() { | ||
90 | + return port; | ||
91 | + } | ||
92 | +} |
1 | +/* | ||
2 | + * Copyright 2016-present 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.ui.model.topo; | ||
18 | + | ||
19 | +import org.onosproject.net.region.RegionId; | ||
20 | + | ||
21 | + | ||
22 | +/** | ||
23 | + * Designates a link between two region nodes. | ||
24 | + */ | ||
25 | +public class UiRegionLink extends UiLink { | ||
26 | + | ||
27 | + private static final String E_NOT_REGION_ID = | ||
28 | + "UI link identifier not region to region"; | ||
29 | + | ||
30 | + // private (synthetic) region - region link | ||
31 | + private final RegionId regionA; | ||
32 | + private final RegionId regionB; | ||
33 | + | ||
34 | + /** | ||
35 | + * Creates a region to region UI link. Note that it is expected that the | ||
36 | + * link identifier is one that has region IDs as source and destination. | ||
37 | + * | ||
38 | + * @param topology parent topology | ||
39 | + * @param id canonicalized link identifier | ||
40 | + * @throws IllegalArgumentException if the link ID is not region-region | ||
41 | + */ | ||
42 | + public UiRegionLink(UiTopology topology, UiLinkId id) { | ||
43 | + super(topology, id); | ||
44 | + regionA = id.regionA(); | ||
45 | + regionB = id.regionB(); | ||
46 | + if (regionA == null || regionB == null) { | ||
47 | + throw new IllegalArgumentException(E_NOT_REGION_ID); | ||
48 | + } | ||
49 | + } | ||
50 | + | ||
51 | + @Override | ||
52 | + public String endPointA() { | ||
53 | + return regionA.id(); | ||
54 | + } | ||
55 | + | ||
56 | + @Override | ||
57 | + public String endPointB() { | ||
58 | + return regionB.id(); | ||
59 | + } | ||
60 | + | ||
61 | + /** | ||
62 | + * Returns the identity of the first region. | ||
63 | + * | ||
64 | + * @return first region ID | ||
65 | + */ | ||
66 | + public RegionId regionA() { | ||
67 | + return regionA; | ||
68 | + } | ||
69 | + | ||
70 | + /** | ||
71 | + * Returns the identity of the second region. | ||
72 | + * | ||
73 | + * @return second region ID | ||
74 | + */ | ||
75 | + public RegionId regionB() { | ||
76 | + return regionB; | ||
77 | + } | ||
78 | +} |
1 | +/* | ||
2 | + * Copyright 2016-present 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.ui.model.topo; | ||
18 | + | ||
19 | +import org.onosproject.net.region.RegionId; | ||
20 | + | ||
21 | +import static com.google.common.base.MoreObjects.toStringHelper; | ||
22 | + | ||
23 | +/** | ||
24 | + * A synthetic link that encapsulates a UiLink instance and the region to | ||
25 | + * which it belongs. | ||
26 | + */ | ||
27 | +public class UiSynthLink { | ||
28 | + | ||
29 | + private final RegionId regionId; | ||
30 | + private final UiLink link; | ||
31 | + | ||
32 | + /** | ||
33 | + * Constructs a synthetic link with the given parameters. | ||
34 | + * | ||
35 | + * @param regionId the region to which the link belongs | ||
36 | + * @param link the link instance | ||
37 | + */ | ||
38 | + public UiSynthLink(RegionId regionId, UiLink link) { | ||
39 | + this.regionId = regionId; | ||
40 | + this.link = link; | ||
41 | + } | ||
42 | + | ||
43 | + @Override | ||
44 | + public String toString() { | ||
45 | + return toStringHelper(this) | ||
46 | + .add("region", regionId) | ||
47 | + .add("link", link) | ||
48 | + .toString(); | ||
49 | + } | ||
50 | + | ||
51 | + /** | ||
52 | + * Returns the region identifier. | ||
53 | + * | ||
54 | + * @return the region ID | ||
55 | + */ | ||
56 | + public RegionId regionId() { | ||
57 | + return regionId; | ||
58 | + } | ||
59 | + | ||
60 | + /** | ||
61 | + * Returns the link. | ||
62 | + * | ||
63 | + * @return the link | ||
64 | + */ | ||
65 | + public UiLink link() { | ||
66 | + return link; | ||
67 | + } | ||
68 | +} |
... | @@ -19,6 +19,7 @@ package org.onosproject.ui.model.topo; | ... | @@ -19,6 +19,7 @@ package org.onosproject.ui.model.topo; |
19 | import org.onosproject.cluster.NodeId; | 19 | import org.onosproject.cluster.NodeId; |
20 | import org.onosproject.net.DeviceId; | 20 | import org.onosproject.net.DeviceId; |
21 | import org.onosproject.net.HostId; | 21 | import org.onosproject.net.HostId; |
22 | +import org.onosproject.net.PortNumber; | ||
22 | import org.onosproject.net.region.RegionId; | 23 | import org.onosproject.net.region.RegionId; |
23 | import org.slf4j.Logger; | 24 | import org.slf4j.Logger; |
24 | import org.slf4j.LoggerFactory; | 25 | import org.slf4j.LoggerFactory; |
... | @@ -30,9 +31,12 @@ import java.util.HashMap; | ... | @@ -30,9 +31,12 @@ import java.util.HashMap; |
30 | import java.util.HashSet; | 31 | import java.util.HashSet; |
31 | import java.util.List; | 32 | import java.util.List; |
32 | import java.util.Map; | 33 | import java.util.Map; |
34 | +import java.util.Objects; | ||
33 | import java.util.Set; | 35 | import java.util.Set; |
36 | +import java.util.stream.Collectors; | ||
34 | 37 | ||
35 | import static com.google.common.base.MoreObjects.toStringHelper; | 38 | import static com.google.common.base.MoreObjects.toStringHelper; |
39 | +import static org.onosproject.ui.model.topo.UiLinkId.uiLinkId; | ||
36 | 40 | ||
37 | /** | 41 | /** |
38 | * Represents the overall network topology. | 42 | * Represents the overall network topology. |
... | @@ -59,7 +63,11 @@ public class UiTopology extends UiElement { | ... | @@ -59,7 +63,11 @@ public class UiTopology extends UiElement { |
59 | private final Map<RegionId, UiRegion> regionLookup = new HashMap<>(); | 63 | private final Map<RegionId, UiRegion> regionLookup = new HashMap<>(); |
60 | private final Map<DeviceId, UiDevice> deviceLookup = new HashMap<>(); | 64 | private final Map<DeviceId, UiDevice> deviceLookup = new HashMap<>(); |
61 | private final Map<HostId, UiHost> hostLookup = new HashMap<>(); | 65 | private final Map<HostId, UiHost> hostLookup = new HashMap<>(); |
62 | - private final Map<UiLinkId, UiLink> linkLookup = new HashMap<>(); | 66 | + private final Map<UiLinkId, UiDeviceLink> devLinkLookup = new HashMap<>(); |
67 | + private final Map<UiLinkId, UiEdgeLink> edgeLinkLookup = new HashMap<>(); | ||
68 | + | ||
69 | + // a cache of the computed synthetic links | ||
70 | + private final List<UiSynthLink> synthLinks = new ArrayList<>(); | ||
63 | 71 | ||
64 | // a container for devices, hosts, etc. belonging to no region | 72 | // a container for devices, hosts, etc. belonging to no region |
65 | private final UiRegion nullRegion = new UiRegion(this, null); | 73 | private final UiRegion nullRegion = new UiRegion(this, null); |
... | @@ -72,7 +80,9 @@ public class UiTopology extends UiElement { | ... | @@ -72,7 +80,9 @@ public class UiTopology extends UiElement { |
72 | .add("#regions", regionCount()) | 80 | .add("#regions", regionCount()) |
73 | .add("#devices", deviceLookup.size()) | 81 | .add("#devices", deviceLookup.size()) |
74 | .add("#hosts", hostLookup.size()) | 82 | .add("#hosts", hostLookup.size()) |
75 | - .add("#links", linkLookup.size()) | 83 | + .add("#dev-links", devLinkLookup.size()) |
84 | + .add("#edge-links", edgeLinkLookup.size()) | ||
85 | + .add("#synth-links", synthLinks.size()) | ||
76 | .toString(); | 86 | .toString(); |
77 | } | 87 | } |
78 | 88 | ||
... | @@ -91,7 +101,10 @@ public class UiTopology extends UiElement { | ... | @@ -91,7 +101,10 @@ public class UiTopology extends UiElement { |
91 | regionLookup.clear(); | 101 | regionLookup.clear(); |
92 | deviceLookup.clear(); | 102 | deviceLookup.clear(); |
93 | hostLookup.clear(); | 103 | hostLookup.clear(); |
94 | - linkLookup.clear(); | 104 | + devLinkLookup.clear(); |
105 | + edgeLinkLookup.clear(); | ||
106 | + | ||
107 | + synthLinks.clear(); | ||
95 | 108 | ||
96 | nullRegion.destroy(); | 109 | nullRegion.destroy(); |
97 | } | 110 | } |
... | @@ -261,54 +274,96 @@ public class UiTopology extends UiElement { | ... | @@ -261,54 +274,96 @@ public class UiTopology extends UiElement { |
261 | return deviceLookup.size(); | 274 | return deviceLookup.size(); |
262 | } | 275 | } |
263 | 276 | ||
277 | + | ||
264 | /** | 278 | /** |
265 | - * Returns all links in the model. | 279 | + * Returns all device links in the model. |
266 | * | 280 | * |
267 | - * @return all links | 281 | + * @return all device links |
268 | */ | 282 | */ |
269 | - public Set<UiLink> allLinks() { | 283 | + public Set<UiDeviceLink> allDeviceLinks() { |
270 | - return new HashSet<>(linkLookup.values()); | 284 | + return new HashSet<>(devLinkLookup.values()); |
271 | } | 285 | } |
272 | 286 | ||
273 | /** | 287 | /** |
274 | - * Returns the link with the specified identifier, or null if no such | 288 | + * Returns the device link with the specified identifier, or null if no |
275 | - * link exists. | 289 | + * such link exists. |
276 | * | 290 | * |
277 | * @param id the canonicalized link identifier | 291 | * @param id the canonicalized link identifier |
278 | - * @return corresponding UI link | 292 | + * @return corresponding UI device link |
279 | */ | 293 | */ |
280 | - public UiLink findLink(UiLinkId id) { | 294 | + public UiDeviceLink findDeviceLink(UiLinkId id) { |
281 | - return linkLookup.get(id); | 295 | + return devLinkLookup.get(id); |
282 | } | 296 | } |
283 | 297 | ||
284 | /** | 298 | /** |
285 | - * Adds the given UI link to the topology model. | 299 | + * Returns the edge link with the specified identifier, or null if no |
300 | + * such link exists. | ||
286 | * | 301 | * |
287 | - * @param uiLink link to add | 302 | + * @param id the canonicalized link identifier |
303 | + * @return corresponding UI edge link | ||
288 | */ | 304 | */ |
289 | - public void add(UiLink uiLink) { | 305 | + public UiEdgeLink findEdgeLink(UiLinkId id) { |
290 | - linkLookup.put(uiLink.id(), uiLink); | 306 | + return edgeLinkLookup.get(id); |
307 | + } | ||
308 | + | ||
309 | + /** | ||
310 | + * Adds the given UI device link to the topology model. | ||
311 | + * | ||
312 | + * @param uiDeviceLink link to add | ||
313 | + */ | ||
314 | + public void add(UiDeviceLink uiDeviceLink) { | ||
315 | + devLinkLookup.put(uiDeviceLink.id(), uiDeviceLink); | ||
316 | + } | ||
317 | + | ||
318 | + /** | ||
319 | + * Adds the given UI edge link to the topology model. | ||
320 | + * | ||
321 | + * @param uiEdgeLink link to add | ||
322 | + */ | ||
323 | + public void add(UiEdgeLink uiEdgeLink) { | ||
324 | + edgeLinkLookup.put(uiEdgeLink.id(), uiEdgeLink); | ||
325 | + } | ||
326 | + | ||
327 | + /** | ||
328 | + * Removes the given UI device link from the model. | ||
329 | + * | ||
330 | + * @param uiDeviceLink link to remove | ||
331 | + */ | ||
332 | + public void remove(UiDeviceLink uiDeviceLink) { | ||
333 | + UiDeviceLink link = devLinkLookup.remove(uiDeviceLink.id()); | ||
334 | + if (link != null) { | ||
335 | + link.destroy(); | ||
336 | + } | ||
291 | } | 337 | } |
292 | 338 | ||
293 | /** | 339 | /** |
294 | - * Removes the given UI link from the model. | 340 | + * Removes the given UI edge link from the model. |
295 | * | 341 | * |
296 | - * @param uiLink link to remove | 342 | + * @param uiEdgeLink link to remove |
297 | */ | 343 | */ |
298 | - public void remove(UiLink uiLink) { | 344 | + public void remove(UiEdgeLink uiEdgeLink) { |
299 | - UiLink link = linkLookup.remove(uiLink.id()); | 345 | + UiEdgeLink link = edgeLinkLookup.remove(uiEdgeLink.id()); |
300 | if (link != null) { | 346 | if (link != null) { |
301 | link.destroy(); | 347 | link.destroy(); |
302 | } | 348 | } |
303 | } | 349 | } |
304 | 350 | ||
305 | /** | 351 | /** |
306 | - * Returns the number of links configured in the topology. | 352 | + * Returns the number of device links configured in the topology. |
353 | + * | ||
354 | + * @return number of device links | ||
355 | + */ | ||
356 | + public int deviceLinkCount() { | ||
357 | + return devLinkLookup.size(); | ||
358 | + } | ||
359 | + | ||
360 | + /** | ||
361 | + * Returns the number of edge links configured in the topology. | ||
307 | * | 362 | * |
308 | - * @return number of links | 363 | + * @return number of edge links |
309 | */ | 364 | */ |
310 | - public int linkCount() { | 365 | + public int edgeLinkCount() { |
311 | - return linkLookup.size(); | 366 | + return edgeLinkLookup.size(); |
312 | } | 367 | } |
313 | 368 | ||
314 | /** | 369 | /** |
... | @@ -405,22 +460,198 @@ public class UiTopology extends UiElement { | ... | @@ -405,22 +460,198 @@ public class UiTopology extends UiElement { |
405 | } | 460 | } |
406 | 461 | ||
407 | /** | 462 | /** |
408 | - * Returns the set of UI links with the given identifiers. | 463 | + * Returns the set of UI device links with the given identifiers. |
409 | * | 464 | * |
410 | * @param uiLinkIds link identifiers | 465 | * @param uiLinkIds link identifiers |
411 | - * @return set of matching UI link instances | 466 | + * @return set of matching UI device link instances |
412 | */ | 467 | */ |
413 | - Set<UiLink> linkSet(Set<UiLinkId> uiLinkIds) { | 468 | + Set<UiDeviceLink> linkSet(Set<UiLinkId> uiLinkIds) { |
414 | - Set<UiLink> uiLinks = new HashSet<>(); | 469 | + Set<UiDeviceLink> result = new HashSet<>(); |
415 | for (UiLinkId id : uiLinkIds) { | 470 | for (UiLinkId id : uiLinkIds) { |
416 | - UiLink link = linkLookup.get(id); | 471 | + UiDeviceLink link = devLinkLookup.get(id); |
417 | if (link != null) { | 472 | if (link != null) { |
418 | - uiLinks.add(link); | 473 | + result.add(link); |
419 | } else { | 474 | } else { |
420 | - log.warn(E_UNMAPPED, "link", id); | 475 | + log.warn(E_UNMAPPED, "device link", id); |
421 | } | 476 | } |
422 | } | 477 | } |
423 | - return uiLinks; | 478 | + return result; |
479 | + } | ||
480 | + | ||
481 | + /** | ||
482 | + * Uses the device-device links and data about the regions to compute the | ||
483 | + * set of synthetic links that are required per region. | ||
484 | + */ | ||
485 | + public void computeSynthLinks() { | ||
486 | + List<UiSynthLink> slinks = new ArrayList<>(); | ||
487 | + allDeviceLinks().forEach((link) -> { | ||
488 | + UiSynthLink synthetic = inferSyntheticLink(link); | ||
489 | + slinks.add(synthetic); | ||
490 | + log.debug("Synthetic link: {}", synthetic); | ||
491 | + }); | ||
492 | + | ||
493 | + synthLinks.clear(); | ||
494 | + synthLinks.addAll(slinks); | ||
495 | + } | ||
496 | + | ||
497 | + private UiSynthLink inferSyntheticLink(UiDeviceLink link) { | ||
498 | + /* | ||
499 | + Look at the containment hierarchy of each end of the link. Find the | ||
500 | + common ancestor region R. A synthetic link will be added to R, based | ||
501 | + on the "next" node back down the branch... | ||
502 | + | ||
503 | + S1 --- S2 * in the same region ... | ||
504 | + : : | ||
505 | + R R return S1 --- S2 (same link instance) | ||
506 | + | ||
507 | + | ||
508 | + S1 --- S2 * in different regions (R1, R2) at same level | ||
509 | + : : | ||
510 | + R1 R2 return R1 --- R2 | ||
511 | + : : | ||
512 | + R R | ||
513 | + | ||
514 | + S1 --- S2 * in different regions at different levels | ||
515 | + : : | ||
516 | + R1 R2 return R1 --- R3 | ||
517 | + : : | ||
518 | + R R3 | ||
519 | + : | ||
520 | + R | ||
521 | + | ||
522 | + S1 --- S2 * in different regions at different levels | ||
523 | + : : | ||
524 | + R R2 return S1 --- R2 | ||
525 | + : | ||
526 | + R | ||
527 | + | ||
528 | + */ | ||
529 | + DeviceId a = link.deviceA(); | ||
530 | + DeviceId b = link.deviceB(); | ||
531 | + List<RegionId> aBranch = ancestors(a); | ||
532 | + List<RegionId> bBranch = ancestors(b); | ||
533 | + if (aBranch == null || bBranch == null) { | ||
534 | + return null; | ||
535 | + } | ||
536 | + | ||
537 | + return makeSynthLink(link, aBranch, bBranch); | ||
538 | + } | ||
539 | + | ||
540 | + // package private for unit testing | ||
541 | + UiSynthLink makeSynthLink(UiDeviceLink orig, | ||
542 | + List<RegionId> aBranch, | ||
543 | + List<RegionId> bBranch) { | ||
544 | + | ||
545 | + final int aSize = aBranch.size(); | ||
546 | + final int bSize = bBranch.size(); | ||
547 | + final int min = Math.min(aSize, bSize); | ||
548 | + | ||
549 | + int index = 0; | ||
550 | + RegionId commonRegion = aBranch.get(index); | ||
551 | + | ||
552 | + while (true) { | ||
553 | + int next = index + 1; | ||
554 | + if (next == min) { | ||
555 | + // no more pairs of regions left to test | ||
556 | + break; | ||
557 | + } | ||
558 | + RegionId rA = aBranch.get(next); | ||
559 | + RegionId rB = bBranch.get(next); | ||
560 | + if (rA.equals(rB)) { | ||
561 | + commonRegion = rA; | ||
562 | + index++; | ||
563 | + } else { | ||
564 | + break; | ||
565 | + } | ||
566 | + } | ||
567 | + | ||
568 | + | ||
569 | + int endPointIndex = index + 1; | ||
570 | + UiLinkId linkId; | ||
571 | + UiLink link; | ||
572 | + | ||
573 | + if (endPointIndex < aSize) { | ||
574 | + // the A endpoint is a subregion | ||
575 | + RegionId aRegion = aBranch.get(endPointIndex); | ||
576 | + | ||
577 | + if (endPointIndex < bSize) { | ||
578 | + // the B endpoint is a subregion | ||
579 | + RegionId bRegion = bBranch.get(endPointIndex); | ||
580 | + | ||
581 | + linkId = uiLinkId(aRegion, bRegion); | ||
582 | + link = new UiRegionLink(this, linkId); | ||
583 | + | ||
584 | + } else { | ||
585 | + // the B endpoint is the device | ||
586 | + DeviceId dB = orig.deviceB(); | ||
587 | + PortNumber pB = orig.portB(); | ||
588 | + | ||
589 | + linkId = uiLinkId(aRegion, dB, pB); | ||
590 | + link = new UiRegionDeviceLink(this, linkId); | ||
591 | + } | ||
592 | + | ||
593 | + } else { | ||
594 | + // the A endpoint is the device | ||
595 | + DeviceId dA = orig.deviceA(); | ||
596 | + PortNumber pA = orig.portA(); | ||
597 | + | ||
598 | + if (endPointIndex < bSize) { | ||
599 | + // the B endpoint is a subregion | ||
600 | + RegionId bRegion = bBranch.get(endPointIndex); | ||
601 | + | ||
602 | + linkId = uiLinkId(bRegion, dA, pA); | ||
603 | + link = new UiRegionDeviceLink(this, linkId); | ||
604 | + | ||
605 | + } else { | ||
606 | + // the B endpoint is the device | ||
607 | + // (so, we can just use the original device-device link...) | ||
608 | + | ||
609 | + link = orig; | ||
610 | + } | ||
611 | + } | ||
612 | + return new UiSynthLink(commonRegion, link); | ||
613 | + } | ||
614 | + | ||
615 | + private List<RegionId> ancestors(DeviceId id) { | ||
616 | + // return the ancestor chain from this device to root region | ||
617 | + UiDevice dev = findDevice(id); | ||
618 | + if (dev == null) { | ||
619 | + log.warn("Unable to find cached device with ID %s", id); | ||
620 | + return null; | ||
621 | + } | ||
622 | + | ||
623 | + UiRegion r = dev.uiRegion(); | ||
624 | + List<RegionId> result = new ArrayList<>(); | ||
625 | + while (r != null && !r.isRoot()) { | ||
626 | + result.add(0, r.id()); | ||
627 | + r = r.parentRegion(); | ||
628 | + } | ||
629 | + // finally add root region, since this is the grand-daddy of them all | ||
630 | + result.add(0, UiRegion.NULL_ID); | ||
631 | + return result; | ||
632 | + } | ||
633 | + | ||
634 | + | ||
635 | + /** | ||
636 | + * Returns the synthetic links associated with the specified region. | ||
637 | + * | ||
638 | + * @param regionId the region ID | ||
639 | + * @return synthetic links for this region | ||
640 | + */ | ||
641 | + public List<UiSynthLink> findSynthLinks(RegionId regionId) { | ||
642 | + return synthLinks.stream() | ||
643 | + .filter(s -> Objects.equals(regionId, s.regionId())) | ||
644 | + .collect(Collectors.toList()); | ||
645 | + } | ||
646 | + | ||
647 | + | ||
648 | + /** | ||
649 | + * Returns the number of synthetic links in the topology. | ||
650 | + * | ||
651 | + * @return the synthetic link count | ||
652 | + */ | ||
653 | + public int synthLinkCount() { | ||
654 | + return synthLinks.size(); | ||
424 | } | 655 | } |
425 | 656 | ||
426 | /** | 657 | /** |
... | @@ -452,13 +683,22 @@ public class UiTopology extends UiElement { | ... | @@ -452,13 +683,22 @@ public class UiTopology extends UiElement { |
452 | sb.append(INDENT_2).append(h).append(EOL); | 683 | sb.append(INDENT_2).append(h).append(EOL); |
453 | } | 684 | } |
454 | 685 | ||
455 | - sb.append(INDENT_1).append("Links").append(EOL); | 686 | + sb.append(INDENT_1).append("Device Links").append(EOL); |
456 | - for (UiLink link : linkLookup.values()) { | 687 | + for (UiLink link : devLinkLookup.values()) { |
688 | + sb.append(INDENT_2).append(link).append(EOL); | ||
689 | + } | ||
690 | + | ||
691 | + sb.append(INDENT_1).append("Edge Links").append(EOL); | ||
692 | + for (UiLink link : edgeLinkLookup.values()) { | ||
693 | + sb.append(INDENT_2).append(link).append(EOL); | ||
694 | + } | ||
695 | + | ||
696 | + sb.append(INDENT_1).append("Synth Links").append(EOL); | ||
697 | + for (UiSynthLink link : synthLinks) { | ||
457 | sb.append(INDENT_2).append(link).append(EOL); | 698 | sb.append(INDENT_2).append(link).append(EOL); |
458 | } | 699 | } |
459 | sb.append("------").append(EOL); | 700 | sb.append("------").append(EOL); |
460 | 701 | ||
461 | return sb.toString(); | 702 | return sb.toString(); |
462 | } | 703 | } |
463 | - | ||
464 | } | 704 | } | ... | ... |
1 | +/* | ||
2 | + * Copyright 2016-present 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.ui.model.topo; | ||
18 | + | ||
19 | +import org.junit.Test; | ||
20 | +import org.onosproject.net.ConnectPoint; | ||
21 | +import org.onosproject.net.DefaultEdgeLink; | ||
22 | +import org.onosproject.net.DeviceId; | ||
23 | +import org.onosproject.net.EdgeLink; | ||
24 | +import org.onosproject.net.PortNumber; | ||
25 | +import org.onosproject.ui.model.AbstractUiModelTest; | ||
26 | + | ||
27 | +import static org.junit.Assert.assertEquals; | ||
28 | + | ||
29 | +/** | ||
30 | + * Unit tests for {@link UiEdgeLink}. | ||
31 | + */ | ||
32 | +public class UiEdgeLinkTest extends AbstractUiModelTest { | ||
33 | + | ||
34 | + private static final String PHANTOM_HOST_ID = "00:00:00:00:00:00/None"; | ||
35 | + private static final String D1_P8 = "dev-1/8"; | ||
36 | + | ||
37 | + private static final DeviceId DEV = DeviceId.deviceId("dev-1"); | ||
38 | + private static final PortNumber P8 = PortNumber.portNumber(8); | ||
39 | + private static final ConnectPoint CP = new ConnectPoint(DEV, P8); | ||
40 | + | ||
41 | + private static final EdgeLink EDGE_LINK = | ||
42 | + DefaultEdgeLink.createEdgeLink(CP, true); | ||
43 | + | ||
44 | + @Test | ||
45 | + public void basic() { | ||
46 | + title("basic"); | ||
47 | + UiLinkId id = UiLinkId.uiLinkId(EDGE_LINK); | ||
48 | + UiEdgeLink link = new UiEdgeLink(null, id); | ||
49 | + link.attachEdgeLink(EDGE_LINK); | ||
50 | + print(link); | ||
51 | + print(link.endPointA()); | ||
52 | + print(link.endPointB()); | ||
53 | + | ||
54 | + assertEquals("bad end point A", PHANTOM_HOST_ID, link.endPointA()); | ||
55 | + assertEquals("bad end point B", D1_P8, link.endPointB()); | ||
56 | + } | ||
57 | +} |
... | @@ -17,17 +17,23 @@ | ... | @@ -17,17 +17,23 @@ |
17 | package org.onosproject.ui.model.topo; | 17 | package org.onosproject.ui.model.topo; |
18 | 18 | ||
19 | import org.junit.Test; | 19 | import org.junit.Test; |
20 | +import org.onlab.packet.MacAddress; | ||
20 | import org.onosproject.net.ConnectPoint; | 21 | import org.onosproject.net.ConnectPoint; |
21 | import org.onosproject.net.DefaultLink; | 22 | import org.onosproject.net.DefaultLink; |
22 | import org.onosproject.net.DeviceId; | 23 | import org.onosproject.net.DeviceId; |
24 | +import org.onosproject.net.HostId; | ||
23 | import org.onosproject.net.Link; | 25 | import org.onosproject.net.Link; |
24 | import org.onosproject.net.PortNumber; | 26 | import org.onosproject.net.PortNumber; |
25 | import org.onosproject.net.provider.ProviderId; | 27 | import org.onosproject.net.provider.ProviderId; |
28 | +import org.onosproject.net.region.RegionId; | ||
26 | import org.onosproject.ui.model.AbstractUiModelTest; | 29 | import org.onosproject.ui.model.AbstractUiModelTest; |
27 | 30 | ||
28 | import static org.junit.Assert.assertEquals; | 31 | import static org.junit.Assert.assertEquals; |
29 | import static org.junit.Assert.assertNotEquals; | 32 | import static org.junit.Assert.assertNotEquals; |
33 | +import static org.junit.Assert.assertNull; | ||
30 | import static org.onosproject.net.DeviceId.deviceId; | 34 | import static org.onosproject.net.DeviceId.deviceId; |
35 | +import static org.onosproject.net.HostId.hostId; | ||
36 | +import static org.onosproject.net.PortNumber.P0; | ||
31 | import static org.onosproject.net.PortNumber.portNumber; | 37 | import static org.onosproject.net.PortNumber.portNumber; |
32 | 38 | ||
33 | /** | 39 | /** |
... | @@ -35,8 +41,15 @@ import static org.onosproject.net.PortNumber.portNumber; | ... | @@ -35,8 +41,15 @@ import static org.onosproject.net.PortNumber.portNumber; |
35 | */ | 41 | */ |
36 | public class UiLinkIdTest extends AbstractUiModelTest { | 42 | public class UiLinkIdTest extends AbstractUiModelTest { |
37 | 43 | ||
44 | + private static final RegionId REG_1 = RegionId.regionId("Region-1"); | ||
45 | + private static final RegionId REG_2 = RegionId.regionId("Region-2"); | ||
46 | + | ||
47 | + private static final MacAddress MAC_A = MacAddress.valueOf(0x123456L); | ||
48 | + private static final HostId HOST_A = hostId(MAC_A); | ||
49 | + | ||
38 | private static final DeviceId DEV_X = deviceId("device-X"); | 50 | private static final DeviceId DEV_X = deviceId("device-X"); |
39 | private static final DeviceId DEV_Y = deviceId("device-Y"); | 51 | private static final DeviceId DEV_Y = deviceId("device-Y"); |
52 | + | ||
40 | private static final PortNumber P1 = portNumber(1); | 53 | private static final PortNumber P1 = portNumber(1); |
41 | private static final PortNumber P2 = portNumber(2); | 54 | private static final PortNumber P2 = portNumber(2); |
42 | private static final PortNumber P3 = portNumber(3); | 55 | private static final PortNumber P3 = portNumber(3); |
... | @@ -45,6 +58,8 @@ public class UiLinkIdTest extends AbstractUiModelTest { | ... | @@ -45,6 +58,8 @@ public class UiLinkIdTest extends AbstractUiModelTest { |
45 | private static final ConnectPoint CP_Y2 = new ConnectPoint(DEV_Y, P2); | 58 | private static final ConnectPoint CP_Y2 = new ConnectPoint(DEV_Y, P2); |
46 | private static final ConnectPoint CP_Y3 = new ConnectPoint(DEV_Y, P3); | 59 | private static final ConnectPoint CP_Y3 = new ConnectPoint(DEV_Y, P3); |
47 | 60 | ||
61 | + private static final ConnectPoint CP_HA = new ConnectPoint(HOST_A, P0); | ||
62 | + | ||
48 | private static final Link LINK_X1_TO_Y2 = DefaultLink.builder() | 63 | private static final Link LINK_X1_TO_Y2 = DefaultLink.builder() |
49 | .providerId(ProviderId.NONE) | 64 | .providerId(ProviderId.NONE) |
50 | .src(CP_X1) | 65 | .src(CP_X1) |
... | @@ -66,6 +81,12 @@ public class UiLinkIdTest extends AbstractUiModelTest { | ... | @@ -66,6 +81,12 @@ public class UiLinkIdTest extends AbstractUiModelTest { |
66 | .type(Link.Type.DIRECT) | 81 | .type(Link.Type.DIRECT) |
67 | .build(); | 82 | .build(); |
68 | 83 | ||
84 | + private static final Link LINK_HA_TO_X1 = DefaultLink.builder() | ||
85 | + .providerId(ProviderId.NONE) | ||
86 | + .src(CP_HA) | ||
87 | + .dst(CP_X1) | ||
88 | + .type(Link.Type.EDGE) | ||
89 | + .build(); | ||
69 | 90 | ||
70 | @Test | 91 | @Test |
71 | public void canonical() { | 92 | public void canonical() { |
... | @@ -86,4 +107,61 @@ public class UiLinkIdTest extends AbstractUiModelTest { | ... | @@ -86,4 +107,61 @@ public class UiLinkIdTest extends AbstractUiModelTest { |
86 | print("link other: %s", other); | 107 | print("link other: %s", other); |
87 | assertNotEquals("equiv?", one, other); | 108 | assertNotEquals("equiv?", one, other); |
88 | } | 109 | } |
110 | + | ||
111 | + @Test | ||
112 | + public void edgeLink() { | ||
113 | + title("edgeLink"); | ||
114 | + UiLinkId id = UiLinkId.uiLinkId(LINK_HA_TO_X1); | ||
115 | + print("link: %s", id); | ||
116 | + assertEquals("wrong port A", P0, id.portA()); | ||
117 | + assertEquals("wrong element A", HOST_A, id.elementA()); | ||
118 | + assertEquals("wrong port B", P1, id.portB()); | ||
119 | + assertEquals("wrong element B", DEV_X, id.elementB()); | ||
120 | + assertNull("region A?", id.regionA()); | ||
121 | + assertNull("region B?", id.regionB()); | ||
122 | + } | ||
123 | + | ||
124 | + @Test | ||
125 | + public void deviceLink() { | ||
126 | + title("deviceLink"); | ||
127 | + UiLinkId id = UiLinkId.uiLinkId(LINK_X1_TO_Y2); | ||
128 | + print("link: %s", id); | ||
129 | + assertEquals("wrong port A", P1, id.portA()); | ||
130 | + assertEquals("wrong element A", DEV_X, id.elementA()); | ||
131 | + assertEquals("wrong port B", P2, id.portB()); | ||
132 | + assertEquals("wrong element B", DEV_Y, id.elementB()); | ||
133 | + assertNull("region A?", id.regionA()); | ||
134 | + assertNull("region B?", id.regionB()); | ||
135 | + } | ||
136 | + | ||
137 | + @Test | ||
138 | + public void regionLink() { | ||
139 | + title("regionLink"); | ||
140 | + UiLinkId idFirst = UiLinkId.uiLinkId(REG_1, REG_2); | ||
141 | + UiLinkId idSecond = UiLinkId.uiLinkId(REG_2, REG_1); | ||
142 | + print(" first: %s", idFirst); | ||
143 | + print("second: %s", idSecond); | ||
144 | + assertEquals("Not same ID", idFirst, idSecond); | ||
145 | + } | ||
146 | + | ||
147 | + @Test(expected = IllegalArgumentException.class) | ||
148 | + public void identicalRegionBad() { | ||
149 | + UiLinkId.uiLinkId(REG_1, REG_1); | ||
150 | + } | ||
151 | + | ||
152 | + @Test(expected = NullPointerException.class) | ||
153 | + public void nullRegionBad() { | ||
154 | + UiLinkId.uiLinkId(REG_1, (RegionId) null); | ||
155 | + } | ||
156 | + | ||
157 | + @Test | ||
158 | + public void regionDeviceLink() { | ||
159 | + title("regionDeviceLink"); | ||
160 | + UiLinkId id = UiLinkId.uiLinkId(REG_1, DEV_X, P1); | ||
161 | + print("id: %s", id); | ||
162 | + assertEquals("region ID", REG_1, id.regionA()); | ||
163 | + assertEquals("device ID", DEV_X, id.elementB()); | ||
164 | + assertEquals("port", P1, id.portB()); | ||
165 | + } | ||
166 | + | ||
89 | } | 167 | } | ... | ... |
1 | +/* | ||
2 | + * Copyright 2016-present 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.ui.model.topo; | ||
18 | + | ||
19 | +import org.junit.Test; | ||
20 | +import org.onosproject.net.DeviceId; | ||
21 | +import org.onosproject.net.region.RegionId; | ||
22 | +import org.onosproject.ui.model.AbstractUiModelTest; | ||
23 | + | ||
24 | +import static org.junit.Assert.assertEquals; | ||
25 | +import static org.onosproject.net.DeviceId.deviceId; | ||
26 | +import static org.onosproject.net.PortNumber.P0; | ||
27 | +import static org.onosproject.net.region.RegionId.regionId; | ||
28 | + | ||
29 | +/** | ||
30 | + * Unit tests for {@link UiRegionDeviceLink}. | ||
31 | + */ | ||
32 | +public class UiRegionDeviceLinkTest extends AbstractUiModelTest { | ||
33 | + | ||
34 | + private static final RegionId R1 = regionId("r1"); | ||
35 | + private static final DeviceId DEV_X = deviceId("device-X"); | ||
36 | + | ||
37 | + @Test | ||
38 | + public void basic() { | ||
39 | + title("basic"); | ||
40 | + UiLinkId id = UiLinkId.uiLinkId(R1, DEV_X, P0); | ||
41 | + UiRegionDeviceLink link = new UiRegionDeviceLink(null, id); | ||
42 | + print(link); | ||
43 | + assertEquals("region", R1, link.region()); | ||
44 | + assertEquals("device", DEV_X, link.device()); | ||
45 | + assertEquals("port", P0, link.port()); | ||
46 | + } | ||
47 | +} |
1 | +/* | ||
2 | + * Copyright 2016-present 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.ui.model.topo; | ||
18 | + | ||
19 | +import org.junit.Test; | ||
20 | +import org.onosproject.net.ConnectPoint; | ||
21 | +import org.onosproject.net.DefaultLink; | ||
22 | +import org.onosproject.net.DeviceId; | ||
23 | +import org.onosproject.net.Link; | ||
24 | +import org.onosproject.net.provider.ProviderId; | ||
25 | +import org.onosproject.net.region.RegionId; | ||
26 | +import org.onosproject.ui.model.AbstractUiModelTest; | ||
27 | + | ||
28 | +import static org.junit.Assert.assertEquals; | ||
29 | +import static org.onosproject.net.DeviceId.deviceId; | ||
30 | +import static org.onosproject.net.PortNumber.P0; | ||
31 | +import static org.onosproject.net.region.RegionId.regionId; | ||
32 | + | ||
33 | +/** | ||
34 | + * Unit tests for {@link UiRegionLink}. | ||
35 | + */ | ||
36 | +public class UiRegionLinkTest extends AbstractUiModelTest { | ||
37 | + | ||
38 | + private static final RegionId R1 = regionId("r1"); | ||
39 | + private static final RegionId R2 = regionId("r2"); | ||
40 | + | ||
41 | + private static final DeviceId DEV_X = deviceId("device-X"); | ||
42 | + private static final DeviceId DEV_Y = deviceId("device-Y"); | ||
43 | + | ||
44 | + private static final ConnectPoint CP_X = new ConnectPoint(DEV_X, P0); | ||
45 | + private static final ConnectPoint CP_Y = new ConnectPoint(DEV_Y, P0); | ||
46 | + | ||
47 | + private static final Link LINK_X_TO_Y = DefaultLink.builder() | ||
48 | + .providerId(ProviderId.NONE) | ||
49 | + .src(CP_X) | ||
50 | + .dst(CP_Y) | ||
51 | + .type(Link.Type.DIRECT) | ||
52 | + .build(); | ||
53 | + | ||
54 | + | ||
55 | + @Test(expected = NullPointerException.class) | ||
56 | + public void nullPointerRegion() { | ||
57 | + title("nullPointerRegion"); | ||
58 | + new UiRegionLink(null, null); | ||
59 | + } | ||
60 | + | ||
61 | + @Test | ||
62 | + public void regionToRegion() { | ||
63 | + title("regionToRegion"); | ||
64 | + UiLinkId id = UiLinkId.uiLinkId(R1, R2); | ||
65 | + UiRegionLink link = new UiRegionLink(null, id); | ||
66 | + print("link: %s", link); | ||
67 | + assertEquals("bad first region", R1, link.regionA()); | ||
68 | + assertEquals("bad second region", R2, link.regionB()); | ||
69 | + } | ||
70 | + | ||
71 | + @Test(expected = IllegalArgumentException.class) | ||
72 | + public void wrongLinkType() { | ||
73 | + title("wrongLinkType"); | ||
74 | + UiLinkId id = UiLinkId.uiLinkId(LINK_X_TO_Y); | ||
75 | + new UiRegionLink(null, id); | ||
76 | + } | ||
77 | +} |
... | @@ -16,20 +16,165 @@ | ... | @@ -16,20 +16,165 @@ |
16 | 16 | ||
17 | package org.onosproject.ui.model.topo; | 17 | package org.onosproject.ui.model.topo; |
18 | 18 | ||
19 | +import org.junit.Before; | ||
19 | import org.junit.Test; | 20 | import org.junit.Test; |
21 | +import org.onosproject.net.ConnectPoint; | ||
22 | +import org.onosproject.net.DefaultLink; | ||
23 | +import org.onosproject.net.DeviceId; | ||
24 | +import org.onosproject.net.Link; | ||
25 | +import org.onosproject.net.PortNumber; | ||
26 | +import org.onosproject.net.provider.ProviderId; | ||
27 | +import org.onosproject.net.region.RegionId; | ||
20 | import org.onosproject.ui.AbstractUiTest; | 28 | import org.onosproject.ui.AbstractUiTest; |
21 | 29 | ||
30 | +import java.util.ArrayList; | ||
31 | +import java.util.Collections; | ||
32 | +import java.util.List; | ||
33 | + | ||
34 | +import static org.junit.Assert.assertEquals; | ||
35 | +import static org.onosproject.net.DeviceId.deviceId; | ||
36 | +import static org.onosproject.net.PortNumber.portNumber; | ||
37 | + | ||
22 | /** | 38 | /** |
23 | * Unit tests for {@link UiTopology}. | 39 | * Unit tests for {@link UiTopology}. |
24 | */ | 40 | */ |
25 | public class UiTopologyTest extends AbstractUiTest { | 41 | public class UiTopologyTest extends AbstractUiTest { |
26 | 42 | ||
43 | + private static final DeviceId DEV_X = deviceId("dev-X"); | ||
44 | + private static final DeviceId DEV_Y = deviceId("dev-Y"); | ||
45 | + private static final PortNumber P1 = portNumber(1); | ||
46 | + private static final PortNumber P2 = portNumber(2); | ||
47 | + | ||
48 | + private static final String DEV_X_ID = "dev-x/1"; | ||
49 | + private static final String DEV_Y_ID = "dev-y/2"; | ||
50 | + | ||
51 | + private static final ConnectPoint CP_X1 = new ConnectPoint(DEV_X, P1); | ||
52 | + private static final ConnectPoint CP_Y2 = new ConnectPoint(DEV_Y, P2); | ||
53 | + | ||
54 | + private static final Link LINK_X1_TO_Y2 = DefaultLink.builder() | ||
55 | + .providerId(ProviderId.NONE) | ||
56 | + .src(CP_X1) | ||
57 | + .dst(CP_Y2) | ||
58 | + .type(Link.Type.DIRECT) | ||
59 | + .build(); | ||
60 | + | ||
61 | + private static final UiLinkId DX1_DY2 = UiLinkId.uiLinkId(LINK_X1_TO_Y2); | ||
62 | + | ||
63 | + private static final RegionId ROOT = UiRegion.NULL_ID; | ||
64 | + private static final RegionId R1 = RegionId.regionId("R1"); | ||
65 | + private static final RegionId R2 = RegionId.regionId("R2"); | ||
66 | + private static final RegionId R3 = RegionId.regionId("R3"); | ||
67 | + | ||
68 | + private static final String DEV_LINK_CLASS = "UiDeviceLink"; | ||
69 | + private static final String REG_LINK_CLASS = "UiRegionLink"; | ||
70 | + private static final String REG_DEV_LINK_CLASS = "UiRegionDeviceLink"; | ||
71 | + | ||
72 | + | ||
27 | private UiTopology topo; | 73 | private UiTopology topo; |
74 | + private UiDeviceLink devLink; | ||
75 | + | ||
76 | + private List<RegionId> xBranch; | ||
77 | + private List<RegionId> yBranch; | ||
78 | + private UiSynthLink synth; | ||
79 | + | ||
80 | + @Before | ||
81 | + public void setUp() { | ||
82 | + topo = new UiTopology(); | ||
83 | + devLink = new UiDeviceLink(null, DX1_DY2); | ||
84 | + devLink.attachBackingLink(LINK_X1_TO_Y2); | ||
85 | + } | ||
28 | 86 | ||
29 | @Test | 87 | @Test |
30 | public void basic() { | 88 | public void basic() { |
31 | title("basic"); | 89 | title("basic"); |
32 | - topo = new UiTopology(); | ||
33 | print(topo); | 90 | print(topo); |
34 | } | 91 | } |
92 | + | ||
93 | + private List<RegionId> branch(RegionId... ids) { | ||
94 | + List<RegionId> result = new ArrayList<>(ids.length); | ||
95 | + Collections.addAll(result, ids); | ||
96 | + return result; | ||
97 | + } | ||
98 | + | ||
99 | + private void verifySynth(RegionId id, String cls, String epA, String epB) { | ||
100 | + synth = topo.makeSynthLink(devLink, xBranch, yBranch); | ||
101 | + UiLink ulink = synth.link(); | ||
102 | + print(synth); | ||
103 | + print("EpA{%s} EpB{%s}", ulink.endPointA(), ulink.endPointB()); | ||
104 | + | ||
105 | + assertEquals("wrong region", id, synth.regionId()); | ||
106 | + assertEquals("wrong link class", cls, ulink.type()); | ||
107 | + assertEquals("wrong EP A", epA, ulink.endPointA()); | ||
108 | + assertEquals("wrong EP B", epB, ulink.endPointB()); | ||
109 | + } | ||
110 | + | ||
111 | + @Test | ||
112 | + public void makeSynthDevToDevRoot() { | ||
113 | + title("makeSynthDevToDevRoot"); | ||
114 | + xBranch = branch(ROOT); | ||
115 | + yBranch = branch(ROOT); | ||
116 | + verifySynth(ROOT, DEV_LINK_CLASS, DEV_X_ID, DEV_Y_ID); | ||
117 | + } | ||
118 | + | ||
119 | + @Test | ||
120 | + public void makeSynthDevToDevR1() { | ||
121 | + title("makeSynthDevToDevR1"); | ||
122 | + xBranch = branch(ROOT, R1); | ||
123 | + yBranch = branch(ROOT, R1); | ||
124 | + verifySynth(R1, DEV_LINK_CLASS, DEV_X_ID, DEV_Y_ID); | ||
125 | + } | ||
126 | + | ||
127 | + @Test | ||
128 | + public void makeSynthDevToDevR2() { | ||
129 | + title("makeSynthDevToDevR2"); | ||
130 | + xBranch = branch(ROOT, R1, R2); | ||
131 | + yBranch = branch(ROOT, R1, R2); | ||
132 | + verifySynth(R2, DEV_LINK_CLASS, DEV_X_ID, DEV_Y_ID); | ||
133 | + } | ||
134 | + | ||
135 | + @Test | ||
136 | + public void makeSynthRegToRegRoot() { | ||
137 | + title("makeSynthRegToRegRoot"); | ||
138 | + xBranch = branch(ROOT, R1); | ||
139 | + yBranch = branch(ROOT, R2); | ||
140 | + verifySynth(ROOT, REG_LINK_CLASS, R1.id(), R2.id()); | ||
141 | + } | ||
142 | + | ||
143 | + @Test | ||
144 | + public void makeSynthRegToRegR1() { | ||
145 | + title("makeSynthRegToRegR1"); | ||
146 | + xBranch = branch(ROOT, R1, R2); | ||
147 | + yBranch = branch(ROOT, R1, R3); | ||
148 | + verifySynth(R1, REG_LINK_CLASS, R2.id(), R3.id()); | ||
149 | + } | ||
150 | + | ||
151 | + @Test | ||
152 | + public void makeSynthRegToDevRoot() { | ||
153 | + title("makeSynthRegToDevRoot"); | ||
154 | + | ||
155 | + // Note: link is canonicalized to region--device order | ||
156 | + | ||
157 | + xBranch = branch(ROOT); | ||
158 | + yBranch = branch(ROOT, R1); | ||
159 | + verifySynth(ROOT, REG_DEV_LINK_CLASS, R1.id(), DEV_X_ID); | ||
160 | + | ||
161 | + xBranch = branch(ROOT, R1); | ||
162 | + yBranch = branch(ROOT); | ||
163 | + verifySynth(ROOT, REG_DEV_LINK_CLASS, R1.id(), DEV_Y_ID); | ||
164 | + } | ||
165 | + | ||
166 | + @Test | ||
167 | + public void makeSynthRegToDevR3() { | ||
168 | + title("makeSynthRegToDevR3"); | ||
169 | + | ||
170 | + // Note: link is canonicalized to region--device order | ||
171 | + | ||
172 | + xBranch = branch(ROOT, R3); | ||
173 | + yBranch = branch(ROOT, R3, R1); | ||
174 | + verifySynth(R3, REG_DEV_LINK_CLASS, R1.id(), DEV_X_ID); | ||
175 | + | ||
176 | + xBranch = branch(ROOT, R3, R1); | ||
177 | + yBranch = branch(ROOT, R3); | ||
178 | + verifySynth(R3, REG_DEV_LINK_CLASS, R1.id(), DEV_Y_ID); | ||
179 | + } | ||
35 | } | 180 | } | ... | ... |
... | @@ -16,6 +16,7 @@ | ... | @@ -16,6 +16,7 @@ |
16 | 16 | ||
17 | package org.onosproject.ui.impl.topo; | 17 | package org.onosproject.ui.impl.topo; |
18 | 18 | ||
19 | +import com.fasterxml.jackson.databind.JsonNode; | ||
19 | import com.fasterxml.jackson.databind.ObjectMapper; | 20 | import com.fasterxml.jackson.databind.ObjectMapper; |
20 | import com.fasterxml.jackson.databind.node.ArrayNode; | 21 | import com.fasterxml.jackson.databind.node.ArrayNode; |
21 | import com.fasterxml.jackson.databind.node.ObjectNode; | 22 | import com.fasterxml.jackson.databind.node.ObjectNode; |
... | @@ -39,6 +40,7 @@ import org.onosproject.ui.model.topo.UiHost; | ... | @@ -39,6 +40,7 @@ import org.onosproject.ui.model.topo.UiHost; |
39 | import org.onosproject.ui.model.topo.UiLink; | 40 | import org.onosproject.ui.model.topo.UiLink; |
40 | import org.onosproject.ui.model.topo.UiNode; | 41 | import org.onosproject.ui.model.topo.UiNode; |
41 | import org.onosproject.ui.model.topo.UiRegion; | 42 | import org.onosproject.ui.model.topo.UiRegion; |
43 | +import org.onosproject.ui.model.topo.UiSynthLink; | ||
42 | import org.onosproject.ui.model.topo.UiTopoLayout; | 44 | import org.onosproject.ui.model.topo.UiTopoLayout; |
43 | import org.slf4j.Logger; | 45 | import org.slf4j.Logger; |
44 | import org.slf4j.LoggerFactory; | 46 | import org.slf4j.LoggerFactory; |
... | @@ -180,9 +182,11 @@ class Topo2Jsonifier { | ... | @@ -180,9 +182,11 @@ class Topo2Jsonifier { |
180 | * | 182 | * |
181 | * @param region the region to transform to JSON | 183 | * @param region the region to transform to JSON |
182 | * @param subRegions the subregions within this region | 184 | * @param subRegions the subregions within this region |
185 | + * @param links the links within this region | ||
183 | * @return a JSON representation of the data | 186 | * @return a JSON representation of the data |
184 | */ | 187 | */ |
185 | - ObjectNode region(UiRegion region, Set<UiRegion> subRegions) { | 188 | + ObjectNode region(UiRegion region, Set<UiRegion> subRegions, |
189 | + List<UiSynthLink> links) { | ||
186 | ObjectNode payload = objectNode(); | 190 | ObjectNode payload = objectNode(); |
187 | if (region == null) { | 191 | if (region == null) { |
188 | payload.put("note", "no-region"); | 192 | payload.put("note", "no-region"); |
... | @@ -193,14 +197,16 @@ class Topo2Jsonifier { | ... | @@ -193,14 +197,16 @@ class Topo2Jsonifier { |
193 | payload.set("subregions", jsonSubRegions(subRegions)); | 197 | payload.set("subregions", jsonSubRegions(subRegions)); |
194 | } | 198 | } |
195 | 199 | ||
200 | + if (links != null) { | ||
201 | + payload.set("links", jsonLinks(links)); | ||
202 | + } | ||
203 | + | ||
196 | List<String> layerTags = region.layerOrder(); | 204 | List<String> layerTags = region.layerOrder(); |
197 | List<Set<UiNode>> splitDevices = splitByLayer(layerTags, region.devices()); | 205 | List<Set<UiNode>> splitDevices = splitByLayer(layerTags, region.devices()); |
198 | List<Set<UiNode>> splitHosts = splitByLayer(layerTags, region.hosts()); | 206 | List<Set<UiNode>> splitHosts = splitByLayer(layerTags, region.hosts()); |
199 | - Set<UiLink> links = region.links(); | ||
200 | 207 | ||
201 | payload.set("devices", jsonGrouped(splitDevices)); | 208 | payload.set("devices", jsonGrouped(splitDevices)); |
202 | payload.set("hosts", jsonGrouped(splitHosts)); | 209 | payload.set("hosts", jsonGrouped(splitHosts)); |
203 | - payload.set("links", jsonLinks(links)); | ||
204 | payload.set("layerOrder", jsonStrings(layerTags)); | 210 | payload.set("layerOrder", jsonStrings(layerTags)); |
205 | 211 | ||
206 | return payload; | 212 | return payload; |
... | @@ -208,24 +214,22 @@ class Topo2Jsonifier { | ... | @@ -208,24 +214,22 @@ class Topo2Jsonifier { |
208 | 214 | ||
209 | private ArrayNode jsonSubRegions(Set<UiRegion> subregions) { | 215 | private ArrayNode jsonSubRegions(Set<UiRegion> subregions) { |
210 | ArrayNode kids = arrayNode(); | 216 | ArrayNode kids = arrayNode(); |
211 | - if (subregions != null) { | 217 | + subregions.forEach(s -> kids.add(jsonClosedRegion(s))); |
212 | - subregions.forEach(s -> kids.add(jsonClosedRegion(s))); | ||
213 | - } | ||
214 | return kids; | 218 | return kids; |
215 | } | 219 | } |
216 | 220 | ||
221 | + private JsonNode jsonLinks(List<UiSynthLink> links) { | ||
222 | + ArrayNode synthLinks = arrayNode(); | ||
223 | + links.forEach(l -> synthLinks.add(json(l))); | ||
224 | + return synthLinks; | ||
225 | + } | ||
226 | + | ||
217 | private ArrayNode jsonStrings(List<String> strings) { | 227 | private ArrayNode jsonStrings(List<String> strings) { |
218 | ArrayNode array = arrayNode(); | 228 | ArrayNode array = arrayNode(); |
219 | strings.forEach(array::add); | 229 | strings.forEach(array::add); |
220 | return array; | 230 | return array; |
221 | } | 231 | } |
222 | 232 | ||
223 | - private ArrayNode jsonLinks(Set<UiLink> links) { | ||
224 | - ArrayNode result = arrayNode(); | ||
225 | - links.forEach(lnk -> result.add(json(lnk))); | ||
226 | - return result; | ||
227 | - } | ||
228 | - | ||
229 | private ArrayNode jsonGrouped(List<Set<UiNode>> groupedNodes) { | 233 | private ArrayNode jsonGrouped(List<Set<UiNode>> groupedNodes) { |
230 | ArrayNode result = arrayNode(); | 234 | ArrayNode result = arrayNode(); |
231 | groupedNodes.forEach(g -> { | 235 | groupedNodes.forEach(g -> { |
... | @@ -280,11 +284,13 @@ class Topo2Jsonifier { | ... | @@ -280,11 +284,13 @@ class Topo2Jsonifier { |
280 | // TODO: complete host details | 284 | // TODO: complete host details |
281 | } | 285 | } |
282 | 286 | ||
283 | - | 287 | + private ObjectNode json(UiSynthLink sLink) { |
284 | - private ObjectNode json(UiLink link) { | 288 | + UiLink uLink = sLink.link(); |
285 | return objectNode() | 289 | return objectNode() |
286 | - .put("id", link.idAsString()); | 290 | + .put("id", uLink.idAsString()) |
287 | - // TODO: complete link details | 291 | + .put("epA", uLink.endPointA()) |
292 | + .put("epB", uLink.endPointB()) | ||
293 | + .put("type", uLink.type()); | ||
288 | } | 294 | } |
289 | 295 | ||
290 | 296 | ||
... | @@ -305,7 +311,7 @@ class Topo2Jsonifier { | ... | @@ -305,7 +311,7 @@ class Topo2Jsonifier { |
305 | */ | 311 | */ |
306 | public ArrayNode closedNodes(Set<UiNode> nodes) { | 312 | public ArrayNode closedNodes(Set<UiNode> nodes) { |
307 | ArrayNode array = arrayNode(); | 313 | ArrayNode array = arrayNode(); |
308 | - for (UiNode node: nodes) { | 314 | + for (UiNode node : nodes) { |
309 | if (node instanceof UiRegion) { | 315 | if (node instanceof UiRegion) { |
310 | array.add(jsonClosedRegion((UiRegion) node)); | 316 | array.add(jsonClosedRegion((UiRegion) node)); |
311 | } else if (node instanceof UiDevice) { | 317 | } else if (node instanceof UiDevice) { |
... | @@ -361,20 +367,6 @@ class Topo2Jsonifier { | ... | @@ -361,20 +367,6 @@ class Topo2Jsonifier { |
361 | return array; | 367 | return array; |
362 | } | 368 | } |
363 | 369 | ||
364 | - /** | ||
365 | - * Returns a JSON array representation of a list of links. | ||
366 | - * | ||
367 | - * @param links the links | ||
368 | - * @return a JSON representation of the links | ||
369 | - */ | ||
370 | - public ArrayNode links(Set<UiLink> links) { | ||
371 | - ArrayNode array = arrayNode(); | ||
372 | - for (UiLink link : links) { | ||
373 | - array.add(json(link)); | ||
374 | - } | ||
375 | - return array; | ||
376 | - } | ||
377 | - | ||
378 | // package-private for unit testing | 370 | // package-private for unit testing |
379 | List<Set<UiNode>> splitByLayer(List<String> layerTags, | 371 | List<Set<UiNode>> splitByLayer(List<String> layerTags, |
380 | Set<? extends UiNode> nodes) { | 372 | Set<? extends UiNode> nodes) { | ... | ... |
... | @@ -26,6 +26,7 @@ import org.onosproject.ui.impl.UiWebSocket; | ... | @@ -26,6 +26,7 @@ import org.onosproject.ui.impl.UiWebSocket; |
26 | import org.onosproject.ui.model.topo.UiClusterMember; | 26 | import org.onosproject.ui.model.topo.UiClusterMember; |
27 | import org.onosproject.ui.model.topo.UiNode; | 27 | import org.onosproject.ui.model.topo.UiNode; |
28 | import org.onosproject.ui.model.topo.UiRegion; | 28 | import org.onosproject.ui.model.topo.UiRegion; |
29 | +import org.onosproject.ui.model.topo.UiSynthLink; | ||
29 | import org.onosproject.ui.model.topo.UiTopoLayout; | 30 | import org.onosproject.ui.model.topo.UiTopoLayout; |
30 | import org.slf4j.Logger; | 31 | import org.slf4j.Logger; |
31 | import org.slf4j.LoggerFactory; | 32 | import org.slf4j.LoggerFactory; |
... | @@ -125,7 +126,8 @@ public class Topo2ViewMessageHandler extends UiMessageHandler { | ... | @@ -125,7 +126,8 @@ public class Topo2ViewMessageHandler extends UiMessageHandler { |
125 | // (as well as layer-order hints) | 126 | // (as well as layer-order hints) |
126 | UiRegion region = topoSession.getRegion(currentLayout); | 127 | UiRegion region = topoSession.getRegion(currentLayout); |
127 | Set<UiRegion> kids = topoSession.getSubRegions(currentLayout); | 128 | Set<UiRegion> kids = topoSession.getSubRegions(currentLayout); |
128 | - sendMessage(CURRENT_REGION, t2json.region(region, kids)); | 129 | + List<UiSynthLink> links = topoSession.getLinks(currentLayout); |
130 | + sendMessage(CURRENT_REGION, t2json.region(region, kids, links)); | ||
129 | 131 | ||
130 | // these are the regions/devices that are siblings to this region | 132 | // these are the regions/devices that are siblings to this region |
131 | Set<UiNode> peers = topoSession.getPeerNodes(currentLayout); | 133 | Set<UiNode> peers = topoSession.getPeerNodes(currentLayout); |
... | @@ -133,6 +135,8 @@ public class Topo2ViewMessageHandler extends UiMessageHandler { | ... | @@ -133,6 +135,8 @@ public class Topo2ViewMessageHandler extends UiMessageHandler { |
133 | peersPayload.set("peers", t2json.closedNodes(peers)); | 135 | peersPayload.set("peers", t2json.closedNodes(peers)); |
134 | sendMessage(PEER_REGIONS, peersPayload); | 136 | sendMessage(PEER_REGIONS, peersPayload); |
135 | 137 | ||
138 | + // TODO: send breadcrumb message | ||
139 | + | ||
136 | // finally, tell the UI that we are done : TODO review / delete?? | 140 | // finally, tell the UI that we are done : TODO review / delete?? |
137 | sendMessage(TOPO_START_DONE, null); | 141 | sendMessage(TOPO_START_DONE, null); |
138 | 142 | ... | ... |
... | @@ -25,6 +25,7 @@ import org.onosproject.ui.impl.topo.model.UiSharedTopologyModel; | ... | @@ -25,6 +25,7 @@ import org.onosproject.ui.impl.topo.model.UiSharedTopologyModel; |
25 | import org.onosproject.ui.model.topo.UiClusterMember; | 25 | import org.onosproject.ui.model.topo.UiClusterMember; |
26 | import org.onosproject.ui.model.topo.UiNode; | 26 | import org.onosproject.ui.model.topo.UiNode; |
27 | import org.onosproject.ui.model.topo.UiRegion; | 27 | import org.onosproject.ui.model.topo.UiRegion; |
28 | +import org.onosproject.ui.model.topo.UiSynthLink; | ||
28 | import org.onosproject.ui.model.topo.UiTopoLayout; | 29 | import org.onosproject.ui.model.topo.UiTopoLayout; |
29 | import org.slf4j.Logger; | 30 | import org.slf4j.Logger; |
30 | import org.slf4j.LoggerFactory; | 31 | import org.slf4j.LoggerFactory; |
... | @@ -214,6 +215,16 @@ public class UiTopoSession implements UiModelListener { | ... | @@ -214,6 +215,16 @@ public class UiTopoSession implements UiModelListener { |
214 | } | 215 | } |
215 | 216 | ||
216 | /** | 217 | /** |
218 | + * Returns the (synthetic) links of the region in the specified layout. | ||
219 | + * | ||
220 | + * @param layout the layout being viewed | ||
221 | + * @return all links that are contained by this layout's region | ||
222 | + */ | ||
223 | + public List<UiSynthLink> getLinks(UiTopoLayout layout) { | ||
224 | + return sharedModel.getSynthLinks(layout.regionId()); | ||
225 | + } | ||
226 | + | ||
227 | + /** | ||
217 | * Refreshes the model's internal state. | 228 | * Refreshes the model's internal state. |
218 | */ | 229 | */ |
219 | public void refreshModel() { | 230 | public void refreshModel() { | ... | ... |
... | @@ -29,6 +29,6 @@ public class ListLinks extends AbstractElementCommand { | ... | @@ -29,6 +29,6 @@ public class ListLinks extends AbstractElementCommand { |
29 | @Override | 29 | @Override |
30 | protected void execute() { | 30 | protected void execute() { |
31 | UiSharedTopologyModel model = get(UiSharedTopologyModel.class); | 31 | UiSharedTopologyModel model = get(UiSharedTopologyModel.class); |
32 | - sorted(model.getLinks()).forEach(l -> print("%s", l)); | 32 | + sorted(model.getDeviceLinks()).forEach(l -> print("%s", l)); |
33 | } | 33 | } |
34 | } | 34 | } | ... | ... |
... | @@ -33,11 +33,13 @@ import org.onosproject.ui.UiTopoLayoutService; | ... | @@ -33,11 +33,13 @@ import org.onosproject.ui.UiTopoLayoutService; |
33 | import org.onosproject.ui.model.ServiceBundle; | 33 | import org.onosproject.ui.model.ServiceBundle; |
34 | import org.onosproject.ui.model.topo.UiClusterMember; | 34 | import org.onosproject.ui.model.topo.UiClusterMember; |
35 | import org.onosproject.ui.model.topo.UiDevice; | 35 | import org.onosproject.ui.model.topo.UiDevice; |
36 | +import org.onosproject.ui.model.topo.UiDeviceLink; | ||
37 | +import org.onosproject.ui.model.topo.UiEdgeLink; | ||
36 | import org.onosproject.ui.model.topo.UiElement; | 38 | import org.onosproject.ui.model.topo.UiElement; |
37 | import org.onosproject.ui.model.topo.UiHost; | 39 | import org.onosproject.ui.model.topo.UiHost; |
38 | -import org.onosproject.ui.model.topo.UiLink; | ||
39 | import org.onosproject.ui.model.topo.UiLinkId; | 40 | import org.onosproject.ui.model.topo.UiLinkId; |
40 | import org.onosproject.ui.model.topo.UiRegion; | 41 | import org.onosproject.ui.model.topo.UiRegion; |
42 | +import org.onosproject.ui.model.topo.UiSynthLink; | ||
41 | import org.onosproject.ui.model.topo.UiTopoLayout; | 43 | import org.onosproject.ui.model.topo.UiTopoLayout; |
42 | import org.onosproject.ui.model.topo.UiTopoLayoutId; | 44 | import org.onosproject.ui.model.topo.UiTopoLayoutId; |
43 | import org.onosproject.ui.model.topo.UiTopology; | 45 | import org.onosproject.ui.model.topo.UiTopology; |
... | @@ -101,7 +103,7 @@ class ModelCache { | ... | @@ -101,7 +103,7 @@ class ModelCache { |
101 | loadClusterMembers(); | 103 | loadClusterMembers(); |
102 | loadRegions(); | 104 | loadRegions(); |
103 | loadDevices(); | 105 | loadDevices(); |
104 | - loadLinks(); | 106 | + loadDeviceLinks(); |
105 | loadHosts(); | 107 | loadHosts(); |
106 | } | 108 | } |
107 | 109 | ||
... | @@ -334,66 +336,72 @@ class ModelCache { | ... | @@ -334,66 +336,72 @@ class ModelCache { |
334 | } | 336 | } |
335 | 337 | ||
336 | 338 | ||
337 | - // === LINKS | 339 | + // === LINKS === |
338 | 340 | ||
339 | - private UiLink addNewLink(UiLinkId id) { | 341 | + private UiDeviceLink addNewDeviceLink(UiLinkId id) { |
340 | - UiLink uiLink = new UiLink(uiTopology, id); | 342 | + UiDeviceLink uiDeviceLink = new UiDeviceLink(uiTopology, id); |
341 | - uiTopology.add(uiLink); | 343 | + uiTopology.add(uiDeviceLink); |
342 | - return uiLink; | 344 | + return uiDeviceLink; |
343 | } | 345 | } |
344 | 346 | ||
345 | - private void updateLink(UiLink uiLink, Link link) { | 347 | + private UiEdgeLink addNewEdgeLink(UiLinkId id) { |
346 | - uiLink.attachBackingLink(link); | 348 | + UiEdgeLink uiEdgeLink = new UiEdgeLink(uiTopology, id); |
349 | + uiTopology.add(uiEdgeLink); | ||
350 | + return uiEdgeLink; | ||
347 | } | 351 | } |
348 | 352 | ||
349 | - private void loadLinks() { | 353 | + private void updateDeviceLink(UiDeviceLink uiDeviceLink, Link link) { |
354 | + uiDeviceLink.attachBackingLink(link); | ||
355 | + } | ||
356 | + | ||
357 | + private void loadDeviceLinks() { | ||
350 | for (Link link : services.link().getLinks()) { | 358 | for (Link link : services.link().getLinks()) { |
351 | UiLinkId id = uiLinkId(link); | 359 | UiLinkId id = uiLinkId(link); |
352 | 360 | ||
353 | - UiLink uiLink = uiTopology.findLink(id); | 361 | + UiDeviceLink uiDeviceLink = uiTopology.findDeviceLink(id); |
354 | - if (uiLink == null) { | 362 | + if (uiDeviceLink == null) { |
355 | - uiLink = addNewLink(id); | 363 | + uiDeviceLink = addNewDeviceLink(id); |
356 | } | 364 | } |
357 | - updateLink(uiLink, link); | 365 | + updateDeviceLink(uiDeviceLink, link); |
358 | } | 366 | } |
359 | } | 367 | } |
360 | 368 | ||
361 | // invoked from UiSharedTopologyModel link listener | 369 | // invoked from UiSharedTopologyModel link listener |
362 | - void addOrUpdateLink(Link link) { | 370 | + void addOrUpdateDeviceLink(Link link) { |
363 | UiLinkId id = uiLinkId(link); | 371 | UiLinkId id = uiLinkId(link); |
364 | - UiLink uiLink = uiTopology.findLink(id); | 372 | + UiDeviceLink uiDeviceLink = uiTopology.findDeviceLink(id); |
365 | - if (uiLink == null) { | 373 | + if (uiDeviceLink == null) { |
366 | - uiLink = addNewLink(id); | 374 | + uiDeviceLink = addNewDeviceLink(id); |
367 | } | 375 | } |
368 | - updateLink(uiLink, link); | 376 | + updateDeviceLink(uiDeviceLink, link); |
369 | 377 | ||
370 | - postEvent(LINK_ADDED_OR_UPDATED, uiLink); | 378 | + postEvent(LINK_ADDED_OR_UPDATED, uiDeviceLink); |
371 | } | 379 | } |
372 | 380 | ||
373 | // package private for unit test access | 381 | // package private for unit test access |
374 | - UiLink accessLink(UiLinkId id) { | 382 | + UiDeviceLink accessDeviceLink(UiLinkId id) { |
375 | - return uiTopology.findLink(id); | 383 | + return uiTopology.findDeviceLink(id); |
376 | } | 384 | } |
377 | 385 | ||
378 | // invoked from UiSharedTopologyModel link listener | 386 | // invoked from UiSharedTopologyModel link listener |
379 | - void removeLink(Link link) { | 387 | + void removeDeviceLink(Link link) { |
380 | UiLinkId id = uiLinkId(link); | 388 | UiLinkId id = uiLinkId(link); |
381 | - UiLink uiLink = uiTopology.findLink(id); | 389 | + UiDeviceLink uiDeviceLink = uiTopology.findDeviceLink(id); |
382 | - if (uiLink != null) { | 390 | + if (uiDeviceLink != null) { |
383 | - boolean remaining = uiLink.detachBackingLink(link); | 391 | + boolean remaining = uiDeviceLink.detachBackingLink(link); |
384 | if (remaining) { | 392 | if (remaining) { |
385 | - postEvent(LINK_ADDED_OR_UPDATED, uiLink); | 393 | + postEvent(LINK_ADDED_OR_UPDATED, uiDeviceLink); |
386 | } else { | 394 | } else { |
387 | - uiTopology.remove(uiLink); | 395 | + uiTopology.remove(uiDeviceLink); |
388 | - postEvent(LINK_REMOVED, uiLink); | 396 | + postEvent(LINK_REMOVED, uiDeviceLink); |
389 | } | 397 | } |
390 | } else { | 398 | } else { |
391 | - log.warn(E_NO_ELEMENT, "link", id); | 399 | + log.warn(E_NO_ELEMENT, "Device link", id); |
392 | } | 400 | } |
393 | } | 401 | } |
394 | 402 | ||
395 | - Set<UiLink> getAllLinks() { | 403 | + Set<UiDeviceLink> getAllDeviceLinks() { |
396 | - return uiTopology.allLinks(); | 404 | + return uiTopology.allDeviceLinks(); |
397 | } | 405 | } |
398 | 406 | ||
399 | // === HOSTS | 407 | // === HOSTS |
... | @@ -411,20 +419,19 @@ class ModelCache { | ... | @@ -411,20 +419,19 @@ class ModelCache { |
411 | host.setEdgeLinkId(elinkId); | 419 | host.setEdgeLinkId(elinkId); |
412 | 420 | ||
413 | // add synthesized edge link to the topology | 421 | // add synthesized edge link to the topology |
414 | - UiLink edgeLink = addNewLink(elinkId); | 422 | + UiEdgeLink edgeLink = addNewEdgeLink(elinkId); |
415 | edgeLink.attachEdgeLink(elink); | 423 | edgeLink.attachEdgeLink(elink); |
416 | 424 | ||
417 | return host; | 425 | return host; |
418 | } | 426 | } |
419 | 427 | ||
420 | - private void insertNewUiLink(UiLinkId id, EdgeLink e) { | 428 | + private void insertNewUiEdgeLink(UiLinkId id, EdgeLink e) { |
421 | - UiLink newEdgeLink = addNewLink(id); | 429 | + UiEdgeLink newEdgeLink = addNewEdgeLink(id); |
422 | newEdgeLink.attachEdgeLink(e); | 430 | newEdgeLink.attachEdgeLink(e); |
423 | - | ||
424 | } | 431 | } |
425 | 432 | ||
426 | private void updateHost(UiHost uiHost, Host h) { | 433 | private void updateHost(UiHost uiHost, Host h) { |
427 | - UiLink existing = uiTopology.findLink(uiHost.edgeLinkId()); | 434 | + UiEdgeLink existing = uiTopology.findEdgeLink(uiHost.edgeLinkId()); |
428 | 435 | ||
429 | EdgeLink currentElink = synthesizeLink(h); | 436 | EdgeLink currentElink = synthesizeLink(h); |
430 | UiLinkId currentElinkId = uiLinkId(currentElink); | 437 | UiLinkId currentElinkId = uiLinkId(currentElink); |
... | @@ -432,7 +439,7 @@ class ModelCache { | ... | @@ -432,7 +439,7 @@ class ModelCache { |
432 | if (existing != null) { | 439 | if (existing != null) { |
433 | if (!currentElinkId.equals(existing.id())) { | 440 | if (!currentElinkId.equals(existing.id())) { |
434 | // edge link has changed | 441 | // edge link has changed |
435 | - insertNewUiLink(currentElinkId, currentElink); | 442 | + insertNewUiEdgeLink(currentElinkId, currentElink); |
436 | uiHost.setEdgeLinkId(currentElinkId); | 443 | uiHost.setEdgeLinkId(currentElinkId); |
437 | 444 | ||
438 | uiTopology.remove(existing); | 445 | uiTopology.remove(existing); |
... | @@ -440,7 +447,7 @@ class ModelCache { | ... | @@ -440,7 +447,7 @@ class ModelCache { |
440 | 447 | ||
441 | } else { | 448 | } else { |
442 | // no previously existing edge link | 449 | // no previously existing edge link |
443 | - insertNewUiLink(currentElinkId, currentElink); | 450 | + insertNewUiEdgeLink(currentElinkId, currentElink); |
444 | uiHost.setEdgeLinkId(currentElinkId); | 451 | uiHost.setEdgeLinkId(currentElinkId); |
445 | 452 | ||
446 | } | 453 | } |
... | @@ -489,7 +496,7 @@ class ModelCache { | ... | @@ -489,7 +496,7 @@ class ModelCache { |
489 | HostId id = host.id(); | 496 | HostId id = host.id(); |
490 | UiHost uiHost = uiTopology.findHost(id); | 497 | UiHost uiHost = uiTopology.findHost(id); |
491 | if (uiHost != null) { | 498 | if (uiHost != null) { |
492 | - UiLink edgeLink = uiTopology.findLink(uiHost.edgeLinkId()); | 499 | + UiEdgeLink edgeLink = uiTopology.findEdgeLink(uiHost.edgeLinkId()); |
493 | uiTopology.remove(edgeLink); | 500 | uiTopology.remove(edgeLink); |
494 | uiTopology.remove(uiHost); | 501 | uiTopology.remove(uiHost); |
495 | postEvent(HOST_REMOVED, uiHost); | 502 | postEvent(HOST_REMOVED, uiHost); |
... | @@ -503,11 +510,17 @@ class ModelCache { | ... | @@ -503,11 +510,17 @@ class ModelCache { |
503 | } | 510 | } |
504 | 511 | ||
505 | 512 | ||
513 | + // === SYNTHETIC LINKS | ||
514 | + | ||
515 | + List<UiSynthLink> getSynthLinks(RegionId regionId) { | ||
516 | + return uiTopology.findSynthLinks(regionId); | ||
517 | + } | ||
518 | + | ||
506 | /** | 519 | /** |
507 | * Refreshes the internal state. | 520 | * Refreshes the internal state. |
508 | */ | 521 | */ |
509 | public void refresh() { | 522 | public void refresh() { |
510 | - // fix up internal linkages if they aren't correct | 523 | + // fix up internal linkages to ensure they are correct |
511 | 524 | ||
512 | // make sure regions reflect layout containment hierarchy | 525 | // make sure regions reflect layout containment hierarchy |
513 | fixupContainmentHierarchy(uiTopology.nullRegion()); | 526 | fixupContainmentHierarchy(uiTopology.nullRegion()); |
... | @@ -542,8 +555,13 @@ class ModelCache { | ... | @@ -542,8 +555,13 @@ class ModelCache { |
542 | Set<DeviceId> leftOver = new HashSet<>(allDevices.size()); | 555 | Set<DeviceId> leftOver = new HashSet<>(allDevices.size()); |
543 | allDevices.forEach(d -> leftOver.add(d.id())); | 556 | allDevices.forEach(d -> leftOver.add(d.id())); |
544 | uiTopology.nullRegion().reconcileDevices(leftOver); | 557 | uiTopology.nullRegion().reconcileDevices(leftOver); |
558 | + | ||
559 | + // now that we have correct region hierarchy, and devices are in their | ||
560 | + // respective regions, we can compute synthetic links for each region. | ||
561 | + uiTopology.computeSynthLinks(); | ||
545 | } | 562 | } |
546 | 563 | ||
564 | + | ||
547 | // === CACHE STATISTICS | 565 | // === CACHE STATISTICS |
548 | 566 | ||
549 | /** | 567 | /** |
... | @@ -583,12 +601,21 @@ class ModelCache { | ... | @@ -583,12 +601,21 @@ class ModelCache { |
583 | } | 601 | } |
584 | 602 | ||
585 | /** | 603 | /** |
586 | - * Returns the number of links in the topology. | 604 | + * Returns the number of device links in the topology. |
587 | * | 605 | * |
588 | - * @return number of links | 606 | + * @return number of device links |
589 | */ | 607 | */ |
590 | - public int linkCount() { | 608 | + public int deviceLinkCount() { |
591 | - return uiTopology.linkCount(); | 609 | + return uiTopology.deviceLinkCount(); |
610 | + } | ||
611 | + | ||
612 | + /** | ||
613 | + * Returns the number of edge links in the topology. | ||
614 | + * | ||
615 | + * @return number of edge links | ||
616 | + */ | ||
617 | + public int edgeLinkCount() { | ||
618 | + return uiTopology.edgeLinkCount(); | ||
592 | } | 619 | } |
593 | 620 | ||
594 | /** | 621 | /** |
... | @@ -600,4 +627,12 @@ class ModelCache { | ... | @@ -600,4 +627,12 @@ class ModelCache { |
600 | return uiTopology.hostCount(); | 627 | return uiTopology.hostCount(); |
601 | } | 628 | } |
602 | 629 | ||
630 | + /** | ||
631 | + * Returns the number of synthetic links in the topology. | ||
632 | + * | ||
633 | + * @return the number of synthetic links | ||
634 | + */ | ||
635 | + public int synthLinkCount() { | ||
636 | + return uiTopology.synthLinkCount(); | ||
637 | + } | ||
603 | } | 638 | } | ... | ... |
... | @@ -65,9 +65,10 @@ import org.onosproject.ui.impl.topo.UiTopoSession; | ... | @@ -65,9 +65,10 @@ import org.onosproject.ui.impl.topo.UiTopoSession; |
65 | import org.onosproject.ui.model.ServiceBundle; | 65 | import org.onosproject.ui.model.ServiceBundle; |
66 | import org.onosproject.ui.model.topo.UiClusterMember; | 66 | import org.onosproject.ui.model.topo.UiClusterMember; |
67 | import org.onosproject.ui.model.topo.UiDevice; | 67 | import org.onosproject.ui.model.topo.UiDevice; |
68 | +import org.onosproject.ui.model.topo.UiDeviceLink; | ||
68 | import org.onosproject.ui.model.topo.UiHost; | 69 | import org.onosproject.ui.model.topo.UiHost; |
69 | -import org.onosproject.ui.model.topo.UiLink; | ||
70 | import org.onosproject.ui.model.topo.UiRegion; | 70 | import org.onosproject.ui.model.topo.UiRegion; |
71 | +import org.onosproject.ui.model.topo.UiSynthLink; | ||
71 | import org.slf4j.Logger; | 72 | import org.slf4j.Logger; |
72 | import org.slf4j.LoggerFactory; | 73 | import org.slf4j.LoggerFactory; |
73 | 74 | ||
... | @@ -269,12 +270,22 @@ public final class UiSharedTopologyModel | ... | @@ -269,12 +270,22 @@ public final class UiSharedTopologyModel |
269 | } | 270 | } |
270 | 271 | ||
271 | /** | 272 | /** |
272 | - * Returns the set of links stored in the model cache. | 273 | + * Returns the set of device links stored in the model cache. |
273 | * | 274 | * |
274 | - * @return set of links | 275 | + * @return set of device links |
275 | */ | 276 | */ |
276 | - public Set<UiLink> getLinks() { | 277 | + public Set<UiDeviceLink> getDeviceLinks() { |
277 | - return cache.getAllLinks(); | 278 | + return cache.getAllDeviceLinks(); |
279 | + } | ||
280 | + | ||
281 | + /** | ||
282 | + * Returns the synthetic links associated with the specified region. | ||
283 | + * | ||
284 | + * @param regionId region ID | ||
285 | + * @return synthetic links for that region | ||
286 | + */ | ||
287 | + public List<UiSynthLink> getSynthLinks(RegionId regionId) { | ||
288 | + return cache.getSynthLinks(regionId); | ||
278 | } | 289 | } |
279 | 290 | ||
280 | // ===================================================================== | 291 | // ===================================================================== |
... | @@ -434,11 +445,11 @@ public final class UiSharedTopologyModel | ... | @@ -434,11 +445,11 @@ public final class UiSharedTopologyModel |
434 | 445 | ||
435 | case LINK_ADDED: | 446 | case LINK_ADDED: |
436 | case LINK_UPDATED: | 447 | case LINK_UPDATED: |
437 | - cache.addOrUpdateLink(link); | 448 | + cache.addOrUpdateDeviceLink(link); |
438 | break; | 449 | break; |
439 | 450 | ||
440 | case LINK_REMOVED: | 451 | case LINK_REMOVED: |
441 | - cache.removeLink(link); | 452 | + cache.removeDeviceLink(link); |
442 | break; | 453 | break; |
443 | 454 | ||
444 | default: | 455 | default: | ... | ... |
... | @@ -29,9 +29,9 @@ import org.onosproject.net.region.Region; | ... | @@ -29,9 +29,9 @@ import org.onosproject.net.region.Region; |
29 | import org.onosproject.ui.impl.topo.model.UiModelEvent.Type; | 29 | import org.onosproject.ui.impl.topo.model.UiModelEvent.Type; |
30 | import org.onosproject.ui.model.topo.UiClusterMember; | 30 | import org.onosproject.ui.model.topo.UiClusterMember; |
31 | import org.onosproject.ui.model.topo.UiDevice; | 31 | import org.onosproject.ui.model.topo.UiDevice; |
32 | +import org.onosproject.ui.model.topo.UiDeviceLink; | ||
32 | import org.onosproject.ui.model.topo.UiElement; | 33 | import org.onosproject.ui.model.topo.UiElement; |
33 | import org.onosproject.ui.model.topo.UiHost; | 34 | import org.onosproject.ui.model.topo.UiHost; |
34 | -import org.onosproject.ui.model.topo.UiLink; | ||
35 | import org.onosproject.ui.model.topo.UiLinkId; | 35 | import org.onosproject.ui.model.topo.UiLinkId; |
36 | import org.onosproject.ui.model.topo.UiRegion; | 36 | import org.onosproject.ui.model.topo.UiRegion; |
37 | 37 | ||
... | @@ -265,54 +265,54 @@ public class ModelCacheTest extends AbstractTopoModelTest { | ... | @@ -265,54 +265,54 @@ public class ModelCacheTest extends AbstractTopoModelTest { |
265 | // we've established that the ID is the same for both | 265 | // we've established that the ID is the same for both |
266 | UiLinkId linkId = idA2B; | 266 | UiLinkId linkId = idA2B; |
267 | 267 | ||
268 | - cache.addOrUpdateLink(link1); | 268 | + cache.addOrUpdateDeviceLink(link1); |
269 | dispatcher.assertLast(Type.LINK_ADDED_OR_UPDATED, linkId.toString()); | 269 | dispatcher.assertLast(Type.LINK_ADDED_OR_UPDATED, linkId.toString()); |
270 | dispatcher.assertEventCount(1); | 270 | dispatcher.assertEventCount(1); |
271 | - assertEquals("unex # links", 1, cache.linkCount()); | 271 | + assertEquals("unex # links", 1, cache.deviceLinkCount()); |
272 | 272 | ||
273 | - UiLink link = cache.accessLink(linkId); | 273 | + UiDeviceLink link = cache.accessDeviceLink(linkId); |
274 | assertEquals("dev A not d2", DEVID_2, link.deviceA()); | 274 | assertEquals("dev A not d2", DEVID_2, link.deviceA()); |
275 | assertEquals("dev B not d7", DEVID_7, link.deviceB()); | 275 | assertEquals("dev B not d7", DEVID_7, link.deviceB()); |
276 | assertEquals("wrong backing link A-B", link1, link.linkAtoB()); | 276 | assertEquals("wrong backing link A-B", link1, link.linkAtoB()); |
277 | assertEquals("backing link B-A?", null, link.linkBtoA()); | 277 | assertEquals("backing link B-A?", null, link.linkBtoA()); |
278 | 278 | ||
279 | - cache.addOrUpdateLink(link2); | 279 | + cache.addOrUpdateDeviceLink(link2); |
280 | dispatcher.assertLast(Type.LINK_ADDED_OR_UPDATED, linkId.toString()); | 280 | dispatcher.assertLast(Type.LINK_ADDED_OR_UPDATED, linkId.toString()); |
281 | dispatcher.assertEventCount(2); | 281 | dispatcher.assertEventCount(2); |
282 | // NOTE: yes! expect 1 UiLink | 282 | // NOTE: yes! expect 1 UiLink |
283 | - assertEquals("unex # links", 1, cache.linkCount()); | 283 | + assertEquals("unex # links", 1, cache.deviceLinkCount()); |
284 | 284 | ||
285 | - link = cache.accessLink(linkId); | 285 | + link = cache.accessDeviceLink(linkId); |
286 | assertEquals("dev A not d2", DEVID_2, link.deviceA()); | 286 | assertEquals("dev A not d2", DEVID_2, link.deviceA()); |
287 | assertEquals("dev B not d7", DEVID_7, link.deviceB()); | 287 | assertEquals("dev B not d7", DEVID_7, link.deviceB()); |
288 | assertEquals("wrong backing link A-B", link1, link.linkAtoB()); | 288 | assertEquals("wrong backing link A-B", link1, link.linkAtoB()); |
289 | assertEquals("wrong backing link B-A", link2, link.linkBtoA()); | 289 | assertEquals("wrong backing link B-A", link2, link.linkBtoA()); |
290 | 290 | ||
291 | // now remove links one at a time | 291 | // now remove links one at a time |
292 | - cache.removeLink(link1); | 292 | + cache.removeDeviceLink(link1); |
293 | // NOTE: yes! ADD_OR_UPDATE, since the link was updated | 293 | // NOTE: yes! ADD_OR_UPDATE, since the link was updated |
294 | dispatcher.assertLast(Type.LINK_ADDED_OR_UPDATED, linkId.toString()); | 294 | dispatcher.assertLast(Type.LINK_ADDED_OR_UPDATED, linkId.toString()); |
295 | dispatcher.assertEventCount(3); | 295 | dispatcher.assertEventCount(3); |
296 | // NOTE: yes! expect 1 UiLink (still) | 296 | // NOTE: yes! expect 1 UiLink (still) |
297 | - assertEquals("unex # links", 1, cache.linkCount()); | 297 | + assertEquals("unex # links", 1, cache.deviceLinkCount()); |
298 | 298 | ||
299 | - link = cache.accessLink(linkId); | 299 | + link = cache.accessDeviceLink(linkId); |
300 | assertEquals("dev A not d2", DEVID_2, link.deviceA()); | 300 | assertEquals("dev A not d2", DEVID_2, link.deviceA()); |
301 | assertEquals("dev B not d7", DEVID_7, link.deviceB()); | 301 | assertEquals("dev B not d7", DEVID_7, link.deviceB()); |
302 | assertEquals("backing link A-B?", null, link.linkAtoB()); | 302 | assertEquals("backing link A-B?", null, link.linkAtoB()); |
303 | assertEquals("wrong backing link B-A", link2, link.linkBtoA()); | 303 | assertEquals("wrong backing link B-A", link2, link.linkBtoA()); |
304 | 304 | ||
305 | // remove final link | 305 | // remove final link |
306 | - cache.removeLink(link2); | 306 | + cache.removeDeviceLink(link2); |
307 | dispatcher.assertLast(Type.LINK_REMOVED, linkId.toString()); | 307 | dispatcher.assertLast(Type.LINK_REMOVED, linkId.toString()); |
308 | dispatcher.assertEventCount(4); | 308 | dispatcher.assertEventCount(4); |
309 | // NOTE: finally link should be removed from cache | 309 | // NOTE: finally link should be removed from cache |
310 | - assertEquals("unex # links", 0, cache.linkCount()); | 310 | + assertEquals("unex # links", 0, cache.deviceLinkCount()); |
311 | } | 311 | } |
312 | 312 | ||
313 | private void assertHostLinkCounts(int nHosts, int nLinks) { | 313 | private void assertHostLinkCounts(int nHosts, int nLinks) { |
314 | assertEquals("unex # hosts", nHosts, cache.hostCount()); | 314 | assertEquals("unex # hosts", nHosts, cache.hostCount()); |
315 | - assertEquals("unex # links", nLinks, cache.linkCount()); | 315 | + assertEquals("unex # links", nLinks, cache.edgeLinkCount()); |
316 | } | 316 | } |
317 | 317 | ||
318 | private void assertLocation(HostId hid, DeviceId expDev, int expPort) { | 318 | private void assertLocation(HostId hid, DeviceId expDev, int expPort) { |
... | @@ -403,6 +403,8 @@ public class ModelCacheTest extends AbstractTopoModelTest { | ... | @@ -403,6 +403,8 @@ public class ModelCacheTest extends AbstractTopoModelTest { |
403 | assertEquals("unex # regions", 3, cache.regionCount()); | 403 | assertEquals("unex # regions", 3, cache.regionCount()); |
404 | assertEquals("unex # devices", 9, cache.deviceCount()); | 404 | assertEquals("unex # devices", 9, cache.deviceCount()); |
405 | assertEquals("unex # hosts", 18, cache.hostCount()); | 405 | assertEquals("unex # hosts", 18, cache.hostCount()); |
406 | - assertEquals("unex # hosts", 26, cache.linkCount()); | 406 | + assertEquals("unex # device-links", 8, cache.deviceLinkCount()); |
407 | + assertEquals("unex # edge-links", 18, cache.edgeLinkCount()); | ||
408 | + assertEquals("unex # synth-links", 0, cache.synthLinkCount()); | ||
407 | } | 409 | } |
408 | } | 410 | } | ... | ... |
-
Please register or login to post a comment