BUG-45 : migrated Keepalive message to generated source code.
[bgpcep.git] / bgp / parser-impl / src / main / java / org / opendaylight / protocol / bgp / parser / impl / BGPMessageFactoryImpl.java
1 /*
2  * Copyright (c) 2013 Cisco Systems, 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.protocol.bgp.parser.impl;
9
10 import java.util.Arrays;
11 import java.util.List;
12
13 import org.opendaylight.protocol.bgp.parser.BGPDocumentedException;
14 import org.opendaylight.protocol.bgp.parser.BGPError;
15 import org.opendaylight.protocol.bgp.parser.BGPMessageFactory;
16 import org.opendaylight.protocol.bgp.parser.impl.message.BGPNotificationMessageParser;
17 import org.opendaylight.protocol.bgp.parser.impl.message.BGPOpenMessageParser;
18 import org.opendaylight.protocol.bgp.parser.impl.message.BGPUpdateMessageParser;
19 import org.opendaylight.protocol.bgp.parser.message.BGPNotificationMessage;
20 import org.opendaylight.protocol.bgp.parser.message.BGPOpenMessage;
21 import org.opendaylight.protocol.framework.DeserializerException;
22 import org.opendaylight.protocol.framework.DocumentedException;
23 import org.opendaylight.protocol.util.ByteArray;
24 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.message.rev130918.Keepalive;
25 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.message.rev130918.KeepaliveBuilder;
26 import org.opendaylight.yangtools.yang.binding.Notification;
27 import org.slf4j.Logger;
28 import org.slf4j.LoggerFactory;
29
30 import com.google.common.collect.Lists;
31 import com.google.common.primitives.UnsignedBytes;
32
33 /**
34  * The byte array
35  */
36 public final class BGPMessageFactoryImpl implements BGPMessageFactory {
37
38         private final static Logger logger = LoggerFactory.getLogger(BGPMessageFactoryImpl.class);
39
40         final static int LENGTH_FIELD_LENGTH = 2; // bytes
41
42         private final static int TYPE_FIELD_LENGTH = 1; // bytes
43
44         final static int MARKER_LENGTH = 16; // bytes
45
46         public final static int COMMON_HEADER_LENGTH = LENGTH_FIELD_LENGTH + TYPE_FIELD_LENGTH + MARKER_LENGTH;
47
48         /*
49          * (non-Javadoc)
50          * @see org.opendaylight.protocol.bgp.parser.BGPMessageParser#parse(byte[])
51          */
52         @Override
53         public List<Notification> parse(final byte[] bytes) throws DeserializerException, DocumentedException {
54                 if (bytes == null) {
55                         throw new IllegalArgumentException("Array of bytes is mandatory.");
56                 }
57                 if (bytes.length < COMMON_HEADER_LENGTH) {
58                         throw new IllegalArgumentException("Too few bytes in passed array. Passed: " + bytes.length + ". Expected: >= "
59                                         + COMMON_HEADER_LENGTH + ".");
60                 }
61                 /*
62                  * byte array starts with message length
63                  */
64                 // final byte[] ones = new byte[MARKER_LENGTH];
65                 // Arrays.fill(ones, (byte)0xff);
66                 // if (Arrays.equals(bytes, ones))
67                 // throw new BGPDocumentedException("Marker not set to ones.", BGPError.CONNECTION_NOT_SYNC);
68                 final byte[] bs = ByteArray.cutBytes(bytes, MARKER_LENGTH);
69                 final int messageLength = ByteArray.bytesToInt(ByteArray.subByte(bs, 0, LENGTH_FIELD_LENGTH));
70                 final int messageType = UnsignedBytes.toInt(bs[LENGTH_FIELD_LENGTH]);
71
72                 final byte[] msgBody = ByteArray.cutBytes(bs, LENGTH_FIELD_LENGTH + TYPE_FIELD_LENGTH);
73
74                 if (messageLength < COMMON_HEADER_LENGTH) {
75                         throw new BGPDocumentedException("Message length field not within valid range.", BGPError.BAD_MSG_LENGTH, ByteArray.subByte(bs,
76                                         0, LENGTH_FIELD_LENGTH));
77                 }
78                 if (msgBody.length != messageLength - COMMON_HEADER_LENGTH) {
79                         throw new DeserializerException("Size doesn't match size specified in header. Passed: " + msgBody.length + "; Expected: "
80                                         + (messageLength - COMMON_HEADER_LENGTH) + ". ");
81                 }
82
83                 logger.debug("Attempt to parse message from bytes: {}", ByteArray.bytesToHexString(msgBody));
84
85                 final Notification msg;
86
87                 switch (messageType) {
88                 case 1:
89                         msg = BGPOpenMessageParser.parse(msgBody);
90                         logger.debug("Received and parsed Open Message: {}", msg);
91                         break;
92                 case 2:
93                         msg = BGPUpdateMessageParser.parse(msgBody, messageLength);
94                         logger.debug("Received and parsed Update Message: {}", msg);
95                         break;
96                 case 3:
97                         msg = BGPNotificationMessageParser.parse(msgBody);
98                         logger.debug("Received and parsed Notification Message: {}", msg);
99                         break;
100                 case 4:
101                         msg = new KeepaliveBuilder().build();
102                         if (messageLength != COMMON_HEADER_LENGTH) {
103                                 throw new BGPDocumentedException("Message length field not within valid range.", BGPError.BAD_MSG_LENGTH, ByteArray.subByte(
104                                                 bs, 0, LENGTH_FIELD_LENGTH));
105                         }
106                         break;
107                 default:
108                         throw new BGPDocumentedException("Unhandled message type " + messageType, BGPError.BAD_MSG_TYPE, new byte[] { bs[LENGTH_FIELD_LENGTH] });
109                 }
110
111                 return Lists.newArrayList(msg);
112         }
113
114         @Override
115         public byte[] put(final Notification msg) {
116                 if (msg == null) {
117                         throw new IllegalArgumentException("BGPMessage is mandatory.");
118                 }
119
120                 logger.trace("Serializing {}", msg);
121
122                 byte[] msgBody = null;
123                 int msgType = 0;
124
125                 /*
126                  * Update message is not supported
127                  */
128                 if (msg instanceof BGPOpenMessage) {
129                         msgType = 1;
130                         msgBody = BGPOpenMessageParser.put((BGPOpenMessage) msg);
131                 } else if (msg instanceof BGPNotificationMessage) {
132                         msgType = 3;
133                         msgBody = BGPNotificationMessageParser.put((BGPNotificationMessage) msg);
134                 } else if (msg instanceof Keepalive) {
135                         msgType = 4;
136                         msgBody = new byte[0];
137                 } else {
138                         throw new IllegalArgumentException("Unknown instance of BGPMessage. Passed " + msg.getClass());
139                 }
140
141                 final byte[] headerBytes = headerToBytes(msgBody.length + COMMON_HEADER_LENGTH, msgType);
142                 final byte[] retBytes = new byte[headerBytes.length + msgBody.length];
143
144                 ByteArray.copyWhole(headerBytes, retBytes, 0);
145                 ByteArray.copyWhole(msgBody, retBytes, COMMON_HEADER_LENGTH);
146
147                 logger.trace("Serialized BGP message {}.", Arrays.toString(retBytes));
148                 return retBytes;
149         }
150
151         /**
152          * Serializes this BGP Message header to byte array.
153          * 
154          * @return byte array representation of this header
155          */
156         public byte[] headerToBytes(final int msgLength, final int msgType) {
157                 final byte[] retBytes = new byte[COMMON_HEADER_LENGTH];
158
159                 Arrays.fill(retBytes, 0, MARKER_LENGTH, (byte) 0xff);
160
161                 System.arraycopy(ByteArray.intToBytes(msgLength), Integer.SIZE / Byte.SIZE - LENGTH_FIELD_LENGTH, retBytes, MARKER_LENGTH,
162                                 LENGTH_FIELD_LENGTH);
163
164                 retBytes[MARKER_LENGTH + LENGTH_FIELD_LENGTH] = (byte) msgType;
165
166                 return retBytes;
167         }
168 }