b4f38ccd72bf6505a406377a1ebc1cd86313d0a0
[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 java.util.HashMap;
11
12 import org.opendaylight.protocol.framework.DeserializerException;
13 import org.opendaylight.protocol.framework.DocumentedException;
14 import org.opendaylight.protocol.framework.ProtocolMessage;
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.PCEPMessage;
20 import org.opendaylight.protocol.pcep.impl.message.PCCreateMessageParser;
21 import org.opendaylight.protocol.pcep.impl.message.PCEPCloseMessageParser;
22 import org.opendaylight.protocol.pcep.impl.message.PCEPErrorMessageParser;
23 import org.opendaylight.protocol.pcep.impl.message.PCEPKeepAliveMessageParser;
24 import org.opendaylight.protocol.pcep.impl.message.PCEPNotificationMessageParser;
25 import org.opendaylight.protocol.pcep.impl.message.PCEPOpenMessageParser;
26 import org.opendaylight.protocol.pcep.impl.message.PCEPRawMessage;
27 import org.opendaylight.protocol.pcep.impl.message.PCEPReplyMessageParser;
28 import org.opendaylight.protocol.pcep.impl.message.PCEPReportMessageParser;
29 import org.opendaylight.protocol.pcep.impl.message.PCEPRequestMessageParser;
30 import org.opendaylight.protocol.pcep.impl.message.PCEPUpdateRequestMessageParser;
31 import org.opendaylight.protocol.pcep.impl.message.PCEPXRAddTunnelMessageParser;
32 import org.opendaylight.protocol.pcep.impl.message.PCEPXRDeleteTunnelMessageParser;
33 import org.opendaylight.protocol.pcep.message.PCCreateMessage;
34 import org.opendaylight.protocol.pcep.message.PCEPCloseMessage;
35 import org.opendaylight.protocol.pcep.message.PCEPErrorMessage;
36 import org.opendaylight.protocol.pcep.message.PCEPKeepAliveMessage;
37 import org.opendaylight.protocol.pcep.message.PCEPNotificationMessage;
38 import org.opendaylight.protocol.pcep.message.PCEPOpenMessage;
39 import org.opendaylight.protocol.pcep.message.PCEPReplyMessage;
40 import org.opendaylight.protocol.pcep.message.PCEPReportMessage;
41 import org.opendaylight.protocol.pcep.message.PCEPRequestMessage;
42 import org.opendaylight.protocol.pcep.message.PCEPUpdateRequestMessage;
43 import org.opendaylight.protocol.pcep.message.PCEPXRAddTunnelMessage;
44 import org.opendaylight.protocol.pcep.message.PCEPXRDeleteTunnelMessage;
45 import org.opendaylight.protocol.util.ByteArray;
46 import org.slf4j.Logger;
47 import org.slf4j.LoggerFactory;
48
49 import com.google.common.primitives.UnsignedBytes;
50
51 /**
52  * Factory for subclasses of {@link org.opendaylight.protocol.pcep.PCEPMessage PCEPMessage}
53  */
54 public class PCEPMessageFactory implements ProtocolMessageFactory {
55
56         private final static Logger logger = LoggerFactory.getLogger(PCEPMessageFactory.class);
57
58         private final static int TYPE_SIZE = 1; // bytes
59
60         private final static int LENGTH_SIZE = 2; // bytes
61
62         public final static int COMMON_HEADER_LENGTH = 4; // bytes
63
64         /**
65          * Type identifier for {@link org.opendaylight.protocol.pcep.PCEPMessage PCEPMessage}
66          */
67         public enum PCEPMessageType {
68                 OPEN(1), NOTIFICATION(5), KEEPALIVE(2), RESPONSE(4), REQUEST(3), ERROR(6), CLOSE(7), UPDATE_REQUEST(11), STATUS_REPORT(10),
69                 // TODO: replace with actual values by IANA
70                 XR_ADD_TUNNEL(8), XR_DELETE_TUNNEL(9), PCCREATE(12);
71
72                 private final int identifier;
73
74                 PCEPMessageType(final int identifier) {
75                         this.identifier = identifier;
76                 }
77
78                 public int getIdentifier() {
79                         return this.identifier;
80                 }
81
82                 public static PCEPMessageType getFromInt(final int type) throws PCEPDeserializerException {
83
84                         for (final PCEPMessageType type_e : PCEPMessageType.values()) {
85                                 if (type_e.getIdentifier() == type)
86                                         return type_e;
87                         }
88
89                         throw new PCEPDeserializerException("Unknown PCEPMessage Class identifier. Passed: " + type + "; Known: "
90                                         + PCEPMessageType.values() + ".");
91                 }
92         }
93
94         private static class MapOfParsers extends HashMap<PCEPMessageType, PCEPMessageParser> {
95
96                 private static final long serialVersionUID = -5715193806554448822L;
97
98                 private final static MapOfParsers instance = new MapOfParsers();
99
100                 private MapOfParsers() {
101                         this.fillInMap();
102                 }
103
104                 private void fillInMap() {
105                         this.put(PCEPMessageType.OPEN, new PCEPOpenMessageParser());
106                         this.put(PCEPMessageType.KEEPALIVE, new PCEPKeepAliveMessageParser());
107                         this.put(PCEPMessageType.NOTIFICATION, new PCEPNotificationMessageParser());
108                         this.put(PCEPMessageType.ERROR, new PCEPErrorMessageParser());
109                         this.put(PCEPMessageType.RESPONSE, new PCEPReplyMessageParser());
110                         this.put(PCEPMessageType.REQUEST, new PCEPRequestMessageParser());
111                         this.put(PCEPMessageType.UPDATE_REQUEST, new PCEPUpdateRequestMessageParser());
112                         this.put(PCEPMessageType.STATUS_REPORT, new PCEPReportMessageParser());
113                         this.put(PCEPMessageType.CLOSE, new PCEPCloseMessageParser());
114                         this.put(PCEPMessageType.XR_ADD_TUNNEL, new PCEPXRAddTunnelMessageParser());
115                         this.put(PCEPMessageType.XR_DELETE_TUNNEL, new PCEPXRDeleteTunnelMessageParser());
116                         this.put(PCEPMessageType.PCCREATE, new PCCreateMessageParser());
117                 }
118
119                 public static MapOfParsers getInstance() {
120                         return instance;
121                 }
122         }
123
124         /**
125          * 
126          * @param bytes assume array of bytes without common header
127          * @param msgHeader
128          * @return Parsed specific PCEPMessage
129          * @throws PCEPDeserializerException
130          * @throws PCEPDocumentedException
131          */
132
133         @Override
134         public ProtocolMessage parse(final byte[] bytes) throws DeserializerException, DocumentedException {
135                 if (bytes == null)
136                         throw new IllegalArgumentException("Array of bytes is mandatory.");
137
138                 logger.trace("Attempt to parse message from bytes: {}", ByteArray.bytesToHexString(bytes));
139
140                 final int type = UnsignedBytes.toInt(bytes[1]);
141
142                 final int msgLength = ByteArray.bytesToInt(ByteArray.subByte(bytes, TYPE_SIZE + 1, LENGTH_SIZE));
143
144                 final byte[] msgBody = ByteArray.cutBytes(bytes, TYPE_SIZE + 1 + LENGTH_SIZE);
145
146                 if (msgBody.length != (msgLength - COMMON_HEADER_LENGTH))
147                         throw new DeserializerException("Size don't match size specified in header. Passed: " + msgBody.length + "; Expected: "
148                                         + (msgLength - COMMON_HEADER_LENGTH) + ". " + msgLength);
149
150                 /*
151                  * if PCEPObjectIdentifier.getObjectClassFromInt() dont't throws
152                  * exception and if returned null we know the error type
153                  */
154                 PCEPMessageType msgType;
155                 try {
156                         msgType = PCEPMessageType.getFromInt(type);
157                 } catch (final PCEPDeserializerException e) {
158                         throw new DeserializerException(e.getMessage(), e);
159                 }
160                 if (msgType == null)
161                         throw new DocumentedException("Unhandled message type " + type, new PCEPDocumentedException("Unhandled message type " + type, PCEPErrors.CAPABILITY_NOT_SUPPORTED));
162
163                 PCEPMessage msg;
164                 try {
165                         msg = new PCEPRawMessage(PCEPObjectFactory.parseObjects(msgBody), msgType);
166                 } catch (final PCEPDeserializerException e) {
167                         throw new DeserializerException(e.getMessage(), e);
168                 } catch (final PCEPDocumentedException e) {
169                         throw new DocumentedException(e.getMessage(), e);
170                 }
171                 logger.debug("Message was parsed. {}", msg);
172                 return msg;
173         }
174
175         @Override
176         public byte[] put(final ProtocolMessage msg) {
177                 final PCEPMessage pcepMsg = (PCEPMessage) msg;
178                 if (pcepMsg == null)
179                         throw new IllegalArgumentException("PCEPMessage is mandatory.");
180
181                 final PCEPMessageType msgType;
182
183                 if (pcepMsg instanceof PCEPOpenMessage) {
184                         msgType = PCEPMessageType.OPEN;
185                 } else if (pcepMsg instanceof PCEPKeepAliveMessage) {
186                         msgType = PCEPMessageType.KEEPALIVE;
187                 } else if (pcepMsg instanceof PCEPCloseMessage) {
188                         msgType = PCEPMessageType.CLOSE;
189                 } else if (pcepMsg instanceof PCEPReplyMessage) {
190                         msgType = PCEPMessageType.RESPONSE;
191                 } else if (pcepMsg instanceof PCEPRequestMessage) {
192                         msgType = PCEPMessageType.REQUEST;
193                 } else if (pcepMsg instanceof PCEPNotificationMessage) {
194                         msgType = PCEPMessageType.NOTIFICATION;
195                 } else if (pcepMsg instanceof PCEPErrorMessage) {
196                         msgType = PCEPMessageType.ERROR;
197                 } else if (pcepMsg instanceof PCEPReportMessage) {
198                         msgType = PCEPMessageType.STATUS_REPORT;
199                 } else if (pcepMsg instanceof PCEPUpdateRequestMessage) {
200                         msgType = PCEPMessageType.UPDATE_REQUEST;
201                 } else if (pcepMsg instanceof PCEPXRAddTunnelMessage) {
202                         msgType = PCEPMessageType.XR_ADD_TUNNEL;
203                 } else if (pcepMsg instanceof PCEPXRDeleteTunnelMessage) {
204                         msgType = PCEPMessageType.XR_DELETE_TUNNEL;
205                 } else if (pcepMsg instanceof PCCreateMessage) {
206                         msgType = PCEPMessageType.PCCREATE;
207                 } else {
208                         logger.error("Unknown instance of PCEPMessage. Message class: {}", pcepMsg.getClass());
209                         throw new IllegalArgumentException("Unknown instance of PCEPMessage. Passed " + pcepMsg.getClass());
210                 }
211
212                 logger.trace("Serializing {}", msgType);
213
214                 final byte[] msgBody = MapOfParsers.getInstance().get(msgType).put(pcepMsg);
215
216                 final PCEPMessageHeader msgHeader = new PCEPMessageHeader(msgType.getIdentifier(), msgBody.length
217                                 + PCEPMessageHeader.COMMON_HEADER_LENGTH, PCEPMessage.PCEP_VERSION);
218
219                 final byte[] headerBytes = msgHeader.toBytes();
220                 final byte[] retBytes = new byte[headerBytes.length + msgBody.length];
221
222                 ByteArray.copyWhole(headerBytes, retBytes, 0);
223                 ByteArray.copyWhole(msgBody, retBytes, PCEPMessageHeader.COMMON_HEADER_LENGTH);
224
225                 return retBytes;
226         }
227 }