Migrate more setFoo(List) setters
[openflowplugin.git] / openflowplugin-impl / src / main / java / org / opendaylight / openflowplugin / impl / common / MultipartReplyTranslatorUtil.java
1 /*
2  * Copyright (c) 2017 Pantheon Technologies s.r.o. and others.  All rights reserved.
3  *
4  * This program and the accompanying materials are made available under the
5  * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6  * and is available at http://www.eclipse.org/legal/epl-v10.html
7  */
8 package org.opendaylight.openflowplugin.impl.common;
9
10 import java.util.ArrayList;
11 import java.util.List;
12 import java.util.Map;
13 import java.util.Optional;
14 import java.util.stream.Collectors;
15 import org.eclipse.jdt.annotation.Nullable;
16 import org.opendaylight.openflowplugin.api.openflow.device.DeviceInfo;
17 import org.opendaylight.openflowplugin.api.openflow.device.MessageTranslator;
18 import org.opendaylight.openflowplugin.api.openflow.device.TranslatorLibrary;
19 import org.opendaylight.openflowplugin.api.openflow.md.core.TranslatorKey;
20 import org.opendaylight.openflowplugin.api.openflow.md.util.OpenflowVersion;
21 import org.opendaylight.openflowplugin.extension.api.path.MatchPath;
22 import org.opendaylight.openflowplugin.impl.util.GroupUtil;
23 import org.opendaylight.openflowplugin.openflow.md.core.sal.convertor.ConvertorExecutor;
24 import org.opendaylight.openflowplugin.openflow.md.core.sal.convertor.data.FlowStatsResponseConvertorData;
25 import org.opendaylight.openflowplugin.openflow.md.core.sal.convertor.data.VersionConvertorData;
26 import org.opendaylight.openflowplugin.openflow.md.core.sal.convertor.data.VersionDatapathIdConvertorData;
27 import org.opendaylight.openflowplugin.openflow.md.util.InventoryDataServiceUtil;
28 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.Counter32;
29 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.Counter64;
30 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNodeConnector;
31 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.multipart.reply.multipart.reply.body.MultipartReplyDescBuilder;
32 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.flow.and.statistics.map.list.FlowAndStatisticsMapList;
33 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.multipart.reply.multipart.reply.body.MultipartReplyFlowAggregateStats;
34 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.multipart.reply.multipart.reply.body.MultipartReplyFlowAggregateStatsBuilder;
35 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.multipart.reply.multipart.reply.body.MultipartReplyFlowStats;
36 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.multipart.reply.multipart.reply.body.MultipartReplyFlowStatsBuilder;
37 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.table.statistics.rev131215.flow.table.and.statistics.map.FlowTableAndStatisticsMapBuilder;
38 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.table.statistics.rev131215.multipart.reply.multipart.reply.body.MultipartReplyFlowTableStats;
39 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.table.statistics.rev131215.multipart.reply.multipart.reply.body.MultipartReplyFlowTableStatsBuilder;
40 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.port.rev130925.multipart.reply.multipart.reply.body.MultipartReplyPortDesc;
41 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.port.rev130925.multipart.reply.multipart.reply.body.MultipartReplyPortDescBuilder;
42 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.port.rev130925.multipart.reply.multipart.reply.body.multipart.reply.port.desc.PortsBuilder;
43 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.queue.rev130925.QueueId;
44 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.statistics.rev131111.multipart.reply.multipart.reply.body.MultipartReplyGroupDescBuilder;
45 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.statistics.rev131111.multipart.reply.multipart.reply.body.MultipartReplyGroupFeaturesBuilder;
46 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.statistics.rev131111.multipart.reply.multipart.reply.body.MultipartReplyGroupStats;
47 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.statistics.rev131111.multipart.reply.multipart.reply.body.MultipartReplyGroupStatsBuilder;
48 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.Chaining;
49 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.ChainingChecks;
50 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.GroupAll;
51 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.GroupCapability;
52 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.GroupFf;
53 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.GroupIndirect;
54 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.GroupSelect;
55 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.GroupType;
56 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.SelectLiveness;
57 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.SelectWeight;
58 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.group.desc.stats.reply.GroupDescStats;
59 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.group.statistics.reply.GroupStats;
60 import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.statistics.rev131111.multipart.reply.multipart.reply.body.MultipartReplyMeterConfigBuilder;
61 import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.statistics.rev131111.multipart.reply.multipart.reply.body.MultipartReplyMeterFeaturesBuilder;
62 import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.statistics.rev131111.multipart.reply.multipart.reply.body.MultipartReplyMeterStats;
63 import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.statistics.rev131111.multipart.reply.multipart.reply.body.MultipartReplyMeterStatsBuilder;
64 import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.types.rev130918.MeterBand;
65 import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.types.rev130918.MeterBandDrop;
66 import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.types.rev130918.MeterBandDscpRemark;
67 import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.types.rev130918.MeterBurst;
68 import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.types.rev130918.MeterCapability;
69 import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.types.rev130918.MeterKbps;
70 import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.types.rev130918.MeterPktps;
71 import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.types.rev130918.MeterStats;
72 import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.types.rev130918.meter.config.stats.reply.MeterConfigStats;
73 import org.opendaylight.yang.gen.v1.urn.opendaylight.model.statistics.types.rev130925.duration.DurationBuilder;
74 import org.opendaylight.yang.gen.v1.urn.opendaylight.model.statistics.types.rev130925.node.connector.statistics.BytesBuilder;
75 import org.opendaylight.yang.gen.v1.urn.opendaylight.model.statistics.types.rev130925.node.connector.statistics.PacketsBuilder;
76 import org.opendaylight.yang.gen.v1.urn.opendaylight.multipart.types.rev170112.multipart.reply.MultipartReplyBody;
77 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.MultipartReply;
78 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.OfHeader;
79 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.PortGrouping;
80 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.multipart.reply.multipart.reply.body.MultipartReplyAggregateCase;
81 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.multipart.reply.multipart.reply.body.MultipartReplyDescCase;
82 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.multipart.reply.multipart.reply.body.MultipartReplyFlowCase;
83 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.multipart.reply.multipart.reply.body.MultipartReplyGroupCase;
84 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.multipart.reply.multipart.reply.body.MultipartReplyGroupDescCase;
85 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.multipart.reply.multipart.reply.body.MultipartReplyGroupFeaturesCase;
86 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.multipart.reply.multipart.reply.body.MultipartReplyMeterCase;
87 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.multipart.reply.multipart.reply.body.MultipartReplyMeterConfigCase;
88 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.multipart.reply.multipart.reply.body.MultipartReplyMeterFeaturesCase;
89 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.multipart.reply.multipart.reply.body.MultipartReplyPortDescCase;
90 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.multipart.reply.multipart.reply.body.MultipartReplyPortStatsCase;
91 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.multipart.reply.multipart.reply.body.MultipartReplyQueueCase;
92 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.multipart.reply.multipart.reply.body.MultipartReplyTableCase;
93 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.multipart.reply.multipart.reply.body.MultipartReplyTableFeaturesCase;
94 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.multipart.reply.multipart.reply.body.multipart.reply.aggregate._case.MultipartReplyAggregate;
95 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.multipart.reply.multipart.reply.body.multipart.reply.desc._case.MultipartReplyDesc;
96 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.multipart.reply.multipart.reply.body.multipart.reply.group._case.MultipartReplyGroup;
97 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.multipart.reply.multipart.reply.body.multipart.reply.group.desc._case.MultipartReplyGroupDesc;
98 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.multipart.reply.multipart.reply.body.multipart.reply.group.features._case.MultipartReplyGroupFeatures;
99 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.multipart.reply.multipart.reply.body.multipart.reply.meter._case.MultipartReplyMeter;
100 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.multipart.reply.multipart.reply.body.multipart.reply.meter.config._case.MultipartReplyMeterConfig;
101 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.multipart.reply.multipart.reply.body.multipart.reply.meter.features._case.MultipartReplyMeterFeatures;
102 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.multipart.reply.multipart.reply.body.multipart.reply.port.stats._case.MultipartReplyPortStats;
103 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.multipart.reply.multipart.reply.body.multipart.reply.port.stats._case.multipart.reply.port.stats.PortStats;
104 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.multipart.reply.multipart.reply.body.multipart.reply.table.features._case.MultipartReplyTableFeatures;
105 import org.opendaylight.yang.gen.v1.urn.opendaylight.port.statistics.rev131214.multipart.reply.multipart.reply.body.MultipartReplyPortStatsBuilder;
106 import org.opendaylight.yang.gen.v1.urn.opendaylight.port.statistics.rev131214.node.connector.statistics.and.port.number.map.NodeConnectorStatisticsAndPortNumberMap;
107 import org.opendaylight.yang.gen.v1.urn.opendaylight.port.statistics.rev131214.node.connector.statistics.and.port.number.map.NodeConnectorStatisticsAndPortNumberMapBuilder;
108 import org.opendaylight.yang.gen.v1.urn.opendaylight.port.statistics.rev131214.node.connector.statistics.and.port.number.map.NodeConnectorStatisticsAndPortNumberMapKey;
109 import org.opendaylight.yang.gen.v1.urn.opendaylight.queue.statistics.rev131216.multipart.reply.multipart.reply.body.MultipartReplyQueueStats;
110 import org.opendaylight.yang.gen.v1.urn.opendaylight.queue.statistics.rev131216.multipart.reply.multipart.reply.body.MultipartReplyQueueStatsBuilder;
111 import org.opendaylight.yang.gen.v1.urn.opendaylight.queue.statistics.rev131216.queue.id.and.statistics.map.QueueIdAndStatisticsMapBuilder;
112 import org.opendaylight.yang.gen.v1.urn.opendaylight.table.types.rev131026.TableId;
113 import org.opendaylight.yang.gen.v1.urn.opendaylight.table.types.rev131026.multipart.reply.multipart.reply.body.MultipartReplyTableFeaturesBuilder;
114 import org.opendaylight.yangtools.yang.binding.util.BindingMap;
115 import org.opendaylight.yangtools.yang.common.Uint64;
116 import org.slf4j.Logger;
117 import org.slf4j.LoggerFactory;
118
119 /**
120  * Class converts multipart reply messages to the objects that can be then written to datastore using
121  * multipart writers.
122  */
123 public final class MultipartReplyTranslatorUtil {
124     private static final Logger LOG = LoggerFactory.getLogger(MultipartReplyTranslatorUtil.class);
125
126     private MultipartReplyTranslatorUtil() {
127         // Hidden on purpose
128     }
129
130     public static Optional<? extends MultipartReplyBody> translate(final OfHeader message, final DeviceInfo deviceInfo,
131             final @Nullable ConvertorExecutor convertorExecutor, final @Nullable TranslatorLibrary translatorLibrary) {
132
133         if (message instanceof MultipartReply) {
134             final MultipartReply msg = (MultipartReply) message;
135             final OpenflowVersion ofVersion = OpenflowVersion.get(deviceInfo.getVersion());
136             final VersionDatapathIdConvertorData data = new VersionDatapathIdConvertorData(deviceInfo.getVersion());
137             data.setDatapathId(deviceInfo.getDatapathId());
138
139             switch (msg.getType()) {
140                 case OFPMPFLOW:
141                     return translateFlow(msg, data, convertorExecutor);
142                 case OFPMPAGGREGATE:
143                     return Optional.of(translateAggregate(msg));
144                 case OFPMPPORTSTATS:
145                     return Optional.of(translatePortStats(msg, ofVersion, deviceInfo.getDatapathId()));
146                 case OFPMPGROUP:
147                     return translateGroup(msg, data, convertorExecutor);
148                 case OFPMPGROUPDESC:
149                     return translateGroupDesc(msg, data, convertorExecutor);
150                 case OFPMPGROUPFEATURES:
151                     return Optional.of(translateGroupFeatures(msg));
152                 case OFPMPMETER:
153                     return translateMeter(msg, data, convertorExecutor);
154                 case OFPMPMETERCONFIG:
155                     return translateMeterConfig(msg, data, convertorExecutor);
156                 case OFPMPMETERFEATURES:
157                     return Optional.of(translateMeterFeatures(msg));
158                 case OFPMPTABLE:
159                     return Optional.of(translateTable(msg));
160                 case OFPMPQUEUE:
161                     return Optional.of(translateQueue(msg, ofVersion, deviceInfo.getDatapathId()));
162                 case OFPMPDESC:
163                     return Optional.of(translateDesc(msg));
164                 case OFPMPTABLEFEATURES:
165                     return translateTableFeatures(msg, deviceInfo.getVersion(), convertorExecutor);
166                 case OFPMPPORTDESC:
167                     return translatePortDesc(msg, deviceInfo, translatorLibrary);
168                 default:
169                     // TODO: log something?
170                     break;
171             }
172         } else if (message instanceof org.opendaylight.yang.gen.v1.urn.opendaylight.multipart.types.rev170112
173             .MultipartReply) {
174             return Optional.of(((org.opendaylight.yang.gen.v1.urn.opendaylight.multipart.types.rev170112
175                 .MultipartReply) message).getMultipartReplyBody());
176         }
177
178         LOG.debug("Failed to translate {} for node {}.", message.implementedInterface(), deviceInfo);
179         return Optional.empty();
180     }
181
182     private static Optional<MultipartReplyPortDesc> translatePortDesc(final MultipartReply msg,
183             final DeviceInfo deviceInfo, final TranslatorLibrary translatorLibrary) {
184         if (translatorLibrary == null) {
185             return Optional.empty();
186         }
187
188         return Optional.of(new MultipartReplyPortDescBuilder()
189             .setPorts(((MultipartReplyPortDescCase) msg.getMultipartReplyBody())
190                 .getMultipartReplyPortDesc().nonnullPorts().stream()
191                 .map(port -> {
192                     final MessageTranslator<PortGrouping, FlowCapableNodeConnector> translator =
193                         translatorLibrary .lookupTranslator(new TranslatorKey(deviceInfo.getVersion(),
194                             PortGrouping.class.getName()));
195
196                     return new PortsBuilder(translator.translate(port, deviceInfo, null)).build();
197                 })
198                 .collect(Collectors.toList()))
199             .build());
200     }
201
202     private static Optional<org.opendaylight.yang.gen.v1.urn.opendaylight.table.types.rev131026.multipart.reply
203             .multipart.reply.body.MultipartReplyTableFeatures> translateTableFeatures(final MultipartReply msg,
204                     final short version, final ConvertorExecutor convertorExecutor) {
205         if (convertorExecutor == null) {
206             return Optional.empty();
207         }
208
209         final MultipartReplyTableFeatures multipartReplyTableFeatures =
210             ((MultipartReplyTableFeaturesCase) msg.getMultipartReplyBody()).getMultipartReplyTableFeatures();
211         final Optional<List<org.opendaylight.yang.gen.v1.urn.opendaylight.table.types.rev131026.table.features
212             .TableFeatures>> tableFeaturesList = convertorExecutor
213             .convert(multipartReplyTableFeatures, new VersionConvertorData(version));
214
215         return Optional.of(new MultipartReplyTableFeaturesBuilder()
216             .setTableFeatures(tableFeaturesList.map(BindingMap::ordered).orElse(Map.of()))
217             .build());
218     }
219
220     private static org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.multipart.reply.multipart
221             .reply.body.MultipartReplyDesc translateDesc(final MultipartReply msg) {
222         final MultipartReplyDesc desc = ((MultipartReplyDescCase) msg.getMultipartReplyBody()).getMultipartReplyDesc();
223
224         return new MultipartReplyDescBuilder()
225             .setDescription(desc.getDpDesc())
226             .setHardware(desc.getHwDesc())
227             .setManufacturer(desc.getMfrDesc())
228             .setSoftware(desc.getSwDesc())
229             .setSerialNumber(desc.getSerialNum())
230             .build();
231     }
232
233     private static Optional<MultipartReplyFlowStats> translateFlow(final MultipartReply msg,
234             final VersionDatapathIdConvertorData data, final ConvertorExecutor convertor) {
235         if (convertor == null) {
236             return Optional.empty();
237         }
238
239         final FlowStatsResponseConvertorData flowData = new FlowStatsResponseConvertorData(data.getVersion());
240         flowData.setDatapathId(data.getDatapathId());
241         flowData.setMatchPath(MatchPath.FLOWS_STATISTICS_UPDATE_MATCH);
242
243         final MultipartReplyFlowCase caseBody = (MultipartReplyFlowCase) msg.getMultipartReplyBody();
244         final Optional<List<FlowAndStatisticsMapList>> flowAndStatisticsMapLists =
245             convertor.convert(caseBody.getMultipartReplyFlow().getFlowStats(), flowData);
246
247         return Optional.of(new MultipartReplyFlowStatsBuilder()
248             .setFlowAndStatisticsMapList(flowAndStatisticsMapLists.orElse(List.of()))
249             .build());
250     }
251
252     private static MultipartReplyFlowAggregateStats translateAggregate(final MultipartReply msg) {
253         final MultipartReplyAggregate replyBody = ((MultipartReplyAggregateCase) msg.getMultipartReplyBody())
254             .getMultipartReplyAggregate();
255
256         return new MultipartReplyFlowAggregateStatsBuilder()
257             .setByteCount(new Counter64(replyBody.getByteCount()))
258             .setPacketCount(new Counter64(replyBody.getPacketCount()))
259             .setFlowCount(new Counter32(replyBody.getFlowCount()))
260             .build();
261     }
262
263     private static org.opendaylight.yang.gen.v1.urn.opendaylight.port.statistics.rev131214.multipart.reply.multipart
264             .reply.body.MultipartReplyPortStats translatePortStats(final MultipartReply msg,
265                     final OpenflowVersion ofVersion, final Uint64 datapathId) {
266         MultipartReplyPortStatsCase caseBody = (MultipartReplyPortStatsCase) msg.getMultipartReplyBody();
267         MultipartReplyPortStats replyBody = caseBody.getMultipartReplyPortStats();
268
269         final var statsMap = BindingMap.<NodeConnectorStatisticsAndPortNumberMapKey,
270             NodeConnectorStatisticsAndPortNumberMap>orderedBuilder();
271         for (PortStats portStats : replyBody.nonnullPortStats()) {
272             final DurationBuilder durationBuilder = new DurationBuilder();
273             if (portStats.getDurationSec() != null) {
274                 durationBuilder.setSecond(new Counter32(portStats.getDurationSec()));
275             }
276             if (portStats.getDurationNsec() != null) {
277                 durationBuilder.setNanosecond(new Counter32(portStats.getDurationNsec()));
278             }
279
280             statsMap.add(new NodeConnectorStatisticsAndPortNumberMapBuilder()
281                 .setNodeConnectorId(InventoryDataServiceUtil.nodeConnectorIdfromDatapathPortNo(datapathId,
282                     portStats.getPortNo(), ofVersion))
283                 .setBytes(new BytesBuilder()
284                     .setReceived(portStats.getRxBytes())
285                     .setTransmitted(portStats.getTxBytes())
286                     .build())
287                 .setPackets(new PacketsBuilder()
288                     .setReceived(portStats.getRxPackets())
289                     .setTransmitted(portStats.getTxPackets())
290                     .build())
291                 .setDuration(durationBuilder.build())
292                 .setCollisionCount(portStats.getCollisions())
293                 .setReceiveCrcError(portStats.getRxCrcErr())
294                 .setReceiveDrops(portStats.getRxDropped())
295                 .setReceiveErrors(portStats.getRxErrors())
296                 .setReceiveFrameError(portStats.getRxFrameErr())
297                 .setReceiveOverRunError(portStats.getRxOverErr())
298                 .setTransmitDrops(portStats.getTxDropped())
299                 .setTransmitErrors(portStats.getTxErrors())
300                 .build());
301         }
302
303         return new MultipartReplyPortStatsBuilder()
304             .setNodeConnectorStatisticsAndPortNumberMap(statsMap.build())
305             .build();
306     }
307
308     private static Optional<MultipartReplyGroupStats> translateGroup(final MultipartReply msg,
309             final VersionDatapathIdConvertorData data, final ConvertorExecutor convertorExecutor) {
310         if (convertorExecutor == null) {
311             return Optional.empty();
312         }
313
314         final MultipartReplyGroup replyBody = ((MultipartReplyGroupCase) msg.getMultipartReplyBody())
315             .getMultipartReplyGroup();
316         final Optional<List<GroupStats>> groupStatsList = convertorExecutor.convert(
317             replyBody.getGroupStats(), data);
318
319         return Optional.of(new MultipartReplyGroupStatsBuilder()
320             .setGroupStats(groupStatsList.map(BindingMap::ordered).orElse(Map.of()))
321             .build());
322     }
323
324     private static Optional<org.opendaylight.yang.gen.v1.urn.opendaylight.group.statistics.rev131111.multipart.reply
325             .multipart.reply.body.MultipartReplyGroupDesc> translateGroupDesc(final MultipartReply msg,
326                     final VersionDatapathIdConvertorData data, final ConvertorExecutor convertorExecutor) {
327         if (convertorExecutor == null) {
328             return Optional.empty();
329         }
330
331         MultipartReplyGroupDescCase caseBody = (MultipartReplyGroupDescCase) msg.getMultipartReplyBody();
332         MultipartReplyGroupDesc replyBody = caseBody.getMultipartReplyGroupDesc();
333
334         final Optional<List<GroupDescStats>> groupDescStatsList = convertorExecutor.convert(
335             replyBody.getGroupDesc(), data);
336
337         return Optional.of(new MultipartReplyGroupDescBuilder()
338             .setGroupDescStats(groupDescStatsList.map(BindingMap::ordered).orElse(Map.of()))
339             .build());
340     }
341
342     private static org.opendaylight.yang.gen.v1.urn.opendaylight.group.statistics.rev131111.multipart.reply.multipart
343             .reply.body.MultipartReplyGroupFeatures translateGroupFeatures(final MultipartReply msg) {
344         final MultipartReplyGroupFeatures replyBody = ((MultipartReplyGroupFeaturesCase) msg.getMultipartReplyBody())
345             .getMultipartReplyGroupFeatures();
346         final List<Class<? extends GroupType>> supportedGroups = new ArrayList<>();
347         if (replyBody.getTypes().getOFPGTALL()) {
348             supportedGroups.add(GroupAll.class);
349         }
350         if (replyBody.getTypes().getOFPGTSELECT()) {
351             supportedGroups.add(GroupSelect.class);
352         }
353         if (replyBody.getTypes().getOFPGTINDIRECT()) {
354             supportedGroups.add(GroupIndirect.class);
355         }
356         if (replyBody.getTypes().getOFPGTFF()) {
357             supportedGroups.add(GroupFf.class);
358         }
359
360         List<Class<? extends GroupCapability>> supportedCapabilities = new ArrayList<>();
361         if (replyBody.getCapabilities().getOFPGFCCHAINING()) {
362             supportedCapabilities.add(Chaining.class);
363         }
364         if (replyBody.getCapabilities().getOFPGFCCHAININGCHECKS()) {
365             supportedCapabilities.add(ChainingChecks.class);
366         }
367         if (replyBody.getCapabilities().getOFPGFCSELECTLIVENESS()) {
368             supportedCapabilities.add(SelectLiveness.class);
369         }
370         if (replyBody.getCapabilities().getOFPGFCSELECTWEIGHT()) {
371             supportedCapabilities.add(SelectWeight.class);
372         }
373
374         return new MultipartReplyGroupFeaturesBuilder()
375             .setGroupTypesSupported(supportedGroups)
376             .setMaxGroups(replyBody.getMaxGroups())
377             .setGroupCapabilitiesSupported(supportedCapabilities)
378             .setActions(GroupUtil.extractGroupActionsSupportBitmap(replyBody.getActionsBitmap()))
379             .build();
380     }
381
382     private static Optional<MultipartReplyMeterStats> translateMeter(final MultipartReply msg,
383             final VersionDatapathIdConvertorData data, final ConvertorExecutor convertorExecutor) {
384         if (convertorExecutor == null) {
385             return Optional.empty();
386         }
387
388         final MultipartReplyMeter replyBody = ((MultipartReplyMeterCase) msg.getMultipartReplyBody())
389             .getMultipartReplyMeter();
390         final Optional<List<
391             org.opendaylight.yang.gen.v1.urn.opendaylight.meter.types.rev130918.meter.statistics.reply.MeterStats>>
392                 meterStatsList = convertorExecutor.convert(replyBody.getMeterStats(), data);
393
394         return Optional.of(new MultipartReplyMeterStatsBuilder()
395             .setMeterStats(meterStatsList.map(BindingMap::ordered).orElse(Map.of()))
396             .build());
397     }
398
399     private static Optional<org.opendaylight.yang.gen.v1.urn.opendaylight.meter.statistics.rev131111.multipart.reply
400             .multipart.reply.body.MultipartReplyMeterConfig> translateMeterConfig(final MultipartReply msg,
401                     final VersionDatapathIdConvertorData data, final ConvertorExecutor convertorExecutor) {
402         if (convertorExecutor == null) {
403             return Optional.empty();
404         }
405
406         MultipartReplyMeterConfigCase caseBody = (MultipartReplyMeterConfigCase) msg.getMultipartReplyBody();
407         MultipartReplyMeterConfig replyBody = caseBody.getMultipartReplyMeterConfig();
408         final Optional<List<MeterConfigStats>> meterConfigStatsList
409                 = convertorExecutor.convert(replyBody.getMeterConfig(), data);
410
411         return Optional.of(new MultipartReplyMeterConfigBuilder()
412             .setMeterConfigStats(meterConfigStatsList.map(BindingMap::ordered).orElse(Map.of()))
413             .build());
414     }
415
416     private static org.opendaylight.yang.gen.v1.urn.opendaylight.meter.statistics.rev131111.multipart.reply.multipart
417             .reply.body.MultipartReplyMeterFeatures translateMeterFeatures(final MultipartReply msg) {
418         MultipartReplyMeterFeaturesCase caseBody = (MultipartReplyMeterFeaturesCase) msg.getMultipartReplyBody();
419         MultipartReplyMeterFeatures replyBody = caseBody.getMultipartReplyMeterFeatures();
420
421         final List<Class<? extends MeterCapability>> supportedCapabilities = new ArrayList<>();
422         if (replyBody.getCapabilities().getOFPMFBURST()) {
423             supportedCapabilities.add(MeterBurst.class);
424         }
425         if (replyBody.getCapabilities().getOFPMFKBPS()) {
426             supportedCapabilities.add(MeterKbps.class);
427         }
428         if (replyBody.getCapabilities().getOFPMFPKTPS()) {
429             supportedCapabilities.add(MeterPktps.class);
430         }
431         if (replyBody.getCapabilities().getOFPMFSTATS()) {
432             supportedCapabilities.add(MeterStats.class);
433         }
434
435         final List<Class<? extends MeterBand>> supportedMeterBand = new ArrayList<>();
436         if (replyBody.getBandTypes().getOFPMBTDROP()) {
437             supportedMeterBand.add(MeterBandDrop.class);
438         }
439         if (replyBody.getBandTypes().getOFPMBTDSCPREMARK()) {
440             supportedMeterBand.add(MeterBandDscpRemark.class);
441         }
442
443         return new MultipartReplyMeterFeaturesBuilder()
444             .setMaxBands(replyBody.getMaxBands())
445             .setMaxColor(replyBody.getMaxColor())
446             .setMaxMeter(new Counter32(replyBody.getMaxMeter()))
447             .setMeterCapabilitiesSupported(supportedCapabilities)
448             .setMeterBandSupported(supportedMeterBand)
449             .build();
450     }
451
452     private static MultipartReplyFlowTableStats translateTable(final MultipartReply msg) {
453         final var salFlowStats = ((MultipartReplyTableCase) msg.getMultipartReplyBody()).getMultipartReplyTable()
454             .nonnullTableStats().stream()
455             //TODO: Duplicate code: look at OpendaylightFlowTableStatisticsServiceImpl method transformToNotification
456             .map(swTableStats -> new FlowTableAndStatisticsMapBuilder()
457                 .setActiveFlows(new Counter32(swTableStats.getActiveCount()))
458                 .setPacketsLookedUp(new Counter64(swTableStats.getLookupCount()))
459                 .setPacketsMatched(new Counter64(swTableStats.getMatchedCount()))
460                 .setTableId(new TableId(swTableStats.getTableId()))
461                 .build())
462             .collect(BindingMap.toOrderedMap());
463
464         return new MultipartReplyFlowTableStatsBuilder()
465             .setFlowTableAndStatisticsMap(salFlowStats)
466             .build();
467     }
468
469     private static MultipartReplyQueueStats translateQueue(final MultipartReply msg,
470                                                            final OpenflowVersion ofVersion,
471                                                            final Uint64 datapathId) {
472         final var statsMap = ((MultipartReplyQueueCase) msg.getMultipartReplyBody()).getMultipartReplyQueue()
473             .nonnullQueueStats().stream()
474             .map(queueStats -> new QueueIdAndStatisticsMapBuilder()
475                 .setNodeConnectorId(InventoryDataServiceUtil.nodeConnectorIdfromDatapathPortNo(datapathId,
476                     queueStats.getPortNo(), ofVersion))
477                 .setQueueId(new QueueId(queueStats.getQueueId()))
478                 .setTransmissionErrors(new Counter64(queueStats.getTxErrors()))
479                 .setTransmittedBytes(new Counter64(queueStats.getTxBytes()))
480                 .setTransmittedPackets(new Counter64(queueStats.getTxPackets()))
481                 .setDuration(new DurationBuilder()
482                     .setSecond(new Counter32(queueStats.getDurationSec()))
483                     .setNanosecond(new Counter32(queueStats.getDurationNsec()))
484                     .build())
485                 .build())
486             .collect(BindingMap.toOrderedMap());
487
488         return new MultipartReplyQueueStatsBuilder()
489             .setQueueIdAndStatisticsMap(statsMap)
490             .build();
491     }
492 }