Add missing list keys where necessary
[lispflowmapping.git] / mappingservice / lisp-proto / src / main / java / org / opendaylight / lispflowmapping / lisp / serializer / MapNotifySerializer.java
1 /*
2  * Copyright (c) 2014 Contextream, Inc. 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.lispflowmapping.lisp.serializer;
9
10 import java.nio.ByteBuffer;
11 import java.util.ArrayList;
12 import java.util.List;
13 import org.apache.commons.lang3.BooleanUtils;
14 import org.opendaylight.lispflowmapping.lisp.serializer.exception.LispSerializationException;
15 import org.opendaylight.lispflowmapping.lisp.util.ByteUtil;
16 import org.opendaylight.lispflowmapping.lisp.util.NumberUtil;
17 import org.opendaylight.yang.gen.v1.urn.opendaylight.lfm.lisp.proto.rev151105.MapNotify;
18 import org.opendaylight.yang.gen.v1.urn.opendaylight.lfm.lisp.proto.rev151105.MessageType;
19 import org.opendaylight.yang.gen.v1.urn.opendaylight.lfm.lisp.proto.rev151105.SiteId;
20 import org.opendaylight.yang.gen.v1.urn.opendaylight.lfm.lisp.proto.rev151105.XtrId;
21 import org.opendaylight.yang.gen.v1.urn.opendaylight.lfm.lisp.proto.rev151105.mapnotifymessage.MapNotifyBuilder;
22 import org.opendaylight.yang.gen.v1.urn.opendaylight.lfm.lisp.proto.rev151105.mapping.record.container.MappingRecordBuilder;
23 import org.opendaylight.yang.gen.v1.urn.opendaylight.lfm.lisp.proto.rev151105.mapping.record.list.MappingRecordItem;
24 import org.opendaylight.yang.gen.v1.urn.opendaylight.lfm.lisp.proto.rev151105.mapping.record.list.MappingRecordItemBuilder;
25 import org.opendaylight.yang.gen.v1.urn.opendaylight.lfm.lisp.proto.rev151105.mapping.record.list.MappingRecordItemKey;
26
27 /**
28  * This class deals with serializing map notify from the java object to udp.
29  */
30 public final class MapNotifySerializer {
31
32     private static final MapNotifySerializer INSTANCE = new MapNotifySerializer();
33
34     // Private constructor prevents instantiation from other classes
35     private MapNotifySerializer() {
36     }
37
38     public static MapNotifySerializer getInstance() {
39         return INSTANCE;
40     }
41
42     public ByteBuffer serialize(MapNotify mapNotify) {
43         int size = Length.HEADER_SIZE;
44         if (mapNotify.getAuthenticationData() != null) {
45             size += mapNotify.getAuthenticationData().length;
46         }
47         if (mapNotify.isXtrSiteIdPresent() != null && mapNotify.isXtrSiteIdPresent()) {
48             size += org.opendaylight.lispflowmapping.lisp.serializer.MapRegisterSerializer.Length.XTRID_SIZE
49                   + org.opendaylight.lispflowmapping.lisp.serializer.MapRegisterSerializer.Length.SITEID_SIZE;
50         }
51         for (MappingRecordItem mappingRecord : mapNotify.getMappingRecordItem()) {
52             size += MappingRecordSerializer.getInstance().getSerializationSize(mappingRecord.getMappingRecord());
53         }
54
55         ByteBuffer replyBuffer = ByteBuffer.allocate(size);
56         replyBuffer.put((byte) ((byte) (MessageType.MapNotify.getIntValue() << 4)
57                 | ByteUtil.boolToBit(BooleanUtils.isTrue(mapNotify.isXtrSiteIdPresent()), Flags.XTRSITEID)));
58         replyBuffer.position(replyBuffer.position() + Length.RES);
59         replyBuffer.put(ByteUtil.boolToBit(BooleanUtils.isTrue(mapNotify.isMergeEnabled()), Flags.MERGE_ENABLED));
60         if (mapNotify.getMappingRecordItem() != null) {
61             replyBuffer.put((byte) mapNotify.getMappingRecordItem().size());
62         } else {
63             replyBuffer.put((byte) 0);
64         }
65         replyBuffer.putLong(NumberUtil.asLong(mapNotify.getNonce()));
66         replyBuffer.putShort(NumberUtil.asShort(mapNotify.getKeyId()));
67         if (mapNotify.getAuthenticationData() != null) {
68             replyBuffer.putShort((short) mapNotify.getAuthenticationData().length);
69             replyBuffer.put(mapNotify.getAuthenticationData());
70         } else {
71             replyBuffer.putShort((short) 0);
72         }
73
74         if (mapNotify.getMappingRecordItem() != null) {
75             for (MappingRecordItem mappingRecord : mapNotify.getMappingRecordItem()) {
76                 MappingRecordSerializer.getInstance().serialize(replyBuffer, mappingRecord.getMappingRecord());
77             }
78         }
79
80         if (mapNotify.isXtrSiteIdPresent() != null && mapNotify.isXtrSiteIdPresent()) {
81             replyBuffer.put(mapNotify.getXtrId().getValue());
82             replyBuffer.put(mapNotify.getSiteId().getValue());
83         }
84         replyBuffer.clear();
85         return replyBuffer;
86     }
87
88     @SuppressWarnings("checkstyle:IllegalCatch")
89     public MapNotify deserialize(ByteBuffer notifyBuffer) {
90         try {
91             final byte typeAndFlags = notifyBuffer.get();
92             final int type = typeAndFlags >> 4;
93             if (MessageType.forValue(type) != MessageType.MapNotify) {
94                 throw new LispSerializationException("Expected Map-Notify packet (type 4), but was type " + type);
95             }
96
97             MapNotifyBuilder builder = new MapNotifyBuilder();
98             builder.setMappingRecordItem(new ArrayList<MappingRecordItem>());
99
100             boolean xtrSiteIdPresent = ByteUtil.extractBit(typeAndFlags, Flags.XTRSITEID);
101             builder.setXtrSiteIdPresent(xtrSiteIdPresent);
102
103             notifyBuffer.position(notifyBuffer.position() + Length.RES);
104             builder.setMergeEnabled(ByteUtil.extractBit(notifyBuffer.get(), Flags.MERGE_ENABLED));
105
106             byte recordCount = (byte) ByteUtil.getUnsignedByte(notifyBuffer);
107             builder.setNonce(notifyBuffer.getLong());
108             builder.setKeyId(notifyBuffer.getShort());
109             short authenticationLength = notifyBuffer.getShort();
110             byte[] authenticationData = new byte[authenticationLength];
111             notifyBuffer.get(authenticationData);
112             builder.setAuthenticationData(authenticationData);
113
114             if (xtrSiteIdPresent) {
115                 List<MappingRecordBuilder> mrbs = new ArrayList<MappingRecordBuilder>();
116                 for (int i = 0; i < recordCount; i++) {
117                     mrbs.add(MappingRecordSerializer.getInstance().deserializeToBuilder(notifyBuffer));
118                 }
119                 byte[] xtrIdBuf  = new byte[MapRegisterSerializer.Length.XTRID_SIZE];
120                 notifyBuffer.get(xtrIdBuf);
121                 XtrId xtrId = new XtrId(xtrIdBuf);
122                 byte[] siteIdBuf = new byte[MapRegisterSerializer.Length.SITEID_SIZE];
123                 notifyBuffer.get(siteIdBuf);
124                 SiteId siteId = new SiteId(siteIdBuf);
125                 builder.setXtrId(xtrId);
126                 builder.setSiteId(siteId);
127                 int idx = 0;
128                 for (MappingRecordBuilder mrb : mrbs) {
129                     mrb.setXtrId(xtrId);
130                     mrb.setSiteId(siteId);
131                     builder.getMappingRecordItem().add(new MappingRecordItemBuilder()
132                             .withKey(new MappingRecordItemKey(Integer.toString(idx)))
133                             .setMappingRecord(mrb.build()).build());
134                     idx++;
135                 }
136             } else {
137                 for (int i = 0; i < recordCount; i++) {
138                     builder.getMappingRecordItem().add(new MappingRecordItemBuilder()
139                             .withKey(new MappingRecordItemKey(Integer.toString(i)))
140                             .setMappingRecord(MappingRecordSerializer.getInstance().deserialize(notifyBuffer))
141                             .build());
142                 }
143             }
144
145             notifyBuffer.limit(notifyBuffer.position());
146             return builder.build();
147         } catch (RuntimeException re) {
148             throw new LispSerializationException("Couldn't deserialize Map-Notify (len="
149                     + notifyBuffer.capacity() + ")", re);
150         }
151     }
152
153     private interface Flags {
154         byte XTRSITEID = 0x08;
155         byte MERGE_ENABLED = 0x04;
156     }
157
158     private interface Length {
159         int HEADER_SIZE = 16;
160         int RES = 1;
161     }
162
163 }