Merge "Randomize port to allow concurrent execution"
[bgpcep.git] / pcep / impl / src / main / java / org / opendaylight / protocol / pcep / impl / RawPCEPMessageFactory.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 java.util.HashMap;
11 import java.util.List;
12
13 import org.opendaylight.protocol.framework.DeserializerException;
14 import org.opendaylight.protocol.framework.DocumentedException;
15 import org.opendaylight.protocol.framework.ProtocolMessageFactory;
16 import org.opendaylight.protocol.pcep.PCEPDeserializerException;
17 import org.opendaylight.protocol.pcep.PCEPDocumentedException;
18 import org.opendaylight.protocol.pcep.PCEPErrors;
19 import org.opendaylight.protocol.pcep.impl.message.PCCreateMessageParser;
20 import org.opendaylight.protocol.pcep.impl.message.PCEPCloseMessageParser;
21 import org.opendaylight.protocol.pcep.impl.message.PCEPErrorMessageParser;
22 import org.opendaylight.protocol.pcep.impl.message.PCEPKeepAliveMessageParser;
23 import org.opendaylight.protocol.pcep.impl.message.PCEPNotificationMessageParser;
24 import org.opendaylight.protocol.pcep.impl.message.PCEPOpenMessageParser;
25 import org.opendaylight.protocol.pcep.impl.message.PCEPReplyMessageParser;
26 import org.opendaylight.protocol.pcep.impl.message.PCEPReportMessageParser;
27 import org.opendaylight.protocol.pcep.impl.message.PCEPRequestMessageParser;
28 import org.opendaylight.protocol.pcep.impl.message.PCEPUpdateRequestMessageParser;
29 import org.opendaylight.protocol.pcep.message.PCCreateMessage;
30 import org.opendaylight.protocol.pcep.message.PCEPCloseMessage;
31 import org.opendaylight.protocol.pcep.message.PCEPErrorMessage;
32 import org.opendaylight.protocol.pcep.message.PCEPNotificationMessage;
33 import org.opendaylight.protocol.pcep.message.PCEPOpenMessage;
34 import org.opendaylight.protocol.pcep.message.PCEPReplyMessage;
35 import org.opendaylight.protocol.pcep.message.PCEPReportMessage;
36 import org.opendaylight.protocol.pcep.message.PCEPRequestMessage;
37 import org.opendaylight.protocol.pcep.message.PCEPUpdateRequestMessage;
38 import org.opendaylight.protocol.pcep.spi.PCEPMessageType;
39 import org.opendaylight.protocol.pcep.spi.RawMessage;
40 import org.opendaylight.protocol.util.ByteArray;
41 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev131005.KeepaliveMessage;
42 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev131005.Message;
43 import org.slf4j.Logger;
44 import org.slf4j.LoggerFactory;
45
46 import com.google.common.base.Preconditions;
47 import com.google.common.collect.Lists;
48 import com.google.common.primitives.UnsignedBytes;
49
50 /**
51  * Factory for subclasses of {@link Message}
52  */
53 class RawPCEPMessageFactory implements ProtocolMessageFactory<Message> {
54
55         private final static Logger logger = LoggerFactory.getLogger(PCEPMessageFactory.class);
56
57         private final static int TYPE_SIZE = 1; // bytes
58
59         private final static int LENGTH_SIZE = 2; // bytes
60
61         public final static int COMMON_HEADER_LENGTH = 4; // bytes
62
63         /**
64          * Current supported version of PCEP.
65          */
66         public static final int PCEP_VERSION = 1;
67
68         private static class MapOfParsers extends HashMap<PCEPMessageType, PCEPMessageParser> {
69
70                 private static final long serialVersionUID = -5715193806554448822L;
71
72                 private final static MapOfParsers instance = new MapOfParsers();
73
74                 private MapOfParsers() {
75                         this.fillInMap();
76                 }
77
78                 private void fillInMap() {
79                         this.put(PCEPMessageType.OPEN, new PCEPOpenMessageParser());
80                         this.put(PCEPMessageType.KEEPALIVE, new PCEPKeepAliveMessageParser());
81                         this.put(PCEPMessageType.NOTIFICATION, new PCEPNotificationMessageParser());
82                         this.put(PCEPMessageType.ERROR, new PCEPErrorMessageParser());
83                         this.put(PCEPMessageType.RESPONSE, new PCEPReplyMessageParser());
84                         this.put(PCEPMessageType.REQUEST, new PCEPRequestMessageParser());
85                         this.put(PCEPMessageType.UPDATE_REQUEST, new PCEPUpdateRequestMessageParser());
86                         this.put(PCEPMessageType.STATUS_REPORT, new PCEPReportMessageParser());
87                         this.put(PCEPMessageType.CLOSE, new PCEPCloseMessageParser());
88                         this.put(PCEPMessageType.PCCREATE, new PCCreateMessageParser());
89                 }
90
91                 public static MapOfParsers getInstance() {
92                         return instance;
93                 }
94         }
95
96         /**
97          * 
98          * @param bytes assume array of bytes without common header
99          * @return Parsed specific PCEPMessage
100          * @throws PCEPDeserializerException
101          * @throws PCEPDocumentedException
102          */
103
104         @Override
105         public List<Message> parse(final byte[] bytes) throws DeserializerException, DocumentedException {
106                 Preconditions.checkArgument(bytes != null, "Bytes may not be null");
107                 Preconditions.checkArgument(bytes.length != 0, "Bytes may not be empty");
108
109                 logger.trace("Attempt to parse message from bytes: {}", ByteArray.bytesToHexString(bytes));
110
111                 final int type = UnsignedBytes.toInt(bytes[1]);
112
113                 final int msgLength = ByteArray.bytesToInt(ByteArray.subByte(bytes, TYPE_SIZE + 1, LENGTH_SIZE));
114
115                 final byte[] msgBody = ByteArray.cutBytes(bytes, TYPE_SIZE + 1 + LENGTH_SIZE);
116
117                 if (msgBody.length != msgLength - COMMON_HEADER_LENGTH) {
118                         throw new DeserializerException("Body size " + msgBody.length + " does not match header size "
119                                         + (msgLength - COMMON_HEADER_LENGTH));
120                 }
121
122                 /*
123                  * if PCEPObjectIdentifier.getObjectClassFromInt() dont't throws
124                  * exception and if returned null we know the error type
125                  */
126                 final PCEPMessageType msgType = PCEPMessageType.getFromInt(type);
127                 if (msgType == null) {
128                         logger.debug("Unknown message type {}", type);
129                         throw new DocumentedException("Unhandled message type " + type, new PCEPDocumentedException("Unhandled message type " + type, PCEPErrors.CAPABILITY_NOT_SUPPORTED));
130                 }
131
132                 Message msg;
133                 try {
134                         msg = new RawMessage(PCEPObjectFactory.parseObjects(msgBody), msgType);
135                 } catch (final PCEPDeserializerException e) {
136                         logger.debug("Unexpected deserializer problem", e);
137                         throw new DeserializerException(e.getMessage(), e);
138                 } catch (final PCEPDocumentedException e) {
139                         logger.debug("Documented deserializer problem", e);
140                         throw new DocumentedException(e.getMessage(), e);
141                 }
142                 logger.debug("Message was parsed. {}", msg);
143                 return Lists.newArrayList(msg);
144         }
145
146         @Override
147         public byte[] put(final Message msg) {
148                 if (msg == null) {
149                         throw new IllegalArgumentException("PCEPMessage is mandatory.");
150                 }
151
152                 final PCEPMessageType msgType;
153
154                 if (msg instanceof PCEPOpenMessage) {
155                         msgType = PCEPMessageType.OPEN;
156                 } else if (msg instanceof KeepaliveMessage) {
157                         msgType = PCEPMessageType.KEEPALIVE;
158                 } else if (msg instanceof PCEPCloseMessage) {
159                         msgType = PCEPMessageType.CLOSE;
160                 } else if (msg instanceof PCEPReplyMessage) {
161                         msgType = PCEPMessageType.RESPONSE;
162                 } else if (msg instanceof PCEPRequestMessage) {
163                         msgType = PCEPMessageType.REQUEST;
164                 } else if (msg instanceof PCEPNotificationMessage) {
165                         msgType = PCEPMessageType.NOTIFICATION;
166                 } else if (msg instanceof PCEPErrorMessage) {
167                         msgType = PCEPMessageType.ERROR;
168                 } else if (msg instanceof PCEPReportMessage) {
169                         msgType = PCEPMessageType.STATUS_REPORT;
170                 } else if (msg instanceof PCEPUpdateRequestMessage) {
171                         msgType = PCEPMessageType.UPDATE_REQUEST;
172                 } else if (msg instanceof PCCreateMessage) {
173                         msgType = PCEPMessageType.PCCREATE;
174                 } else {
175                         logger.error("Unknown instance of PCEPMessage. Message class: {}", msg.getClass());
176                         throw new IllegalArgumentException("Unknown instance of PCEPMessage. Passed " + msg.getClass());
177                 }
178
179                 logger.trace("Serializing {}", msgType);
180
181                 final byte[] msgBody = MapOfParsers.getInstance().get(msgType).put(msg);
182
183                 final PCEPMessageHeader msgHeader = new PCEPMessageHeader(msgType.getIdentifier(), msgBody.length
184                                 + PCEPMessageHeader.COMMON_HEADER_LENGTH, PCEP_VERSION);
185
186                 final byte[] headerBytes = msgHeader.toBytes();
187                 final byte[] retBytes = new byte[headerBytes.length + msgBody.length];
188
189                 ByteArray.copyWhole(headerBytes, retBytes, 0);
190                 ByteArray.copyWhole(msgBody, retBytes, PCEPMessageHeader.COMMON_HEADER_LENGTH);
191
192                 return retBytes;
193         }
194 }