blob: 22a20c39a4958a1f3809b1552e84b16cea64b5ca [file] [log] [blame]
jaegonkim185299e2018-04-29 20:15:25 +09001/*
2 * Copyright 2015-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 */
16package org.onosproject.cli.net;
17
18import com.google.common.base.MoreObjects;
19import com.google.common.collect.ImmutableSet;
20import com.google.common.collect.SetMultimap;
21import com.google.common.collect.Streams;
Ray Milkeyd84f89b2018-08-17 14:54:17 -070022import org.apache.karaf.shell.api.action.Argument;
23import org.apache.karaf.shell.api.action.Command;
24import org.apache.karaf.shell.api.action.lifecycle.Service;
25import org.apache.karaf.shell.api.action.Option;
jaegonkim185299e2018-04-29 20:15:25 +090026import org.onosproject.cli.AbstractShellCommand;
27import org.onosproject.net.AnnotationKeys;
28import org.onosproject.net.ConnectPoint;
29import org.onosproject.net.DefaultDevice;
30import org.onosproject.net.Device;
31import org.onosproject.net.DeviceId;
32import org.onosproject.net.Link;
33import org.onosproject.net.LinkKey;
34import org.onosproject.net.Port;
35import org.onosproject.net.device.DeviceService;
36import org.onosproject.net.device.PortStatistics;
37import org.onosproject.net.flow.FlowEntry;
38import org.onosproject.net.flow.FlowRule;
39import org.onosproject.net.flow.FlowRuleService;
40import org.onosproject.net.intent.FlowRuleIntent;
41import org.onosproject.net.intent.Intent;
42import org.onosproject.net.intent.IntentService;
43import org.onosproject.net.intent.Key;
44import org.onosproject.net.intent.ObjectiveTrackerService;
45import org.onosproject.net.intent.PointToPointIntent;
46import org.onosproject.net.intent.WorkPartitionService;
47import org.onosproject.net.statistic.FlowStatisticService;
48
49import java.lang.reflect.Field;
50import java.util.ArrayList;
51import java.util.Collection;
52import java.util.HashMap;
53import java.util.HashSet;
54import java.util.List;
55import java.util.Map;
56import java.util.Objects;
57import java.util.Set;
58import java.util.stream.Stream;
59
Ray Milkeyd84f89b2018-08-17 14:54:17 -070060@Service
jaegonkim185299e2018-04-29 20:15:25 +090061@Command(scope = "onos", name = "intents-diagnosis",
62 description = "Diagnosis intents")
63public class IntentsDiagnosisCommand extends AbstractShellCommand {
64
65 @Argument(index = 0, name = "key",
66 description = "Intent key",
67 required = false, multiValued = false)
68 String key = null;
69
70 @Option(name = "-d", aliases = "--details", description = "printing intent details",
71 required = false, multiValued = false)
72 private boolean dump = false;
73
74 @Option(name = "-l", aliases = "--link", description = "printing local intentsByLink",
75 required = false, multiValued = false)
76 private boolean dumpIntentByLink = false;
77
78 private static final int MAX_INTENT_PATH = 100;
79 private static final String FIELD_INTENTS_BY_LINK = "intentsByLink";
80
81 @Override
Ray Milkeyd84f89b2018-08-17 14:54:17 -070082 protected void doExecute() {
jaegonkim185299e2018-04-29 20:15:25 +090083
84 print("intents-diagnosis");
85 ServiceRefs svcRefs = buildServiceRefs();
86 if (svcRefs == null) {
87 return;
88 }
89 try {
90 for (Intent intent : svcRefs.intentsService().getIntents()) {
91 if (key != null && !intent.key().toString().equals(key)) {
92 continue;
93 }
94 print("");
95 printIntentHdr(intent, svcRefs);
96 if (intent instanceof PointToPointIntent) {
97 diagnosisP2Pintent((PointToPointIntent) intent, svcRefs);
98 } else {
99 // TODO : it needs to implement other types of intent
100 print(" It doesn't support %s intent.", intent.getClass().getSimpleName());
101 }
102 }
103 if (dumpIntentByLink) {
104 dumpIntentsByLink(svcRefs);
105 }
106 } catch (Exception e) {
107 print("error: " + e);
108 }
109
110 }
111
112 private void printIntentHdr(Intent intent, ServiceRefs svcRefs) {
113 print("* intent key: %s", intent.key());
114 print(" - state: %s", svcRefs.intentsService().getIntentState(intent.key()));
115 dump(" - leader: %s %s", svcRefs.getWorkPartitionService().getLeader(intent.key(), Key::hash),
116 svcRefs.workPartitionService.isMine(intent.key(), Key::hash) ? "(Mine)" : "");
117 }
118
Ray Milkey30ab5152018-05-08 09:29:28 -0700119 private void dumpIntentsByLink(ServiceRefs svcRefs) {
jaegonkim185299e2018-04-29 20:15:25 +0900120 Set<Map.Entry<LinkKey, Key>> intentsByLink = getIntentsByLinkSet(svcRefs);
121
122 print("* intentsbylink:");
123 for (Map.Entry<LinkKey, Key> entry : intentsByLink) {
124 print(" - %s, Intents: %s ", entry.getKey(), entry.getValue());
125 }
126 }
127
Ray Milkey30ab5152018-05-08 09:29:28 -0700128 private Set<Map.Entry<LinkKey, Key>> getIntentsByLinkSet(ServiceRefs svcRefs) {
jaegonkim185299e2018-04-29 20:15:25 +0900129
Ray Milkey30ab5152018-05-08 09:29:28 -0700130 try {
jaegonkim185299e2018-04-29 20:15:25 +0900131
Ray Milkey30ab5152018-05-08 09:29:28 -0700132 ObjectiveTrackerService objTracker = svcRefs.getObjectiveTrackerService();
jaegonkim185299e2018-04-29 20:15:25 +0900133
Ray Milkey30ab5152018-05-08 09:29:28 -0700134 // Utilizing reflection instead of adding new interface for getting intentsByLink
135 Field f = objTracker.getClass().getDeclaredField(FIELD_INTENTS_BY_LINK);
136 f.setAccessible(true);
137 SetMultimap<LinkKey, Key> intentsByLink = (SetMultimap<LinkKey, Key>) f.get(objTracker);
138
139 return ImmutableSet.copyOf(intentsByLink.entries());
140 } catch (NoSuchFieldException | IllegalAccessException ex) {
141 error("error: " + ex);
142 return ImmutableSet.of();
143 }
jaegonkim185299e2018-04-29 20:15:25 +0900144 }
145
Ray Milkey30ab5152018-05-08 09:29:28 -0700146 private void diagnosisP2Pintent(PointToPointIntent intent, ServiceRefs svcRefs) {
jaegonkim185299e2018-04-29 20:15:25 +0900147
148 List<Intent> installableIntents = svcRefs.intentsService().getInstallableIntents(intent.key());
149
150 if (installableIntents.size() == 0) {
151 error("NO INSTALLABLE INTENTS");
152 return;
153 }
154
155 Set<String> notSupport = new HashSet<>();
156 for (Intent installable: installableIntents) {
157 if (installable instanceof FlowRuleIntent) {
158 checkP2PFlowRuleIntent(intent, (FlowRuleIntent) installable, svcRefs);
159 } else {
160 // TODO : it needs to implement other types of installables
161 notSupport.add(installable.getClass().getSimpleName());
162 }
163 }
164
165 if (notSupport.size() > 0) {
166 print(" It doesn't support %s.", notSupport);
167 }
168 }
169
Ray Milkey30ab5152018-05-08 09:29:28 -0700170 private void checkP2PFlowRuleIntent(PointToPointIntent intent, FlowRuleIntent installable, ServiceRefs svcRefs) {
jaegonkim185299e2018-04-29 20:15:25 +0900171
172 final Map<DeviceId, DeviceOnIntent> devs = createDevicesOnP2PIntent(intent, installable);
173
174 boolean errorOccurred = false;
175 // checking the number of links & CPs in P2P intent
176 for (DeviceOnIntent dev: devs.values()) {
177 if (dev.getIngressLinks().size() > 1) {
178 error("MULTIPLE NUMBER OF INGRESS LINKs on " + dev.deviceId()
179 + ": " + dev.getIngressLinks());
180 errorOccurred = true;
181 }
182 if (dev.getIngressCps().size() > 1) {
183 error("MULTIPLE NUMBER OF INGRESS CONNECT POINTs on " + dev.deviceId()
184 + ": " + dev.getIngressCps());
185 errorOccurred = true;
186 }
187 if (dev.getEgressLinks().size() > 1) {
188 error("MULTIPLE NUMBER OF EGRESS LINKs: on " + dev.deviceId()
189 + ": " + dev.getEgressLinks());
190 errorOccurred = true;
191 }
192 if (dev.getEgressCps().size() > 1) {
193 error("MULTIPLE NUMBER OF EGRESS CONNECT POINTs: on " + dev.deviceId()
194 + ": " + dev.getEgressCps());
195 errorOccurred = true;
196 }
197 }
198
199 ConnectPoint startCp = intent.filteredIngressPoint().connectPoint();
200 DeviceOnIntent startDev = devs.get(startCp.deviceId());
201 if (startDev == null) {
202 error("STARTING CONNECT POINT DEVICE: " + startCp.deviceId() + " is not on intent");
203 errorOccurred = true;
204 }
205
206 ConnectPoint endCp = intent.filteredEgressPoint().connectPoint();
207 DeviceOnIntent endDev = devs.get(endCp.deviceId());
208 if (endDev == null) {
209 error("END CONNECT POINT DEVICE: " + endCp.deviceId() + " is not on intent");
210 errorOccurred = true;
211 }
212
213 if (!errorOccurred) {
214 // Per device checking with path-order
215 DeviceOnIntent dev = startDev;
216 int i = 0;
217 for (; i < MAX_INTENT_PATH; i++) {
218 perDeviceChecking(dev, svcRefs);
219
220 // P2P intent has only 1 egress CP
221 ConnectPoint egressCp = dev.getEgressCps().stream().findFirst().orElse(null);
222 if (egressCp != null && Objects.equals(endCp, egressCp)) {
223 break;
224 }
225
226 // P2P intent has only 1 egress link
227 Link egressLink = dev.getEgressLinks().stream().findFirst().orElse(null);
228 if (egressLink == null) {
229 error("INVALID EGRESS LINK & CONNECT POINT for: " + dev);
230 errorOccurred = true;
231 break;
232 }
233 if (Objects.equals(egressLink.dst(), endCp)) {
234 break;
235 }
236
237 // P2P intent only 1 ingress link
238 dev = devs.values().stream()
239 .filter(nextDev -> Objects.equals(
240 egressLink, nextDev.getIngressLinks().stream().findFirst().orElse(null)))
241 .findAny().orElse(null);
242 if (dev == null) {
243 error("FAILED TO FIND NEXT DEV for: " + dev + ", LINK: " + egressLink);
244 errorOccurred = true;
245 break;
246 }
247 }
248 if (i == MAX_INTENT_PATH) {
249 error("MAX INTENT PATH WAS EXCEEDED");
250 errorOccurred = true;
251 }
252 }
253
254 if (errorOccurred) {
255 // Installable checking
256 dump("");
257 dump("ERROR OCCURRED. DO PER FLOW CHECKING");
258 perFlowRuleChecking(installable, svcRefs);
259 }
260
261 if (svcRefs.workPartitionService.isMine(intent.key(), Key::hash)) {
262 checkIntentsByLink(installable, svcRefs);
263 }
264 }
265
Ray Milkey30ab5152018-05-08 09:29:28 -0700266 private void checkIntentsByLink(FlowRuleIntent installable, ServiceRefs svcRefs) {
jaegonkim185299e2018-04-29 20:15:25 +0900267
268 Set<Map.Entry<LinkKey, Key>> intentsByLink = getIntentsByLinkSet(svcRefs);
269
270 installable.resources().forEach(
271 rsrc -> {
272 if (rsrc instanceof Link) {
273 Link link = (Link) rsrc;
274 LinkKey linkKey = LinkKey.linkKey(link);
275 intentsByLink.stream()
276 .filter(entry -> Objects.equals(entry.getKey(), linkKey)
277 && Objects.equals(entry.getValue(), installable.key()))
278 .findAny()
279 .orElseGet(() -> {
280 error("FAILED TO FIND LINK(" + link + ") for intents: " + installable.key());
281 return null;
282 });
283 }
284 }
285 );
286 }
287
288 // TODO: It needs to consider FLowObjectiveIntent case
289 private void perDeviceChecking(DeviceOnIntent devOnIntent, ServiceRefs svcRefs) {
290
291 Collection<PortStatistics> portStats =
292 svcRefs.deviceService().getPortStatistics(devOnIntent.deviceId());
293 Collection<PortStatistics> portDeltaStats =
294 svcRefs.deviceService().getPortDeltaStatistics(devOnIntent.deviceId());
295
296 dump("");
297 dump(" ------------------------------------------------------------------------------------------");
298
299 Device device = svcRefs.deviceService.getDevice(devOnIntent.deviceId());
300 if (device == null) {
301 error("INVALID DEVICE for " + devOnIntent.deviceId());
302 return;
303 }
304
305 dump(" %s", getDeviceString(device));
306 dump(" %s", device.annotations());
307
308 devOnIntent.getIngressCps().stream()
309 .forEach(cp -> dumpCpStatistics(cp, portStats, portDeltaStats, "INGRESS", svcRefs));
310
311 Stream<FlowEntry> flowEntries = Streams.stream(svcRefs.flowService.getFlowEntries(devOnIntent.deviceId()));
312
313 devOnIntent.getFlowRules().stream()
314 .forEach(
315 intentFlowRule -> {
316 FlowEntry matchedEntry = flowEntries
317 .filter(entry -> Objects.equals(intentFlowRule.id(), entry.id()))
318 .findFirst().orElse(null);
319
320 if (matchedEntry == null) {
321 error("FAILED TO FIND FLOW ENTRY: for " + intentFlowRule);
322 return;
323 }
324
325 if (Objects.equals(intentFlowRule.selector(), matchedEntry.selector()) &&
326 Objects.equals(intentFlowRule.treatment(), matchedEntry.treatment())) {
327 dumpFlowEntry(matchedEntry, "FLOW ENTRY");
328 return;
329 }
330
331 error("INSTALLABLE-FLOW ENTRY mismatch");
332 dumpFlowRule(intentFlowRule, "INSTALLABLE");
333 dumpFlowEntry(matchedEntry, "FLOW ENTRY");
334 }
335 );
336
337 devOnIntent.getEgressCps().stream()
338 .forEach(
339 cp -> dumpCpStatistics(cp, portStats, portDeltaStats, "EGRESS", svcRefs)
340 );
341 }
342
343 // TODO: It needs to consider FLowObjectiveIntent case
344 private void perFlowRuleChecking(FlowRuleIntent installable, ServiceRefs svcRefs) {
345
346 installable.flowRules().forEach(
347 flowrule -> {
348 DeviceId devId = flowrule.deviceId();
349 if (devId == null) {
350 error("INVALID DEVICE ID for " + flowrule);
351 return;
352 }
353
354 Device dev = svcRefs.deviceService.getDevice(devId);
355 if (dev == null) {
356 error("INVALID DEVICE for " + flowrule);
357 return;
358 }
359
360 dump("");
361 dump(
362 " ------------------------------------------------------------------------------------------");
363 dump(" %s", getDeviceString(dev));
364 dump(" %s", dev.annotations());
365
366 svcRefs.flowService().getFlowEntries(devId)
367 .forEach(
368 entry -> {
369 dumpFlowRule(flowrule, "INSTALLABLE");
370 dumpFlowEntry(entry, "FLOW ENTRY");
371
372 if (!flowrule.selector().equals(entry.selector())) {
373 return;
374 }
375 if (flowrule.id().equals(entry.id()) &&
376 flowrule.treatment().equals(entry.treatment())) {
377 dumpFlowEntry(entry, "FLOW ENTRY");
378 return;
379 }
380 error("INSTALLABLE-FLOW ENTRY mismatch");
381 }
382 );
383 }
384 );
385 }
386
387 private Map<DeviceId, DeviceOnIntent> createDevicesOnP2PIntent(
388 PointToPointIntent intent, FlowRuleIntent flowRuleIntent) {
389
390 final Map<DeviceId, DeviceOnIntent> devMap = new HashMap<>();
391
392 flowRuleIntent.resources().forEach(
393 rsrc -> {
394 if (rsrc instanceof Link) {
395 Link link = (Link) rsrc;
396 ConnectPoint srcCp = link.src();
397 ConnectPoint dstCp = link.dst();
398 try {
399 DeviceOnIntent dev = devMap.computeIfAbsent(srcCp.deviceId(), DeviceOnIntent::new);
Ray Milkey30ab5152018-05-08 09:29:28 -0700400 dev.addEgressLink(link);
401
jaegonkim185299e2018-04-29 20:15:25 +0900402 dev = devMap.computeIfAbsent(dstCp.deviceId(), DeviceOnIntent::new);
Ray Milkey30ab5152018-05-08 09:29:28 -0700403 dev.addIngressLink(link);
jaegonkim185299e2018-04-29 20:15:25 +0900404 } catch (IllegalStateException e) {
405 print("error: " + e);
406 }
407 }
408 }
409 );
410
411 ConnectPoint startCp = intent.filteredIngressPoint().connectPoint();
412 DeviceOnIntent startDev = devMap.computeIfAbsent(startCp.deviceId(), DeviceOnIntent::new);
413 if (!startDev.hasIngressCp(startCp)) {
414 startDev.addIngressCp(startCp);
415 }
416
417 ConnectPoint endCp = intent.filteredEgressPoint().connectPoint();
418 DeviceOnIntent endDev = devMap.computeIfAbsent(endCp.deviceId(), DeviceOnIntent::new);
419 if (!endDev.hasEgressCp(endCp)) {
420 endDev.addEgessCp(endCp);
421 }
422
423 flowRuleIntent.flowRules().forEach(
424 flowRule -> {
425 DeviceId devId = flowRule.deviceId();
426 if (devId == null) {
427 error("INVALID DEVICE ID for " + flowRule);
428 return;
429 }
430 DeviceOnIntent dev = devMap.get(devId);
431 if (dev == null) {
432 error("DEVICE(" + devId + ") IS NOT ON INTENTS LINKS");
433 return;
434 }
435
436 dev.addFlowRule(flowRule);
437 }
438 );
439
440 return devMap;
441 }
442
443 private String getDeviceString(Device dev) {
444
445 StringBuilder buf = new StringBuilder();
446 if (dev != null) {
447 buf.append(String.format("Device: %s, ", dev.id()));
448 buf.append(String.format("%s, ", dev.type()));
449 buf.append(String.format("%s, ", dev.manufacturer()));
450 buf.append(String.format("%s, ", dev.hwVersion()));
451 buf.append(String.format("%s, ", dev.swVersion()));
452 if (dev instanceof DefaultDevice) {
453 DefaultDevice dfltDev = (DefaultDevice) dev;
454 if (dfltDev.driver() != null) {
455 buf.append(String.format("%s, ", dfltDev.driver().name()));
456 }
457 String channelId = dfltDev.annotations().value("channelId");
458 if (channelId != null) {
459 buf.append(String.format("%s, ", channelId));
460 }
461 }
462 }
463
464 return buf.toString();
465 }
466
467 private void dumpFlowRule(FlowRule rule, String hdr) {
468 dump(" " + hdr + ":");
469 dump(" - id=%s, priority=%d", rule.id(), rule.priority());
470 dump(" - %s", rule.selector());
471 dump(" - %s", rule.treatment());
472 }
473
474 private void dumpFlowEntry(FlowEntry entry, String hdr) {
475 dumpFlowRule(entry, hdr);
476 dump(" - packets=%d", entry.packets());
477 }
478
479
480 private void dumpCpStatistics(ConnectPoint cp, Collection<PortStatistics> devPortStats,
481 Collection<PortStatistics> devPortDeltaStats, String direction, ServiceRefs svcs) {
482 if (cp == null) {
483 return;
484 }
485
486 dump(" %s:", direction);
487
488 if (cp.port().isLogical()) {
489 dump(" - logical: device: %s, port: %s", cp.deviceId(), cp.port());
490 return;
491 }
492
493 Port port = svcs.deviceService.getPort(cp.deviceId(), cp.port());
494 if (port == null) {
495 return;
496 }
497
498 try {
499 devPortStats.stream()
500 .filter(stat -> stat.portNumber().equals(cp.port()))
501 .forEach(stat -> dump(" - stat : %s:", getPortStatStr(stat, port)));
502 } catch (IllegalStateException e) {
503 error("error: " + e);
504 return;
505 }
506
507 try {
508 devPortDeltaStats.stream()
509 .filter(stat -> stat.portNumber().equals(cp.port()))
510 .forEach(stat -> dump(" - delta : %s:", getPortStatStr(stat, port)));
511 } catch (IllegalStateException e) {
512 error("error: " + e);
513 }
514 }
515
Yuta HIGUCHIe7e71a82018-05-18 16:36:43 -0700516 private void dump(String format, Object... args) {
jaegonkim185299e2018-04-29 20:15:25 +0900517 if (dump) {
518 print(format, args);
519 }
520 }
521
522 private String getPortStatStr(PortStatistics stat, Port port) {
523
524 final String portName = port.annotations().value(AnnotationKeys.PORT_NAME);
525
526 return String.format("port: %s(%s), ", stat.portNumber(), portName) +
527 String.format("enabled: %b, ", port.isEnabled()) +
528 String.format("pktRx: %d, ", stat.packetsReceived()) +
529 String.format("pktTx: %d, ", stat.packetsSent()) +
530 String.format("pktRxErr: %d, ", stat.packetsRxErrors()) +
531 String.format("pktTxErr: %d, ", stat.packetsTxErrors()) +
532 String.format("pktRxDrp: %d, ", stat.packetsRxDropped()) +
533 String.format("pktTxDrp: %d", stat.packetsTxDropped());
534 }
535
536 private static class DeviceOnIntent {
537
538 private final DeviceId devId;
539
540 private Collection<Link> ingressLinks = new ArrayList<>();
541
542 private Collection<Link> egressLinks = new ArrayList<>();
543
544 private Collection<ConnectPoint> ingressCps = new ArrayList<>();
545
546 private Collection<ConnectPoint> egressCps = new ArrayList<>();
547
548 private Collection<FlowRule> flowRules = new ArrayList<>();
549
550 public DeviceOnIntent(DeviceId devId) {
551 this.devId = devId;
552 }
553
554 public DeviceId deviceId() {
555 return devId;
556 }
557
558 public Collection<Link> getIngressLinks() {
559 return ingressLinks;
560 }
561
562 public Collection<Link> getEgressLinks() {
563 return egressLinks;
564 }
565
566 public void addIngressLink(Link link) {
567 ingressLinks.add(link);
568 addIngressCp(link.dst());
569 }
570
571 public void addEgressLink(Link link) {
572 egressLinks.add(link);
573 addEgessCp(link.src());
574 }
575
576 public void addIngressCp(ConnectPoint cp) {
577 ingressCps.add(cp);
578 }
579
580 public void addEgessCp(ConnectPoint cp) {
581 egressCps.add(cp);
582 }
583
584 public boolean hasIngressCp(final ConnectPoint cp) {
585 return ingressCps.stream().anyMatch(icp -> Objects.equals(icp, cp));
586 }
587
588 public boolean hasEgressCp(ConnectPoint cp) {
589 return egressCps.stream().anyMatch(ecp -> Objects.equals(ecp, cp));
590 }
591
592 public Collection<ConnectPoint> getIngressCps() {
593 return ingressCps;
594 }
595
596 public Collection<ConnectPoint> getEgressCps() {
597 return egressCps;
598 }
599
600 public Collection<FlowRule> getFlowRules() {
601 return flowRules;
602 }
603
604 public void addFlowRule(FlowRule flowRule) {
605 flowRules.add(flowRule);
606 }
607
Yuta HIGUCHIe7e71a82018-05-18 16:36:43 -0700608 @Override
jaegonkim185299e2018-04-29 20:15:25 +0900609 public String toString() {
610 return MoreObjects.toStringHelper(getClass())
611 .omitNullValues()
612 .add("devId", devId)
613 .add("ingressLinks", ingressLinks)
614 .add("egressLinks", egressLinks)
615 .add("flowRules", flowRules)
616 .toString();
617 }
618 }
619
620
621 private ServiceRefs buildServiceRefs() {
622 IntentService intentsService = get(IntentService.class);
623 if (intentsService == null) {
624 return null;
625 }
626 DeviceService deviceService = get(DeviceService.class);
627 if (deviceService == null) {
628 return null;
629 }
630 FlowStatisticService flowStatsService = get(FlowStatisticService.class);
631 if (flowStatsService == null) {
632 return null;
633 }
634 FlowRuleService flowService = get(FlowRuleService.class);
635 if (flowService == null) {
636 return null;
637 }
638 WorkPartitionService workPartitionService = get(WorkPartitionService.class);
639 if (workPartitionService == null) {
640 return null;
641 }
642 ObjectiveTrackerService objectiveTrackerService = get(ObjectiveTrackerService.class);
643 if (objectiveTrackerService == null) {
644 return null;
645 }
646
647 return new ServiceRefs(
648 intentsService,
649 deviceService,
650 flowService,
651 workPartitionService,
652 objectiveTrackerService
653 );
654 }
655
656 private static final class ServiceRefs {
657
658 private IntentService intentsService;
659 private DeviceService deviceService;
660 private FlowRuleService flowService;
661 private WorkPartitionService workPartitionService;
662 private ObjectiveTrackerService objectiveTrackerService;
663
664 private ServiceRefs(
665 IntentService intentsService,
666 DeviceService deviceService,
667 FlowRuleService flowService,
668 WorkPartitionService workPartitionService,
669 ObjectiveTrackerService objectiveTrackerService
670 ) {
671 this.intentsService = intentsService;
672 this.deviceService = deviceService;
673 this.flowService = flowService;
674 this.workPartitionService = workPartitionService;
675 this.objectiveTrackerService = objectiveTrackerService;
676 }
677
678 public IntentService intentsService() {
679 return intentsService;
680 }
681
682 public DeviceService deviceService() {
683 return deviceService;
684 }
685
686 public FlowRuleService flowService() {
687 return flowService;
688 }
689
690 public WorkPartitionService getWorkPartitionService() {
691 return workPartitionService;
692 }
693
694 public ObjectiveTrackerService getObjectiveTrackerService() {
695 return objectiveTrackerService;
696 }
697 }
698
699}