Ayaka Koshibe
Committed by Gerrit Code Review

Linc-OE ports now identifiable as Och and OMS ports.

Reference: ONOS-1803

Conflicts:
	utils/misc/src/main/java/org/onlab/util/Frequency.java

Change-Id: Ie2bdf74f8198afbd58a4762ff97bff6f4e9010df
...@@ -28,6 +28,9 @@ import org.onosproject.net.SparseAnnotations; ...@@ -28,6 +28,9 @@ import org.onosproject.net.SparseAnnotations;
28 import org.onosproject.net.device.DefaultDeviceDescription; 28 import org.onosproject.net.device.DefaultDeviceDescription;
29 import org.onosproject.net.device.DefaultPortDescription; 29 import org.onosproject.net.device.DefaultPortDescription;
30 import org.onosproject.net.device.DeviceDescription; 30 import org.onosproject.net.device.DeviceDescription;
31 +import org.onosproject.net.device.OchPortDescription;
32 +import org.onosproject.net.device.OduCltPortDescription;
33 +import org.onosproject.net.device.OmsPortDescription;
31 import org.onosproject.net.device.PortDescription; 34 import org.onosproject.net.device.PortDescription;
32 import org.onosproject.store.Timestamp; 35 import org.onosproject.store.Timestamp;
33 import org.onosproject.store.impl.Timestamped; 36 import org.onosproject.store.impl.Timestamped;
...@@ -97,9 +100,34 @@ class DeviceDescriptions { ...@@ -97,9 +100,34 @@ class DeviceDescriptions {
97 if (oldOne != null) { 100 if (oldOne != null) {
98 SparseAnnotations merged = union(oldOne.value().annotations(), 101 SparseAnnotations merged = union(oldOne.value().annotations(),
99 newDesc.value().annotations()); 102 newDesc.value().annotations());
100 - newOne = new Timestamped<PortDescription>( 103 + newOne = null;
101 - new DefaultPortDescription(newDesc.value(), merged), 104 + switch (newDesc.value().type()) {
102 - newDesc.timestamp()); 105 + case OMS:
106 + OmsPortDescription omsDesc = (OmsPortDescription) (newDesc.value());
107 + newOne = new Timestamped<PortDescription>(
108 + new OmsPortDescription(
109 + omsDesc, omsDesc.minFrequency(), omsDesc.maxFrequency(), omsDesc.grid(), merged),
110 + newDesc.timestamp());
111 + break;
112 + case OCH:
113 + OchPortDescription ochDesc = (OchPortDescription) (newDesc.value());
114 + newOne = new Timestamped<PortDescription>(
115 + new OchPortDescription(
116 + ochDesc, ochDesc.signalType(), ochDesc.isTunable(), ochDesc.lambda(), merged),
117 + newDesc.timestamp());
118 + break;
119 + case ODUCLT:
120 + OduCltPortDescription ocDesc = (OduCltPortDescription) (newDesc.value());
121 + newOne = new Timestamped<PortDescription>(
122 + new OduCltPortDescription(
123 + ocDesc, ocDesc.signalType(), merged),
124 + newDesc.timestamp());
125 + break;
126 + default:
127 + newOne = new Timestamped<PortDescription>(
128 + new DefaultPortDescription(newDesc.value(), merged),
129 + newDesc.timestamp());
130 + }
103 } 131 }
104 portDescs.put(newOne.value().portNumber(), newOne); 132 portDescs.put(newOne.value().portNumber(), newOne);
105 } 133 }
......
...@@ -717,7 +717,6 @@ public class GossipDeviceStore ...@@ -717,7 +717,6 @@ public class GossipDeviceStore
717 public synchronized DeviceEvent updatePortStatus(ProviderId providerId, 717 public synchronized DeviceEvent updatePortStatus(ProviderId providerId,
718 DeviceId deviceId, 718 DeviceId deviceId,
719 PortDescription portDescription) { 719 PortDescription portDescription) {
720 -
721 final Timestamp newTimestamp; 720 final Timestamp newTimestamp;
722 try { 721 try {
723 newTimestamp = deviceClockService.getTimestamp(deviceId); 722 newTimestamp = deviceClockService.getTimestamp(deviceId);
...@@ -1000,13 +999,14 @@ public class GossipDeviceStore ...@@ -1000,13 +999,14 @@ public class GossipDeviceStore
1000 // if no primary, assume not enabled 999 // if no primary, assume not enabled
1001 boolean isEnabled = false; 1000 boolean isEnabled = false;
1002 DefaultAnnotations annotations = DefaultAnnotations.builder().build(); 1001 DefaultAnnotations annotations = DefaultAnnotations.builder().build();
1003 - 1002 + Timestamp newest = null;
1004 final Timestamped<PortDescription> portDesc = primDescs.getPortDesc(number); 1003 final Timestamped<PortDescription> portDesc = primDescs.getPortDesc(number);
1005 if (portDesc != null) { 1004 if (portDesc != null) {
1006 isEnabled = portDesc.value().isEnabled(); 1005 isEnabled = portDesc.value().isEnabled();
1007 annotations = merge(annotations, portDesc.value().annotations()); 1006 annotations = merge(annotations, portDesc.value().annotations());
1007 + newest = portDesc.timestamp();
1008 } 1008 }
1009 - 1009 + Port updated = null;
1010 for (Entry<ProviderId, DeviceDescriptions> e : descsMap.entrySet()) { 1010 for (Entry<ProviderId, DeviceDescriptions> e : descsMap.entrySet()) {
1011 if (e.getKey().equals(primary)) { 1011 if (e.getKey().equals(primary)) {
1012 continue; 1012 continue;
...@@ -1019,30 +1019,35 @@ public class GossipDeviceStore ...@@ -1019,30 +1019,35 @@ public class GossipDeviceStore
1019 // annotation merging. not so efficient, should revisit later 1019 // annotation merging. not so efficient, should revisit later
1020 final Timestamped<PortDescription> otherPortDesc = e.getValue().getPortDesc(number); 1020 final Timestamped<PortDescription> otherPortDesc = e.getValue().getPortDesc(number);
1021 if (otherPortDesc != null) { 1021 if (otherPortDesc != null) {
1022 + if (newest != null && newest.isNewerThan(otherPortDesc.timestamp())) {
1023 + continue;
1024 + }
1022 annotations = merge(annotations, otherPortDesc.value().annotations()); 1025 annotations = merge(annotations, otherPortDesc.value().annotations());
1026 + switch (otherPortDesc.value().type()) {
1027 + case OMS:
1028 + OmsPortDescription omsPortDesc = (OmsPortDescription) otherPortDesc.value();
1029 + updated = new OmsPort(device, number, isEnabled, omsPortDesc.minFrequency(),
1030 + omsPortDesc.maxFrequency(), omsPortDesc.grid());
1031 + break;
1032 + case OCH:
1033 + OchPortDescription ochPortDesc = (OchPortDescription) otherPortDesc.value();
1034 + updated = new OchPort(device, number, isEnabled, ochPortDesc.signalType(),
1035 + ochPortDesc.isTunable(), ochPortDesc.lambda(), annotations);
1036 + break;
1037 + case ODUCLT:
1038 + OduCltPortDescription oduCltPortDesc = (OduCltPortDescription) otherPortDesc.value();
1039 + updated = new OduCltPort(device, number, isEnabled, oduCltPortDesc.signalType(), annotations);
1040 + break;
1041 + default:
1042 + updated = new DefaultPort(device, number, isEnabled, annotations);
1043 + }
1044 + newest = otherPortDesc.timestamp();
1023 } 1045 }
1024 } 1046 }
1025 -
1026 if (portDesc == null) { 1047 if (portDesc == null) {
1027 - return new DefaultPort(device, number, false, annotations); 1048 + return updated == null ? new DefaultPort(device, number, false, annotations) : updated;
1028 - }
1029 -
1030 - switch (portDesc.value().type()) {
1031 - case OMS:
1032 - OmsPortDescription omsPortDesc = (OmsPortDescription) portDesc.value();
1033 - return new OmsPort(device, number, isEnabled, omsPortDesc.minFrequency(),
1034 - omsPortDesc.maxFrequency(), omsPortDesc.grid());
1035 - case OCH:
1036 - OchPortDescription ochPortDesc = (OchPortDescription) portDesc.value();
1037 - return new OchPort(device, number, isEnabled, ochPortDesc.signalType(),
1038 - ochPortDesc.isTunable(), ochPortDesc.lambda(), annotations);
1039 - case ODUCLT:
1040 - OduCltPortDescription oduCltPortDesc = (OduCltPortDescription) portDesc.value();
1041 - return new OduCltPort(device, number, isEnabled, oduCltPortDesc.signalType(), annotations);
1042 - default:
1043 - return new DefaultPort(device, number, isEnabled, portDesc.value().type(),
1044 - portDesc.value().portSpeed(), annotations);
1045 } 1049 }
1050 + return updated == null ? new DefaultPort(device, number, isEnabled, annotations) : updated;
1046 } 1051 }
1047 1052
1048 /** 1053 /**
......
...@@ -342,7 +342,7 @@ public class OpenFlowDeviceProvider extends AbstractProvider implements DevicePr ...@@ -342,7 +342,7 @@ public class OpenFlowDeviceProvider extends AbstractProvider implements DevicePr
342 if (sw.isOptical()) { 342 if (sw.isOptical()) {
343 OpenFlowOpticalSwitch opsw = (OpenFlowOpticalSwitch) sw; 343 OpenFlowOpticalSwitch opsw = (OpenFlowOpticalSwitch) sw;
344 opsw.getPortTypes().forEach(type -> { 344 opsw.getPortTypes().forEach(type -> {
345 - LOG.info("ports: {}", opsw.getPortsOf(type)); 345 + LOG.debug("ports: {}", opsw.getPortsOf(type));
346 opsw.getPortsOf(type).forEach( 346 opsw.getPortsOf(type).forEach(
347 op -> { 347 op -> {
348 portDescs.add(buildPortDescription(type, (OFPortOptical) op)); 348 portDescs.add(buildPortDescription(type, (OFPortOptical) op));
...@@ -406,10 +406,10 @@ public class OpenFlowDeviceProvider extends AbstractProvider implements DevicePr ...@@ -406,10 +406,10 @@ public class OpenFlowDeviceProvider extends AbstractProvider implements DevicePr
406 if (port.getVersion() == OFVersion.OF_13 406 if (port.getVersion() == OFVersion.OF_13
407 && ptype == PortDescPropertyType.OPTICAL_TRANSPORT) { 407 && ptype == PortDescPropertyType.OPTICAL_TRANSPORT) {
408 // At this point, not much is carried in the optical port message. 408 // At this point, not much is carried in the optical port message.
409 - LOG.info("Optical transport port message {}", port.toString()); 409 + LOG.debug("Optical transport port message {}", port.toString());
410 } else { 410 } else {
411 // removable once 1.4+ support complete. 411 // removable once 1.4+ support complete.
412 - LOG.warn("Unsupported optical port properties"); 412 + LOG.debug("Unsupported optical port properties");
413 } 413 }
414 return new DefaultPortDescription(portNo, enabled, type, 0, annotations); 414 return new DefaultPortDescription(portNo, enabled, type, 0, annotations);
415 } 415 }
......
...@@ -17,19 +17,28 @@ package org.onosproject.rest.resources; ...@@ -17,19 +17,28 @@ package org.onosproject.rest.resources;
17 17
18 import com.fasterxml.jackson.databind.JsonNode; 18 import com.fasterxml.jackson.databind.JsonNode;
19 import com.google.common.collect.Lists; 19 import com.google.common.collect.Lists;
20 +
20 import org.onlab.packet.ChassisId; 21 import org.onlab.packet.ChassisId;
21 import org.onlab.packet.IpAddress; 22 import org.onlab.packet.IpAddress;
22 import org.onlab.packet.MacAddress; 23 import org.onlab.packet.MacAddress;
23 import org.onlab.packet.VlanId; 24 import org.onlab.packet.VlanId;
25 +import org.onlab.util.Frequency;
26 +import org.onosproject.net.ChannelSpacing;
24 import org.onosproject.net.ConnectPoint; 27 import org.onosproject.net.ConnectPoint;
25 import org.onosproject.net.DefaultAnnotations; 28 import org.onosproject.net.DefaultAnnotations;
26 import org.onosproject.net.Device; 29 import org.onosproject.net.Device;
27 import org.onosproject.net.DeviceId; 30 import org.onosproject.net.DeviceId;
31 +import org.onosproject.net.GridType;
28 import org.onosproject.net.Host; 32 import org.onosproject.net.Host;
29 import org.onosproject.net.HostId; 33 import org.onosproject.net.HostId;
30 import org.onosproject.net.HostLocation; 34 import org.onosproject.net.HostLocation;
31 import org.onosproject.net.Link; 35 import org.onosproject.net.Link;
32 import org.onosproject.net.MastershipRole; 36 import org.onosproject.net.MastershipRole;
37 +import org.onosproject.net.OchPort;
38 +import org.onosproject.net.OchSignal;
39 +import org.onosproject.net.OduCltPort;
40 +import org.onosproject.net.OduSignalType;
41 +import org.onosproject.net.OmsPort;
33 import org.onosproject.net.Port; 42 import org.onosproject.net.Port;
34 import org.onosproject.net.SparseAnnotations; 43 import org.onosproject.net.SparseAnnotations;
35 import org.onosproject.net.device.DefaultDeviceDescription; 44 import org.onosproject.net.device.DefaultDeviceDescription;
...@@ -41,6 +50,9 @@ import org.onosproject.net.device.DeviceProvider; ...@@ -41,6 +50,9 @@ import org.onosproject.net.device.DeviceProvider;
41 import org.onosproject.net.device.DeviceProviderRegistry; 50 import org.onosproject.net.device.DeviceProviderRegistry;
42 import org.onosproject.net.device.DeviceProviderService; 51 import org.onosproject.net.device.DeviceProviderService;
43 import org.onosproject.net.device.DeviceService; 52 import org.onosproject.net.device.DeviceService;
53 +import org.onosproject.net.device.OchPortDescription;
54 +import org.onosproject.net.device.OduCltPortDescription;
55 +import org.onosproject.net.device.OmsPortDescription;
44 import org.onosproject.net.device.PortDescription; 56 import org.onosproject.net.device.PortDescription;
45 import org.onosproject.net.host.DefaultHostDescription; 57 import org.onosproject.net.host.DefaultHostDescription;
46 import org.onosproject.net.host.HostProvider; 58 import org.onosproject.net.host.HostProvider;
...@@ -82,6 +94,10 @@ class ConfigProvider implements DeviceProvider, LinkProvider, HostProvider { ...@@ -82,6 +94,10 @@ class ConfigProvider implements DeviceProvider, LinkProvider, HostProvider {
82 94
83 private static final String UNKNOWN = "unknown"; 95 private static final String UNKNOWN = "unknown";
84 96
97 + private static final Frequency CENTER = Frequency.ofTHz(193.1);
98 + // C-band has 4.4 THz (4,400 GHz) total bandwidth
99 + private static final Frequency TOTAL = Frequency.ofTHz(4.4);
100 +
85 private CountDownLatch deviceLatch; 101 private CountDownLatch deviceLatch;
86 102
87 private final JsonNode cfg; 103 private final JsonNode cfg;
...@@ -200,6 +216,21 @@ class ConfigProvider implements DeviceProvider, LinkProvider, HostProvider { ...@@ -200,6 +216,21 @@ class ConfigProvider implements DeviceProvider, LinkProvider, HostProvider {
200 // Parses the given node with port information. 216 // Parses the given node with port information.
201 private PortDescription parsePort(JsonNode node) { 217 private PortDescription parsePort(JsonNode node) {
202 Port.Type type = Port.Type.valueOf(node.path("type").asText("COPPER")); 218 Port.Type type = Port.Type.valueOf(node.path("type").asText("COPPER"));
219 + switch (type) {
220 + case COPPER:
221 + return new DefaultPortDescription(portNumber(node.path("port").asLong(0)),
222 + node.path("enabled").asBoolean(true),
223 + type, node.path("speed").asLong(1_000));
224 + case FIBER:
225 + // Currently, assume OMS when FIBER. Provide sane defaults.
226 + return new OmsPortDescription(portNumber(node.path("port").asLong(0)),
227 + node.path("enabled").asBoolean(true),
228 + CENTER,
229 + CENTER.add(TOTAL),
230 + Frequency.ofGHz(100));
231 + default:
232 + log.warn("{}: Unsupported Port Type");
233 + }
203 return new DefaultPortDescription(portNumber(node.path("port").asLong(0)), 234 return new DefaultPortDescription(portNumber(node.path("port").asLong(0)),
204 node.path("enabled").asBoolean(true), 235 node.path("enabled").asBoolean(true),
205 type, node.path("speed").asLong(1_000)); 236 type, node.path("speed").asLong(1_000));
...@@ -224,7 +255,8 @@ class ConfigProvider implements DeviceProvider, LinkProvider, HostProvider { ...@@ -224,7 +255,8 @@ class ConfigProvider implements DeviceProvider, LinkProvider, HostProvider {
224 ConnectPoint dst = connectPoint(get(node, "dst")); 255 ConnectPoint dst = connectPoint(get(node, "dst"));
225 Link.Type type = Link.Type.valueOf(get(node, "type", "DIRECT")); 256 Link.Type type = Link.Type.valueOf(get(node, "type", "DIRECT"));
226 SparseAnnotations annotations = annotations(node.get("annotations")); 257 SparseAnnotations annotations = annotations(node.get("annotations"));
227 - 258 + // take annotations to update optical ports with correct attributes.
259 + updatePorts(src, dst, annotations);
228 DefaultLinkDescription desc = reverse ? 260 DefaultLinkDescription desc = reverse ?
229 new DefaultLinkDescription(dst, src, type, annotations) : 261 new DefaultLinkDescription(dst, src, type, annotations) :
230 new DefaultLinkDescription(src, dst, type, annotations); 262 new DefaultLinkDescription(src, dst, type, annotations);
...@@ -234,6 +266,98 @@ class ConfigProvider implements DeviceProvider, LinkProvider, HostProvider { ...@@ -234,6 +266,98 @@ class ConfigProvider implements DeviceProvider, LinkProvider, HostProvider {
234 connectPoints.add(dst); 266 connectPoints.add(dst);
235 } 267 }
236 268
269 + private void updatePorts(ConnectPoint src, ConnectPoint dst, SparseAnnotations annotations) {
270 + DeviceId srcId = src.deviceId();
271 + DeviceId dstId = dst.deviceId();
272 + Port srcPort = deviceService.getPort(srcId, src.port());
273 + Port dstPort = deviceService.getPort(dstId, dst.port());
274 +
275 + final String linkType = annotations.value("optical.type");
276 + if ("cross-connect".equals(linkType)) {
277 + String value = annotations.value("bandwidth").trim();
278 + try {
279 + double bw = Double.parseDouble(value);
280 + updateOchPort(bw, srcPort, dstPort, srcId, dstId);
281 + } catch (NumberFormatException e) {
282 + log.warn("Invalid bandwidth ({}), can't configure port(s)", value);
283 + return;
284 + }
285 + } else if ("WDM".equals(linkType)) {
286 + String value = annotations.value("optical.waves").trim();
287 + try {
288 + int numChls = Integer.parseInt(value);
289 + updateOMSPorts(numChls, srcPort, dstPort, srcId, dstId);
290 + } catch (NumberFormatException e) {
291 + log.warn("Invalid channel ({}), can't configure port(s)", value);
292 + return;
293 + }
294 + }
295 + }
296 +
297 + // uses 'bandwidth' annotation to determine the channel spacing.
298 + private void updateOchPort(double bw, Port srcPort, Port dstPort, DeviceId srcId, DeviceId dstId) {
299 + Device src = deviceService.getDevice(srcId);
300 + Device dst = deviceService.getDevice(dstId);
301 + // bandwidth in MHz (assuming Hz - linc is not clear if Hz or b).
302 + Frequency spacing = Frequency.ofMHz(bw);
303 + // channel bandwidth is smaller than smallest standard channel spacing.
304 + ChannelSpacing chsp = null;
305 + if (spacing.compareTo(ChannelSpacing.CHL_6P25GHZ.frequency()) <= 0) {
306 + chsp = ChannelSpacing.CHL_6P25GHZ;
307 + }
308 + for (int i = 1; i < ChannelSpacing.values().length; i++) {
309 + Frequency val = ChannelSpacing.values()[i].frequency();
310 + // pick the next highest or equal channel interval.
311 + if (val.isLessThan(spacing)) {
312 + chsp = ChannelSpacing.values()[i - 1];
313 + break;
314 + }
315 + }
316 + if (chsp == null) {
317 + log.warn("Invalid channel spacing ({}), can't configure port(s)", spacing);
318 + return;
319 + }
320 + OchSignal signal = new OchSignal(GridType.DWDM, chsp, 1, 1);
321 + if (src.type() == Device.Type.ROADM) {
322 + PortDescription portDesc = new OchPortDescription(srcPort.number(), srcPort.isEnabled(),
323 + OduSignalType.ODU4, true, signal);
324 + deviceProviderService.portStatusChanged(srcId, portDesc);
325 + }
326 + if (dst.type() == Device.Type.ROADM) {
327 + PortDescription portDesc = new OchPortDescription(dstPort.number(), dstPort.isEnabled(),
328 + OduSignalType.ODU4, true, signal);
329 + deviceProviderService.portStatusChanged(dstId, portDesc);
330 + }
331 + }
332 +
333 + private void updateOMSPorts(int numChls, Port srcPort, Port dstPort, DeviceId srcId, DeviceId dstId) {
334 + // round down to largest slot that allows numChl channels to fit into C
335 + // band range
336 + ChannelSpacing chl = null;
337 + Frequency perChl = TOTAL.floorDivision(numChls);
338 + for (int i = 0; i < ChannelSpacing.values().length; i++) {
339 + Frequency val = ChannelSpacing.values()[i].frequency();
340 + if (val.isLessThan(perChl)) {
341 + chl = ChannelSpacing.values()[i];
342 + break;
343 + }
344 + }
345 + if (chl == null) {
346 + chl = ChannelSpacing.CHL_6P25GHZ;
347 + }
348 +
349 + // if true, there was less channels than can be tightly packed.
350 + Frequency grid = (chl == null) ? Frequency.ofGHz(100) : chl.frequency();
351 + // say Linc's 1st slot starts at CENTER and goes up from there.
352 + Frequency min = CENTER.add(grid);
353 + Frequency max = CENTER.add(grid.multiply(numChls));
354 +
355 + PortDescription srcPortDesc = new OmsPortDescription(srcPort.number(), srcPort.isEnabled(), min, max, grid);
356 + PortDescription dstPortDesc = new OmsPortDescription(dstPort.number(), dstPort.isEnabled(), min, max, grid);
357 + deviceProviderService.portStatusChanged(srcId, srcPortDesc);
358 + deviceProviderService.portStatusChanged(dstId, dstPortDesc);
359 + }
360 +
237 // Parses the given JSON and provides hosts as configured. 361 // Parses the given JSON and provides hosts as configured.
238 private void parseHosts() { 362 private void parseHosts() {
239 try { 363 try {
...@@ -298,15 +422,33 @@ class ConfigProvider implements DeviceProvider, LinkProvider, HostProvider { ...@@ -298,15 +422,33 @@ class ConfigProvider implements DeviceProvider, LinkProvider, HostProvider {
298 422
299 // Creates a port description from the specified port. 423 // Creates a port description from the specified port.
300 private PortDescription description(Port p) { 424 private PortDescription description(Port p) {
301 - return new DefaultPortDescription(p.number(), p.isEnabled(), p.type(), p.portSpeed()); 425 + switch (p.type()) {
426 + case OMS:
427 + OmsPort op = (OmsPort) p;
428 + return new OmsPortDescription(
429 + op.number(), op.isEnabled(), op.minFrequency(), op.maxFrequency(), op.grid());
430 + case OCH:
431 + OchPort ochp = (OchPort) p;
432 + return new OchPortDescription(
433 + ochp.number(), ochp.isEnabled(), ochp.signalType(), ochp.isTunable(), ochp.lambda());
434 + case ODUCLT:
435 + OduCltPort odup = (OduCltPort) p;
436 + return new OduCltPortDescription(
437 + odup.number(), odup.isEnabled(), odup.signalType());
438 + default:
439 + return new DefaultPortDescription(p.number(), p.isEnabled(), p.type(), p.portSpeed());
440 + }
302 } 441 }
303 442
304 // Creates a port description from the specified connection point. 443 // Creates a port description from the specified connection point.
305 private PortDescription description(ConnectPoint cp) { 444 private PortDescription description(ConnectPoint cp) {
306 - return new DefaultPortDescription(cp.port(), true); 445 + Port p = deviceService.getPort(cp.deviceId(), cp.port());
446 + if (p == null) {
447 + return new DefaultPortDescription(cp.port(), true);
448 + }
449 + return description(p);
307 } 450 }
308 451
309 -
310 // Produces set of annotations from the given JSON node. 452 // Produces set of annotations from the given JSON node.
311 private SparseAnnotations annotations(JsonNode node) { 453 private SparseAnnotations annotations(JsonNode node) {
312 if (node == null) { 454 if (node == null) {
......