blob: 3fd7e085bf665748a3a901e9f39401bf2ebee608 [file] [log] [blame]
Carmelo Casconecb4327a2018-09-11 15:17:23 -07001/*
2 * Copyright 2017-present Open Networking Foundation
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
17package org.onosproject.net.pi.runtime;
18
19import com.google.common.annotations.Beta;
20import com.google.common.base.MoreObjects;
21import com.google.common.base.Objects;
Carmelo Cascone99c59db2019-01-17 15:39:35 -080022import com.google.common.collect.ImmutableMap;
Carmelo Casconecb4327a2018-09-11 15:17:23 -070023import com.google.common.collect.Maps;
Carmelo Cascone4c289b72019-01-22 15:30:45 -080024import org.onosproject.net.DeviceId;
Carmelo Casconecb4327a2018-09-11 15:17:23 -070025import org.onosproject.net.pi.model.PiActionProfileId;
26
27import java.util.Collection;
28import java.util.Map;
Carmelo Cascone99c59db2019-01-17 15:39:35 -080029import java.util.Optional;
Carmelo Casconecb4327a2018-09-11 15:17:23 -070030
Carmelo Cascone99c59db2019-01-17 15:39:35 -080031import static com.google.common.base.Preconditions.checkArgument;
Carmelo Casconecb4327a2018-09-11 15:17:23 -070032import static com.google.common.base.Preconditions.checkNotNull;
33
34/**
35 * Instance of an action profile group of a protocol-independent pipeline.
36 */
37@Beta
38public final class PiActionProfileGroup implements PiEntity {
39
Carmelo Casconecb4327a2018-09-11 15:17:23 -070040 private final PiActionProfileId actionProfileId;
Carmelo Cascone99c59db2019-01-17 15:39:35 -080041 private final PiActionProfileGroupId groupId;
42 private final ImmutableMap<PiActionProfileMemberId, WeightedMember> members;
43 private final int maxSize;
Carmelo Casconecb4327a2018-09-11 15:17:23 -070044
Carmelo Cascone99c59db2019-01-17 15:39:35 -080045 private PiActionProfileGroup(PiActionProfileGroupId groupId,
46 ImmutableMap<PiActionProfileMemberId, WeightedMember> members,
47 PiActionProfileId actionProfileId,
48 int maxSize) {
49 this.groupId = groupId;
Carmelo Casconecb4327a2018-09-11 15:17:23 -070050 this.members = members;
51 this.actionProfileId = actionProfileId;
Carmelo Cascone99c59db2019-01-17 15:39:35 -080052 this.maxSize = maxSize;
Carmelo Casconecb4327a2018-09-11 15:17:23 -070053 }
54
55 /**
Carmelo Cascone99c59db2019-01-17 15:39:35 -080056 * Returns the ID of this action profile group.
Carmelo Casconecb4327a2018-09-11 15:17:23 -070057 *
Carmelo Cascone99c59db2019-01-17 15:39:35 -080058 * @return action profile group ID
Carmelo Casconecb4327a2018-09-11 15:17:23 -070059 */
60 public PiActionProfileGroupId id() {
Carmelo Cascone99c59db2019-01-17 15:39:35 -080061 return groupId;
Carmelo Casconecb4327a2018-09-11 15:17:23 -070062 }
63
64 /**
Carmelo Cascone99c59db2019-01-17 15:39:35 -080065 * Returns the list of member references of this action profile group.
Carmelo Casconecb4327a2018-09-11 15:17:23 -070066 *
67 * @return collection of action profile members.
68 */
Carmelo Cascone99c59db2019-01-17 15:39:35 -080069 public Collection<WeightedMember> members() {
70 return members.values();
Carmelo Casconecb4327a2018-09-11 15:17:23 -070071 }
72
73 /**
Carmelo Cascone99c59db2019-01-17 15:39:35 -080074 * Returns the group member identified by the given action profile member
75 * ID, if present.
Carmelo Casconecb4327a2018-09-11 15:17:23 -070076 *
Carmelo Cascone99c59db2019-01-17 15:39:35 -080077 * @param memberId action profile member ID
78 * @return optional group member
Carmelo Casconecb4327a2018-09-11 15:17:23 -070079 */
Carmelo Cascone99c59db2019-01-17 15:39:35 -080080 public Optional<WeightedMember> member(PiActionProfileMemberId memberId) {
81 return Optional.of(members.get(memberId));
82 }
83
84 /**
85 * Returns the maximum number of members that this group can hold. 0
86 * signifies that a limit is not set.
87 *
88 * @return maximum number of members that this group can hold
89 */
90 public int maxSize() {
91 return maxSize;
92 }
93
94 /**
95 * Returns the ID of the action profile where this group belong.
96 *
97 * @return action profile ID
98 */
99 public PiActionProfileId actionProfile() {
Carmelo Casconecb4327a2018-09-11 15:17:23 -0700100 return actionProfileId;
101 }
102
103 @Override
Carmelo Cascone99c59db2019-01-17 15:39:35 -0800104 public boolean equals(Object obj) {
105 if (this == obj) {
Carmelo Casconecb4327a2018-09-11 15:17:23 -0700106 return true;
107 }
Carmelo Cascone99c59db2019-01-17 15:39:35 -0800108 if (obj == null || getClass() != obj.getClass()) {
Carmelo Casconecb4327a2018-09-11 15:17:23 -0700109 return false;
110 }
Carmelo Cascone99c59db2019-01-17 15:39:35 -0800111 final PiActionProfileGroup other = (PiActionProfileGroup) obj;
112 return Objects.equal(this.groupId, other.groupId)
113 && Objects.equal(this.members, other.members)
114 && Objects.equal(this.maxSize, other.maxSize)
115 && Objects.equal(this.actionProfileId, other.actionProfileId);
Carmelo Casconecb4327a2018-09-11 15:17:23 -0700116 }
117
118 @Override
119 public int hashCode() {
Carmelo Cascone99c59db2019-01-17 15:39:35 -0800120 return Objects.hashCode(groupId, members, maxSize, actionProfileId);
Carmelo Casconecb4327a2018-09-11 15:17:23 -0700121 }
122
123 @Override
124 public String toString() {
125 return MoreObjects.toStringHelper(this)
Carmelo Cascone99c59db2019-01-17 15:39:35 -0800126 .add("actionProfile", actionProfileId)
127 .add("id", groupId)
Carmelo Cascone61469462019-03-05 23:59:11 -0800128 .add("members", members.values())
Carmelo Cascone99c59db2019-01-17 15:39:35 -0800129 .add("maxSize", maxSize)
Carmelo Casconecb4327a2018-09-11 15:17:23 -0700130 .toString();
131 }
132
133 /**
134 * Returns a new builder of action profile groups.
135 *
136 * @return action profile group builder
137 */
138 public static Builder builder() {
139 return new Builder();
140 }
141
142 @Override
143 public PiEntityType piEntityType() {
144 return PiEntityType.ACTION_PROFILE_GROUP;
145 }
146
Carmelo Cascone4c289b72019-01-22 15:30:45 -0800147 @Override
148 public PiActionProfileGroupHandle handle(DeviceId deviceId) {
149 return PiActionProfileGroupHandle.of(deviceId, this);
150 }
151
Carmelo Casconecb4327a2018-09-11 15:17:23 -0700152 /**
153 * Builder of action profile groups.
154 */
155 public static final class Builder {
156
Carmelo Cascone99c59db2019-01-17 15:39:35 -0800157 private PiActionProfileGroupId groupId;
158 private Map<PiActionProfileMemberId, WeightedMember> members = Maps.newHashMap();
159 private PiActionProfileId actionProfileId;
160 private int maxSize;
Carmelo Casconecb4327a2018-09-11 15:17:23 -0700161
162 private Builder() {
163 // hides constructor.
164 }
165
166 /**
Carmelo Cascone99c59db2019-01-17 15:39:35 -0800167 * Sets the ID of this action profile group.
Carmelo Casconecb4327a2018-09-11 15:17:23 -0700168 *
Carmelo Cascone99c59db2019-01-17 15:39:35 -0800169 * @param id action profile group ID
Carmelo Casconecb4327a2018-09-11 15:17:23 -0700170 * @return this
171 */
172 public Builder withId(PiActionProfileGroupId id) {
Carmelo Cascone99c59db2019-01-17 15:39:35 -0800173 this.groupId = id;
Carmelo Casconecb4327a2018-09-11 15:17:23 -0700174 return this;
175 }
176
177 /**
Carmelo Cascone99c59db2019-01-17 15:39:35 -0800178 * Adds one member to this action profile.
Carmelo Casconecb4327a2018-09-11 15:17:23 -0700179 *
Carmelo Cascone99c59db2019-01-17 15:39:35 -0800180 * @param member member to add
Carmelo Casconecb4327a2018-09-11 15:17:23 -0700181 * @return this
182 */
Carmelo Cascone99c59db2019-01-17 15:39:35 -0800183 public Builder addMember(WeightedMember member) {
184 checkNotNull(member);
Carmelo Casconecb4327a2018-09-11 15:17:23 -0700185 members.put(member.id(), member);
186 return this;
187 }
188
189 /**
Carmelo Cascone99c59db2019-01-17 15:39:35 -0800190 * Adds one member to this action profile group with default weight.
Carmelo Casconecb4327a2018-09-11 15:17:23 -0700191 *
Carmelo Cascone99c59db2019-01-17 15:39:35 -0800192 * @param memberId ID of the action profile member to add
Carmelo Casconecb4327a2018-09-11 15:17:23 -0700193 * @return this
194 */
Carmelo Cascone99c59db2019-01-17 15:39:35 -0800195 public Builder addMember(PiActionProfileMemberId memberId) {
196 addMember(new WeightedMember(memberId, WeightedMember.DEFAULT_WEIGHT));
Carmelo Casconecb4327a2018-09-11 15:17:23 -0700197 return this;
198 }
199
200 /**
Carmelo Cascone99c59db2019-01-17 15:39:35 -0800201 * Adds one member to this action profile group with default weight.
Carmelo Casconecb4327a2018-09-11 15:17:23 -0700202 *
Carmelo Cascone99c59db2019-01-17 15:39:35 -0800203 * @param memberInstance the action profile member instance to add
204 * @return this
205 */
206 public Builder addMember(PiActionProfileMember memberInstance) {
207 addMember(new WeightedMember(memberInstance, WeightedMember.DEFAULT_WEIGHT));
208 return this;
209 }
210
211 /**
212 * Adds all members to this action profile group with default weight.
213 *
214 * @param memberInstances the action profile member instance to add
215 * @return this
216 */
217 public Builder addMembers(Iterable<PiActionProfileMember> memberInstances) {
218 memberInstances.forEach(this::addMember);
219 return this;
220 }
221
222 /**
223 * Adds one member to this action profile group with the given weight.
224 *
225 * @param memberId ID of the action profile member to add
226 * @param weight weight
227 * @return this
228 */
229 public Builder addMember(PiActionProfileMemberId memberId, int weight) {
230 addMember(new WeightedMember(memberId, weight));
231 return this;
232 }
233
234 /**
235 * Adds one member to this action profile group with the given weight.
236 *
237 * @param memberInstance the action profile member instance to add
238 * @param weight weight
239 * @return this
240 */
241 public Builder addMember(PiActionProfileMember memberInstance, int weight) {
242 addMember(new WeightedMember(memberInstance, weight));
243 return this;
244 }
245
246 /**
247 * Sets the ID of the action profile.
248 *
249 * @param piActionProfileId the ID of the action profile
Carmelo Casconecb4327a2018-09-11 15:17:23 -0700250 * @return this
251 */
252 public Builder withActionProfileId(PiActionProfileId piActionProfileId) {
Carmelo Cascone99c59db2019-01-17 15:39:35 -0800253 this.actionProfileId = piActionProfileId;
254 return this;
255 }
256
257 /**
258 * Sets the maximum number of members that this group can hold.
259 *
260 * @param maxSize maximum number of members that this group can hold
261 * @return this
262 */
263 public Builder withMaxSize(int maxSize) {
264 checkArgument(maxSize >= 0, "maxSize cannot be negative");
265 this.maxSize = maxSize;
Carmelo Casconecb4327a2018-09-11 15:17:23 -0700266 return this;
267 }
268
269 /**
270 * Creates a new action profile group.
271 *
272 * @return action profile group
273 */
274 public PiActionProfileGroup build() {
Carmelo Cascone99c59db2019-01-17 15:39:35 -0800275 checkNotNull(groupId);
276 checkNotNull(actionProfileId);
277 checkArgument(maxSize == 0 || members.size() <= maxSize,
278 "The number of members cannot exceed maxSize");
279 final boolean validActionProfileId = members.isEmpty() || members.values()
280 .stream().allMatch(m -> m.instance() == null || m.instance()
281 .actionProfile().equals(actionProfileId));
282 checkArgument(
283 validActionProfileId,
284 "The members' action profile ID must match the group one");
Carmelo Casconecb4327a2018-09-11 15:17:23 -0700285 return new PiActionProfileGroup(
Carmelo Cascone99c59db2019-01-17 15:39:35 -0800286 groupId, ImmutableMap.copyOf(members), actionProfileId, maxSize);
287 }
288 }
289
290 /**
291 * Weighted reference to an action profile member as used in an action
292 * profile group.
293 */
294 public static final class WeightedMember {
295
296 public static final int DEFAULT_WEIGHT = 1;
297
298 private final PiActionProfileMemberId memberId;
299 private final int weight;
300 private final PiActionProfileMember memberInstance;
301
302 /**
303 * Creates a new reference for the given action profile member ID and
304 * weight.
305 *
306 * @param memberId action profile member ID
307 * @param weight weight
308 */
309 public WeightedMember(PiActionProfileMemberId memberId, int weight) {
310 checkNotNull(memberId);
311 this.memberId = memberId;
312 this.weight = weight;
313 this.memberInstance = null;
314 }
315
316 /**
317 * Creates a new reference from the given action profile member instance
318 * and weight. This constructor should be used when performing one-shot
319 * group programming (see {@link #instance()}).
320 *
321 * @param memberInstance action profile member instance
322 * @param weight weight
323 */
324 public WeightedMember(PiActionProfileMember memberInstance, int weight) {
325 checkNotNull(memberInstance);
326 this.memberId = memberInstance.id();
327 this.weight = weight;
328 this.memberInstance = memberInstance;
329 }
330
331 /**
332 * Returns the ID of the action profile member.
333 *
334 * @return action profile member ID
335 */
336 public PiActionProfileMemberId id() {
337 return memberId;
338 }
339
340 /**
341 * Returns the weight of this group member.
342 *
343 * @return weight
344 */
345 public int weight() {
346 return weight;
347 }
348
349 /**
350 * If present, returns the instance of the action profile member pointed
351 * by this reference, otherwise returns null. This method is provided as
352 * a convenient way to perform one-shot group programming, and as such
353 * is meaningful only when performing write operations to a device. In
354 * other words, when reading groups from a device only the member
355 * reference should be returned and not the actual instance, hence this
356 * method should return null.
357 *
358 * @return action profile member instance, or null
359 */
360 public PiActionProfileMember instance() {
361 return memberInstance;
362 }
363
364 @Override
365 public int hashCode() {
366 return Objects.hashCode(memberId, weight);
367 }
368
369 @Override
370 public boolean equals(Object obj) {
371 if (this == obj) {
372 return true;
373 }
374 if (obj == null || getClass() != obj.getClass()) {
375 return false;
376 }
377 final WeightedMember other = (WeightedMember) obj;
378 return Objects.equal(this.memberId, other.memberId)
379 && Objects.equal(this.weight, other.weight);
380 }
381
382 @Override
383 public String toString() {
384 return MoreObjects.toStringHelper(this)
385 .add("memberId", memberId)
386 .add("weight", weight)
387 .toString();
Carmelo Casconecb4327a2018-09-11 15:17:23 -0700388 }
389 }
390}