HIGUCHI Yuta
Committed by Gerrit Code Review

resources command enchancement

- Aggregate output of some Discrete resources
   Currently supports: VlanID, MPLS label, Tributary slots
- Add support for Continuous resource

Change-Id: I5d002ba7f43f8b8d06228507b7463c29296aec90
...@@ -19,6 +19,8 @@ import static org.onosproject.net.DeviceId.deviceId; ...@@ -19,6 +19,8 @@ import static org.onosproject.net.DeviceId.deviceId;
19 19
20 import java.util.Set; 20 import java.util.Set;
21 import java.util.HashSet; 21 import java.util.HashSet;
22 +import java.util.List;
23 +import java.util.ArrayList;
22 import java.util.Arrays; 24 import java.util.Arrays;
23 import java.util.Collection; 25 import java.util.Collection;
24 import java.util.Collections; 26 import java.util.Collections;
...@@ -26,13 +28,23 @@ import java.util.Collections; ...@@ -26,13 +28,23 @@ import java.util.Collections;
26 import org.apache.karaf.shell.commands.Argument; 28 import org.apache.karaf.shell.commands.Argument;
27 import org.apache.karaf.shell.commands.Command; 29 import org.apache.karaf.shell.commands.Command;
28 import org.apache.karaf.shell.commands.Option; 30 import org.apache.karaf.shell.commands.Option;
31 +import org.onlab.packet.MplsLabel;
32 +import org.onlab.packet.VlanId;
29 import org.onosproject.cli.AbstractShellCommand; 33 import org.onosproject.cli.AbstractShellCommand;
30 import org.onosproject.net.DeviceId; 34 import org.onosproject.net.DeviceId;
31 import org.onosproject.net.PortNumber; 35 import org.onosproject.net.PortNumber;
36 +import org.onosproject.net.TributarySlot;
32 import org.onosproject.net.newresource.Resource; 37 import org.onosproject.net.newresource.Resource;
33 import org.onosproject.net.newresource.ResourceService; 38 import org.onosproject.net.newresource.ResourceService;
34 39
35 import com.google.common.base.Strings; 40 import com.google.common.base.Strings;
41 +import com.google.common.collect.ArrayListMultimap;
42 +import com.google.common.collect.DiscreteDomain;
43 +import com.google.common.collect.ImmutableSet;
44 +import com.google.common.collect.Multimap;
45 +import com.google.common.collect.Range;
46 +import com.google.common.collect.RangeSet;
47 +import com.google.common.collect.TreeRangeSet;
36 48
37 /** 49 /**
38 * Lists available resources. 50 * Lists available resources.
...@@ -87,7 +99,8 @@ public class ResourcesCommand extends AbstractShellCommand { ...@@ -87,7 +99,8 @@ public class ResourcesCommand extends AbstractShellCommand {
87 } 99 }
88 100
89 private void printResource(Resource resource, int level) { 101 private void printResource(Resource resource, int level) {
90 - Collection<Resource> children = resourceService.getAvailableResources(resource); 102 + // TODO add an option to show only available resource
103 + Collection<Resource> children = resourceService.getRegisteredResources(resource);
91 104
92 if (resource.equals(Resource.ROOT)) { 105 if (resource.equals(Resource.ROOT)) {
93 print("ROOT"); 106 print("ROOT");
...@@ -99,6 +112,14 @@ public class ResourcesCommand extends AbstractShellCommand { ...@@ -99,6 +112,14 @@ public class ResourcesCommand extends AbstractShellCommand {
99 return; 112 return;
100 } 113 }
101 114
115 + if (resource instanceof Resource.Continuous) {
116 + print("%s%s: %f", Strings.repeat(" ", level),
117 + resource.last(),
118 + ((Resource.Continuous) resource).value());
119 + // Continuous resource is terminal node, stop here
120 + return;
121 + } else {
122 +
102 String toString = String.valueOf(resource.last()); 123 String toString = String.valueOf(resource.last());
103 if (toString.startsWith(resourceName)) { 124 if (toString.startsWith(resourceName)) {
104 print("%s%s", Strings.repeat(" ", level), 125 print("%s%s", Strings.repeat(" ", level),
...@@ -109,14 +130,70 @@ public class ResourcesCommand extends AbstractShellCommand { ...@@ -109,14 +130,70 @@ public class ResourcesCommand extends AbstractShellCommand {
109 toString); 130 toString);
110 } 131 }
111 } 132 }
133 + }
134 +
135 +
136 + // Classify children into aggregatable terminal resources and everything else
137 +
138 + Set<Class<?>> aggregatableTypes = ImmutableSet.<Class<?>>builder()
139 + .add(VlanId.class)
140 + .add(MplsLabel.class)
141 + .build();
142 + // (last() resource name) -> { Resource }
143 + Multimap<String, Resource> aggregatables = ArrayListMultimap.create();
144 + List<Resource> nonAggregatable = new ArrayList<>();
145 +
146 + for (Resource r : children) {
147 + if (r instanceof Resource.Continuous) {
148 + // non-aggregatable terminal node
149 + nonAggregatable.add(r);
150 + } else if (aggregatableTypes.contains(r.last().getClass())) {
151 + // aggregatable & terminal node
152 + aggregatables.put(r.last().getClass().getSimpleName(), r);
153 + } else {
154 + nonAggregatable.add(r);
155 + }
156 + }
157 +
158 + // print aggregated (terminal)
159 + aggregatables.asMap().entrySet()
160 + .forEach(e -> {
161 + // for each type...
162 + String resourceName = e.getKey();
163 +
164 + RangeSet<Long> rangeSet = TreeRangeSet.create();
165 +
166 + // aggregate into RangeSet
167 + e.getValue().stream()
168 + .map(Resource::last)
169 + .map(res -> {
170 + if (res instanceof VlanId) {
171 + return (long) ((VlanId) res).toShort();
172 + } else if (res instanceof MplsLabel) {
173 + return (long) ((MplsLabel) res).toInt();
174 + } else if (res instanceof TributarySlot) {
175 + return ((TributarySlot) res).index();
176 + }
177 + // TODO support Lambda (OchSignal types)
178 + return 0L;
179 + })
180 + .map(Range::singleton)
181 + .map(range -> range.canonical(DiscreteDomain.longs()))
182 + .forEach(rangeSet::add);
183 +
184 + print("%s%s: %s", Strings.repeat(" ", level + 1),
185 + resourceName,
186 + rangeSet);
187 + });
188 +
112 189
190 + // print non-aggregatables (recurse)
113 if (sort) { 191 if (sort) {
114 - children.stream() 192 + nonAggregatable.stream()
115 .sorted((o1, o2) -> String.valueOf(o1.id()).compareTo(String.valueOf(o2.id()))) 193 .sorted((o1, o2) -> String.valueOf(o1.id()).compareTo(String.valueOf(o2.id())))
116 .forEach(r -> printResource(r, level + 1)); 194 .forEach(r -> printResource(r, level + 1));
117 } else { 195 } else {
118 - // TODO: Should consider better output for leaf nodes 196 + nonAggregatable.forEach(r -> printResource(r, level + 1));
119 - children.forEach(r -> printResource(r, level + 1));
120 } 197 }
121 } 198 }
122 } 199 }
......