BUG-64 : refactor BGP parser to use ByteBuf
[bgpcep.git] / bgp / parser-spi / src / main / java / org / opendaylight / protocol / bgp / parser / spi / AbstractMessageRegistry.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.spi;
9
10 import io.netty.buffer.ByteBuf;
11
12 import java.util.Arrays;
13
14 import org.opendaylight.protocol.bgp.parser.BGPDocumentedException;
15 import org.opendaylight.protocol.bgp.parser.BGPError;
16 import org.opendaylight.protocol.bgp.parser.BGPParsingException;
17 import org.opendaylight.protocol.util.ByteArray;
18 import org.opendaylight.yangtools.yang.binding.Notification;
19
20 import com.google.common.base.Preconditions;
21 import com.google.common.primitives.UnsignedBytes;
22
23 public abstract class AbstractMessageRegistry implements MessageRegistry {
24
25         private static final byte[] MARKER;
26
27         protected abstract Notification parseBody(final int type, final ByteBuf body, final int messageLength) throws BGPDocumentedException;
28
29         protected abstract byte[] serializeMessageImpl(final Notification message);
30
31         static {
32                 MARKER = new byte[MessageUtil.MARKER_LENGTH];
33                 Arrays.fill(MARKER, UnsignedBytes.MAX_VALUE);
34         }
35
36         @Override
37         public final Notification parseMessage(final ByteBuf buffer) throws BGPDocumentedException, BGPParsingException {
38                 Preconditions.checkArgument(buffer != null && buffer.readableBytes() != 0, "Array of bytes cannot be null or empty.");
39                 Preconditions.checkArgument(buffer.readableBytes() >= MessageUtil.COMMON_HEADER_LENGTH, "Too few bytes in passed array. Passed: %s. Expected: >= %s.", buffer.readableBytes(), MessageUtil.COMMON_HEADER_LENGTH);
40                 final byte[] marker = ByteArray.readBytes(buffer, MessageUtil.MARKER_LENGTH);
41
42                 if (!Arrays.equals(marker, MARKER)) {
43                         throw new BGPDocumentedException("Marker not set to ones.", BGPError.CONNECTION_NOT_SYNC);
44                 }
45                 final int messageLength = buffer.readUnsignedShort();
46                 // to be sent with Error message
47                 final byte typeBytes = buffer.readByte();
48                 final int messageType = UnsignedBytes.toInt(typeBytes);
49
50                 final ByteBuf msgBody = buffer.slice(buffer.readerIndex(), messageLength - MessageUtil.COMMON_HEADER_LENGTH);
51
52                 if (messageLength < MessageUtil.COMMON_HEADER_LENGTH) {
53                         throw BGPDocumentedException.badMessageLength("Message length field not within valid range.", messageLength);
54                 }
55                 if (msgBody.readableBytes() != messageLength - MessageUtil.COMMON_HEADER_LENGTH) {
56                         throw new BGPParsingException("Size doesn't match size specified in header. Passed: " + msgBody.readableBytes() + "; Expected: "
57                                         + (messageLength - MessageUtil.COMMON_HEADER_LENGTH) + ". ");
58                 }
59                 final Notification msg = parseBody(messageType, msgBody, messageLength);
60                 if (msg == null) {
61                         throw new BGPDocumentedException("Unhandled message type " + messageType, BGPError.BAD_MSG_TYPE, new byte[] { typeBytes });
62                 }
63                 buffer.skipBytes(messageLength - MessageUtil.COMMON_HEADER_LENGTH);
64                 return msg;
65         }
66
67         @Override
68         public final byte[] serializeMessage(final Notification message) {
69                 if (message == null) {
70                         throw new IllegalArgumentException("BGPMessage is mandatory.");
71                 }
72                 final byte[] ret = serializeMessageImpl(message);
73                 if (ret == null) {
74                         throw new IllegalArgumentException("Unknown instance of BGPMessage. Passed " + message.getClass());
75                 }
76                 return ret;
77         }
78 }