Fix checkstyle warnings for impl/protocol package
[openflowplugin.git] / openflowplugin-impl / src / main / java / org / opendaylight / openflowplugin / impl / protocol / serialization / match / MatchSerializer.java
1 /*
2  * Copyright (c) 2016 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
9 package org.opendaylight.openflowplugin.impl.protocol.serialization.match;
10
11 import io.netty.buffer.ByteBuf;
12 import java.util.LinkedHashMap;
13 import java.util.List;
14 import java.util.Map;
15 import java.util.Objects;
16 import java.util.Optional;
17 import org.opendaylight.openflowjava.protocol.api.extensibility.HeaderSerializer;
18 import org.opendaylight.openflowjava.protocol.api.extensibility.OFSerializer;
19 import org.opendaylight.openflowjava.protocol.api.extensibility.SerializerRegistry;
20 import org.opendaylight.openflowjava.protocol.api.extensibility.SerializerRegistryInjector;
21 import org.opendaylight.openflowjava.protocol.api.keys.MatchEntrySerializerKey;
22 import org.opendaylight.openflowjava.protocol.api.util.EncodeConstants;
23 import org.opendaylight.openflowplugin.api.OFConstants;
24 import org.opendaylight.openflowplugin.api.openflow.protocol.serialization.MatchEntrySerializer;
25 import org.opendaylight.openflowplugin.api.openflow.protocol.serialization.MatchEntrySerializerRegistry;
26 import org.opendaylight.openflowplugin.extension.api.ConverterExtensionKey;
27 import org.opendaylight.openflowplugin.openflow.md.core.extension.ExtensionResolvers;
28 import org.opendaylight.openflowplugin.openflow.md.core.session.OFSessionUtil;
29 import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.Match;
30 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.augments.rev150225.oxm.container.match.entry.value.ExperimenterIdCase;
31 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.oxm.rev150225.ExperimenterClass;
32 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.oxm.rev150225.match.entries.grouping.MatchEntry;
33 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.general.rev140714.ExtensionKey;
34 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.general.rev140714.general.extension.list.grouping.ExtensionList;
35 import org.slf4j.Logger;
36 import org.slf4j.LoggerFactory;
37
38 public class MatchSerializer implements OFSerializer<Match>, HeaderSerializer<Match>,
39         MatchEntrySerializerRegistry, SerializerRegistryInjector {
40
41     private static final Logger LOG = LoggerFactory.getLogger(MatchSerializer.class);
42     private static final byte OXM_MATCH_TYPE_CODE = 1;
43     private final Map<org.opendaylight.openflowplugin.api.openflow.protocol.serialization.MatchEntrySerializerKey,
44             MatchEntrySerializer> entryRegistry = new LinkedHashMap<>();
45     private SerializerRegistry registry;
46
47     @Override
48     public void serialize(Match match, ByteBuf outBuffer) {
49         // Save start index in buffer
50         final int matchStartIndex = outBuffer.writerIndex();
51
52         // With OpenflowPlugin models, we cannot check difference between OXM and Standard match type
53         // so all matches will be OXM
54         outBuffer.writeShort(OXM_MATCH_TYPE_CODE);
55
56         // Save length of match type
57         int matchLengthIndex = outBuffer.writerIndex();
58         outBuffer.writeShort(EncodeConstants.EMPTY_LENGTH);
59
60         // Small hack to be able to serialize only match entryRegistry externally
61         serializeHeader(match, outBuffer);
62
63         // Length of ofp_match (excluding padding)
64         int matchLength = outBuffer.writerIndex() - matchStartIndex;
65         outBuffer.setShort(matchLengthIndex, matchLength);
66
67         // If we have any remaining padding, write it at end
68         int paddingRemainder = matchLength % EncodeConstants.PADDING;
69         if (paddingRemainder != 0) {
70             outBuffer.writeZero(EncodeConstants.PADDING - paddingRemainder);
71         }
72     }
73
74     @Override
75     public void serializeHeader(Match match, ByteBuf outBuffer) {
76         if (match == null) {
77             LOG.debug("Match is null, skipping serialization of match entries");
78             return;
79         }
80
81         // Serialize match entries
82         entryRegistry.forEach((key, value) -> {
83             if (value.matchTypeCheck(match)) {
84                 value.serialize(match, outBuffer);
85             }
86         });
87
88         // Serialize match extensions
89         ExtensionResolvers
90                 .getMatchExtensionResolver()
91                 .getExtension(match)
92                 .flatMap(extensions -> Optional.ofNullable(extensions.getExtensionList()))
93                 .ifPresent(extensionList -> serializeExtensionList(extensionList, outBuffer));
94     }
95
96     private void serializeExtensionList(final List<ExtensionList> extensionList, final ByteBuf outBuffer) {
97         // TODO: Remove also extension converters
98         extensionList.forEach(extension -> {
99             final ConverterExtensionKey<? extends ExtensionKey> converterExtensionKey =
100                     new ConverterExtensionKey<>(extension.getExtensionKey(), OFConstants.OFP_VERSION_1_3);
101
102             Optional.ofNullable(OFSessionUtil.getExtensionConvertorProvider())
103                     .flatMap(provider -> Optional.ofNullable(provider.<MatchEntry>getConverter(converterExtensionKey)))
104                     .map(matchEntryConvertorToOFJava -> {
105                         final MatchEntry entry = matchEntryConvertorToOFJava.convert(extension.getExtension());
106
107                         final MatchEntrySerializerKey<?, ?> key = new MatchEntrySerializerKey<>(
108                                 EncodeConstants.OF13_VERSION_ID, entry.getOxmClass(), entry.getOxmMatchField());
109
110                         // If entry is experimenter, set experimenter ID to key
111                         if (entry.getOxmClass().equals(ExperimenterClass.class)) {
112                             key.setExperimenterId(ExperimenterIdCase.class.cast(entry.getMatchEntryValue())
113                                     .getExperimenter().getExperimenter().getValue());
114                         }
115
116                         final OFSerializer<MatchEntry> entrySerializer = registry.getSerializer(key);
117                         entrySerializer.serialize(entry, outBuffer);
118                         return entry;
119                     })
120                     .orElseGet(() -> {
121                         LOG.warn("Serializer for match entry {} for version {} not found.",
122                                 extension.getExtension().getImplementedInterface(),
123                                 OFConstants.OFP_VERSION_1_3);
124                         return null;
125                     });
126         });
127     }
128
129     @Override
130     public void injectSerializerRegistry(SerializerRegistry serializerRegistry) {
131         registry = serializerRegistry;
132     }
133
134     @Override
135     public void registerEntrySerializer(org.opendaylight.openflowplugin.api.openflow.protocol.serialization
136                                                     .MatchEntrySerializerKey key, MatchEntrySerializer serializer) {
137         if (Objects.isNull(key) || Objects.isNull(serializer)) {
138             throw new IllegalArgumentException("MatchEntrySerializerKey or Serializer is null");
139         }
140
141         final MatchEntrySerializer seInRegistry = entryRegistry.put(key, serializer);
142         if (seInRegistry != null) {
143             LOG.debug("Serializer for key {} overwritten. Old serializer: {}, new serializer: {}", key,
144                     seInRegistry.getClass().getName(), serializer.getClass().getName());
145         }
146     }
147
148     @Override
149     public boolean unregisterEntrySerializer(org.opendaylight.openflowplugin.api.openflow.protocol.serialization
150                                                          .MatchEntrySerializerKey key) {
151         return Objects.nonNull(entryRegistry.remove(key));
152     }
153 }