d59a1db4da9a0374eb8982116cd36c613ead8949
[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.spi.MessageParser;
17 import org.opendaylight.protocol.bgp.parser.spi.MessageRegistry;
18 import org.opendaylight.protocol.bgp.parser.spi.MessageSerializer;
19 import org.opendaylight.protocol.framework.DeserializerException;
20 import org.opendaylight.protocol.framework.DocumentedException;
21 import org.opendaylight.protocol.util.ByteArray;
22 import org.opendaylight.yangtools.yang.binding.Notification;
23 import org.slf4j.Logger;
24 import org.slf4j.LoggerFactory;
25
26 import com.google.common.base.Preconditions;
27 import com.google.common.collect.Lists;
28 import com.google.common.primitives.UnsignedBytes;
29
30 /**
31  * The byte array
32  */
33 public final class BGPMessageFactoryImpl implements BGPMessageFactory {
34         public static final BGPMessageFactory INSTANCE = new BGPMessageFactoryImpl(MessageRegistryImpl.INSTANCE);
35
36         private final static Logger logger = LoggerFactory.getLogger(BGPMessageFactoryImpl.class);
37
38         public final static int LENGTH_FIELD_LENGTH = 2; // bytes
39
40         private final static int TYPE_FIELD_LENGTH = 1; // bytes
41
42         final static int MARKER_LENGTH = 16; // bytes
43
44         public final static int COMMON_HEADER_LENGTH = LENGTH_FIELD_LENGTH + TYPE_FIELD_LENGTH + MARKER_LENGTH;
45
46         private final MessageRegistry registry;
47
48         private BGPMessageFactoryImpl(final MessageRegistry registry) {
49                 this.registry = Preconditions.checkNotNull(registry);
50         }
51
52         /*
53          * (non-Javadoc)
54          * @see org.opendaylight.protocol.bgp.parser.BGPMessageParser#parse(byte[])
55          */
56         @Override
57         public List<Notification> parse(final byte[] bytes) throws DeserializerException, DocumentedException {
58                 if (bytes == null) {
59                         throw new IllegalArgumentException("Array of bytes is mandatory.");
60                 }
61                 if (bytes.length < COMMON_HEADER_LENGTH) {
62                         throw new IllegalArgumentException("Too few bytes in passed array. Passed: " + bytes.length + ". Expected: >= "
63                                         + COMMON_HEADER_LENGTH + ".");
64                 }
65                 /*
66                  * byte array starts with message length
67                  */
68                 // final byte[] ones = new byte[MARKER_LENGTH];
69                 // Arrays.fill(ones, (byte)0xff);
70                 // if (Arrays.equals(bytes, ones))
71                 // throw new BGPDocumentedException("Marker not set to ones.", BGPError.CONNECTION_NOT_SYNC);
72                 final byte[] bs = ByteArray.cutBytes(bytes, MARKER_LENGTH);
73                 final int messageLength = ByteArray.bytesToInt(ByteArray.subByte(bs, 0, LENGTH_FIELD_LENGTH));
74                 final int messageType = UnsignedBytes.toInt(bs[LENGTH_FIELD_LENGTH]);
75
76                 final byte[] msgBody = ByteArray.cutBytes(bs, LENGTH_FIELD_LENGTH + TYPE_FIELD_LENGTH);
77
78                 if (messageLength < COMMON_HEADER_LENGTH) {
79                         throw new BGPDocumentedException("Message length field not within valid range.", BGPError.BAD_MSG_LENGTH, ByteArray.subByte(bs,
80                                         0, LENGTH_FIELD_LENGTH));
81                 }
82                 if (msgBody.length != messageLength - COMMON_HEADER_LENGTH) {
83                         throw new DeserializerException("Size doesn't match size specified in header. Passed: " + msgBody.length + "; Expected: "
84                                         + (messageLength - COMMON_HEADER_LENGTH) + ". ");
85                 }
86
87                 logger.debug("Attempt to parse message from bytes: {}", ByteArray.bytesToHexString(msgBody));
88
89                 final MessageParser parser = registry.getMessageParser(messageType);
90                 if (parser == null) {
91                         throw new BGPDocumentedException("Unhandled message type " + messageType, BGPError.BAD_MSG_TYPE, new byte[] { bs[LENGTH_FIELD_LENGTH] });
92                 }
93
94                 final Notification msg = parser.parseMessage(msgBody, messageLength);
95
96                 return Lists.newArrayList(msg);
97         }
98
99         @Override
100         public byte[] put(final Notification msg) {
101                 if (msg == null) {
102                         throw new IllegalArgumentException("BGPMessage is mandatory.");
103                 }
104
105                 logger.trace("Serializing {}", msg);
106
107                 final MessageSerializer serializer = registry.getMessageSerializer(msg);
108                 if (serializer == null) {
109                         throw new IllegalArgumentException("Unknown instance of BGPMessage. Passed " + msg.getClass());
110                 }
111
112                 final byte[] msgBody = serializer.serializeMessage(msg);
113                 final byte[] headerBytes = headerToBytes(msgBody.length + COMMON_HEADER_LENGTH, serializer.messageType());
114                 final byte[] retBytes = new byte[headerBytes.length + msgBody.length];
115
116                 ByteArray.copyWhole(headerBytes, retBytes, 0);
117                 ByteArray.copyWhole(msgBody, retBytes, COMMON_HEADER_LENGTH);
118
119                 logger.trace("Serialized BGP message {}.", Arrays.toString(retBytes));
120                 return retBytes;
121         }
122
123         /**
124          * Serializes this BGP Message header to byte array.
125          * 
126          * @return byte array representation of this header
127          */
128         public byte[] headerToBytes(final int msgLength, final int msgType) {
129                 final byte[] retBytes = new byte[COMMON_HEADER_LENGTH];
130
131                 Arrays.fill(retBytes, 0, MARKER_LENGTH, (byte) 0xff);
132
133                 System.arraycopy(ByteArray.intToBytes(msgLength), Integer.SIZE / Byte.SIZE - LENGTH_FIELD_LENGTH, retBytes, MARKER_LENGTH,
134                                 LENGTH_FIELD_LENGTH);
135
136                 retBytes[MARKER_LENGTH + LENGTH_FIELD_LENGTH] = (byte) msgType;
137
138                 return retBytes;
139         }
140 }