BUG-47 : PCEP migration to generated DTOs.
[bgpcep.git] / pcep / impl / src / main / java / org / opendaylight / protocol / pcep / impl / PCEPMessageFactory.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.UnpooledByteBufAllocator;
12
13 import java.util.Arrays;
14 import java.util.List;
15
16 import org.opendaylight.protocol.framework.DeserializerException;
17 import org.opendaylight.protocol.framework.DocumentedException;
18 import org.opendaylight.protocol.framework.ProtocolMessageFactory;
19 import org.opendaylight.protocol.pcep.PCEPDeserializerException;
20 import org.opendaylight.protocol.pcep.PCEPDocumentedException;
21 import org.opendaylight.protocol.pcep.spi.HandlerRegistry;
22 import org.opendaylight.protocol.pcep.spi.MessageSerializer;
23 import org.opendaylight.protocol.util.ByteArray;
24 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev131005.Message;
25 import org.slf4j.Logger;
26 import org.slf4j.LoggerFactory;
27
28 import com.google.common.base.Preconditions;
29 import com.google.common.primitives.UnsignedBytes;
30
31 /**
32  * A PCEP message parser which also does validation.
33  */
34 public final class PCEPMessageFactory implements ProtocolMessageFactory<Message> {
35
36         private final static Logger logger = LoggerFactory.getLogger(PCEPMessageFactory.class);
37
38         private final static int TYPE_SIZE = 1; // bytes
39
40         private final static int LENGTH_SIZE = 2; // bytes
41
42         public final static int COMMON_HEADER_LENGTH = 4; // bytes
43
44         /**
45          * Current supported version of PCEP.
46          */
47         public static final int PCEP_VERSION = 1;
48
49         private static final int VERSION_SF_LENGTH = 3;
50
51         private final HandlerRegistry registry;
52
53         private static final int VER_FLAGS_MF_LENGTH = 1;
54         private static final int TYPE_F_LENGTH = 1;
55         private static final int LENGTH_F_LENGTH = 2;
56
57         private static final int VER_FLAGS_MF_OFFSET = 0;
58         private static final int TYPE_F_OFFSET = VER_FLAGS_MF_LENGTH + VER_FLAGS_MF_OFFSET;
59         private static final int LENGTH_F_OFFSET = TYPE_F_LENGTH + TYPE_F_OFFSET;
60
61         public PCEPMessageFactory() {
62                 this.registry = HandlerRegistryImpl.INSTANCE;
63         }
64
65         @Override
66         public List<Message> parse(final byte[] bytes) throws DeserializerException, DocumentedException {
67                 Preconditions.checkArgument(bytes != null, "Bytes may not be null");
68                 Preconditions.checkArgument(bytes.length != 0, "Bytes may not be empty");
69
70                 logger.trace("Attempt to parse message from bytes: {}", ByteArray.bytesToHexString(bytes));
71
72                 final int type = UnsignedBytes.toInt(bytes[1]);
73
74                 final int msgLength = ByteArray.bytesToInt(ByteArray.subByte(bytes, TYPE_SIZE + 1, LENGTH_SIZE));
75
76                 final byte[] msgBody = ByteArray.cutBytes(bytes, TYPE_SIZE + 1 + LENGTH_SIZE);
77
78                 if (msgBody.length != msgLength - COMMON_HEADER_LENGTH) {
79                         throw new DeserializerException("Body size " + msgBody.length + " does not match header size "
80                                         + (msgLength - COMMON_HEADER_LENGTH));
81                 }
82
83                 Message msg = null;
84
85                 try {
86                         msg = this.registry.getMessageParser(type).parseMessage(msgBody);
87                 } catch (final PCEPDeserializerException e) {
88                         logger.debug("Unexpected deserializer problem", e);
89                         throw new DeserializerException(e.getMessage(), e);
90                 } catch (final PCEPDocumentedException e) {
91                         logger.debug("Documented deserializer problem", e);
92                         throw new DocumentedException(e.getMessage(), e);
93                 }
94                 logger.debug("Message was parsed. {}", msg);
95                 return Arrays.asList(msg);
96         }
97
98         @Override
99         public byte[] put(final Message msg) {
100                 if (msg == null) {
101                         throw new IllegalArgumentException("PCEPMessage is mandatory.");
102                 }
103
104                 final ByteBuf buf = new UnpooledByteBufAllocator(false).buffer();
105
106                 final MessageSerializer serializer = this.registry.getMessageSerializer(msg);
107
108                 serializer.serializeMessage(msg, buf);
109
110                 final byte[] msgBody = buf.array();
111
112                 final byte[] headerBytes = new byte[COMMON_HEADER_LENGTH];
113
114                 // msgVer_Flag
115                 headerBytes[VER_FLAGS_MF_OFFSET] = (byte) (PCEP_VERSION << (Byte.SIZE - VERSION_SF_LENGTH));
116
117                 // msgType
118                 headerBytes[TYPE_F_OFFSET] = (byte) serializer.getMessageType();
119
120                 // msgLength
121                 System.arraycopy(ByteArray.intToBytes(msgBody.length), Integer.SIZE / Byte.SIZE - LENGTH_F_LENGTH, headerBytes, LENGTH_F_OFFSET,
122                                 LENGTH_F_LENGTH);
123
124                 final byte[] retBytes = new byte[headerBytes.length + msgBody.length];
125
126                 ByteArray.copyWhole(headerBytes, retBytes, 0);
127                 ByteArray.copyWhole(msgBody, retBytes, PCEPMessageHeader.COMMON_HEADER_LENGTH);
128
129                 return retBytes;
130         }
131 }