8ba57ad185d46aa49baf87c977c4f5316514def0
[bgpcep.git] / pcep / impl / src / main / java / org / opendaylight / protocol / pcep / impl / PCEPByteToMessageDecoder.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.pcep.impl;
9
10 import io.netty.buffer.ByteBuf;
11 import io.netty.buffer.ByteBufUtil;
12 import io.netty.channel.ChannelHandlerContext;
13 import io.netty.handler.codec.ByteToMessageDecoder;
14
15 import java.util.ArrayList;
16 import java.util.List;
17
18 import org.opendaylight.protocol.framework.DeserializerException;
19 import org.opendaylight.protocol.pcep.spi.MessageHandlerRegistry;
20 import org.opendaylight.protocol.util.ByteArray;
21 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev131005.Message;
22 import org.slf4j.Logger;
23 import org.slf4j.LoggerFactory;
24
25 import com.google.common.base.Preconditions;
26 import com.google.common.primitives.UnsignedBytes;
27
28 /**
29  * A PCEP message parser which also does validation.
30  */
31 public final class PCEPByteToMessageDecoder extends ByteToMessageDecoder {
32         private final static Logger LOG = LoggerFactory.getLogger(PCEPByteToMessageDecoder.class);
33
34         private final static int TYPE_SIZE = 1; // bytes
35
36         private final static int LENGTH_SIZE = 2; // bytes
37
38         private final MessageHandlerRegistry registry;
39
40         public PCEPByteToMessageDecoder(final MessageHandlerRegistry registry) {
41                 this.registry = Preconditions.checkNotNull(registry);
42         }
43
44         @Override
45         protected void decode(final ChannelHandlerContext ctx, final ByteBuf in, final List<Object> out) throws Exception {
46                 if (in.readableBytes() == 0) {
47                         LOG.debug("No more content in incoming buffer.");
48                         return;
49                 }
50
51                 in.markReaderIndex();
52                 LOG.trace("Received to decode: {}", ByteBufUtil.hexDump(in));
53                 final byte[] bytes = new byte[in.readableBytes()];
54                 in.readBytes(bytes);
55
56                 final List<Message> errors = new ArrayList<>();
57
58                 try {
59                         out.add(parse(bytes, errors));
60                 } catch (DeserializerException e) {
61                         LOG.debug("Failed to decode protocol message", e);
62                         this.exceptionCaught(ctx, e);
63                 }
64                 in.discardReadBytes();
65
66                 if (!errors.isEmpty()) {
67                         // We have a bunch of messages, send them out
68                         for (final Object e : errors) {
69                                 ctx.channel().write(e);
70                         }
71                         ctx.channel().flush();
72                 }
73         }
74
75         private Message parse(final byte[] bytes, final List<Message> errors) throws DeserializerException {
76                 final int type = UnsignedBytes.toInt(bytes[1]);
77                 final int msgLength = ByteArray.bytesToInt(ByteArray.subByte(bytes, TYPE_SIZE + 1, LENGTH_SIZE));
78
79                 final byte[] msgBody = ByteArray.cutBytes(bytes, TYPE_SIZE + 1 + LENGTH_SIZE);
80                 if (msgBody.length != msgLength - PCEPMessageConstants.COMMON_HEADER_LENGTH) {
81                         throw new DeserializerException("Body size " + msgBody.length + " does not match header size "
82                                         + (msgLength - PCEPMessageConstants.COMMON_HEADER_LENGTH));
83                 }
84
85                 final Message msg = this.registry.getMessageParser(type).parseMessage(msgBody, errors);
86                 LOG.debug("Message was parsed. {}", msg);
87                 return msg;
88         }
89 }