Bug-2226: RFC5886 - Messages parsers/serializers
[bgpcep.git] / pcep / impl / src / main / java / org / opendaylight / protocol / pcep / impl / message / PCEPReplyMessageParser.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.message;
9
10 import com.google.common.base.Optional;
11 import com.google.common.base.Preconditions;
12 import io.netty.buffer.ByteBuf;
13 import io.netty.buffer.Unpooled;
14 import java.util.ArrayList;
15 import java.util.List;
16 import org.opendaylight.protocol.pcep.spi.AbstractMessageParser;
17 import org.opendaylight.protocol.pcep.spi.MessageUtil;
18 import org.opendaylight.protocol.pcep.spi.ObjectRegistry;
19 import org.opendaylight.protocol.pcep.spi.PCEPDeserializerException;
20 import org.opendaylight.protocol.pcep.spi.PCEPErrors;
21 import org.opendaylight.protocol.pcep.spi.VendorInformationObjectRegistry;
22 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.message.rev131007.Pcrep;
23 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.message.rev131007.PcrepBuilder;
24 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev131005.Message;
25 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev131005.Object;
26 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev131005.bandwidth.object.Bandwidth;
27 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev131005.explicit.route.object.Ero;
28 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev131005.include.route.object.Iro;
29 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev131005.lsp.attributes.Metrics;
30 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev131005.lsp.attributes.MetricsBuilder;
31 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev131005.lspa.object.Lspa;
32 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev131005.metric.object.Metric;
33 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev131005.monitoring.metrics.MetricPce;
34 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev131005.monitoring.metrics.MetricPceBuilder;
35 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev131005.monitoring.object.Monitoring;
36 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev131005.of.object.Of;
37 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev131005.overload.object.Overload;
38 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev131005.pcc.id.req.object.PccIdReq;
39 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev131005.pce.id.object.PceId;
40 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev131005.pcrep.message.PcrepMessageBuilder;
41 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev131005.pcrep.message.pcrep.message.Replies;
42 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev131005.pcrep.message.pcrep.message.RepliesBuilder;
43 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev131005.pcrep.message.pcrep.message.replies.Result;
44 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev131005.pcrep.message.pcrep.message.replies.result.FailureCase;
45 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev131005.pcrep.message.pcrep.message.replies.result.FailureCaseBuilder;
46 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev131005.pcrep.message.pcrep.message.replies.result.SuccessCase;
47 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev131005.pcrep.message.pcrep.message.replies.result.SuccessCaseBuilder;
48 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev131005.pcrep.message.pcrep.message.replies.result.failure._case.NoPath;
49 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev131005.pcrep.message.pcrep.message.replies.result.success._case.SuccessBuilder;
50 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev131005.pcrep.message.pcrep.message.replies.result.success._case.success.Paths;
51 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev131005.pcrep.message.pcrep.message.replies.result.success._case.success.PathsBuilder;
52 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev131005.proc.time.object.ProcTime;
53 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev131005.rp.object.Rp;
54 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev131005.vendor.information.objects.VendorInformationObject;
55
56 /**
57  * Parser for {@link Pcrep}
58  */
59 public class PCEPReplyMessageParser extends AbstractMessageParser {
60
61     public static final int TYPE = 4;
62
63     public PCEPReplyMessageParser(final ObjectRegistry registry, final VendorInformationObjectRegistry viRegistry) {
64         super(registry, viRegistry);
65     }
66
67     @Override
68     public void serializeMessage(final Message message, final ByteBuf out) {
69         Preconditions.checkArgument(message instanceof Pcrep, "Wrong instance of Message. Passed instance of %s. Need Pcrep.", message.getClass());
70         final org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev131005.pcrep.message.PcrepMessage repMsg = ((Pcrep) message).getPcrepMessage();
71         if (repMsg.getReplies() == null || repMsg.getReplies().isEmpty()) {
72             throw new IllegalArgumentException("Replies cannot be null or empty.");
73         }
74         final ByteBuf buffer = Unpooled.buffer();
75         for (final Replies reply : repMsg.getReplies()) {
76             if (reply.getRp() == null) {
77                 throw new IllegalArgumentException("Reply must contain RP object.");
78             }
79             serializeReply(reply, buffer);
80         }
81         MessageUtil.formatMessage(TYPE, buffer, out);
82     }
83
84     protected void serializeReply(final Replies reply, final ByteBuf buffer) {
85         serializeObject(reply.getRp(), buffer);
86         serializeMonitoring(reply, buffer);
87         serializeVendorInformationObjects(reply.getVendorInformationObject(), buffer);
88         if (reply.getResult() == null) {
89             return;
90         }
91         if (reply.getResult() instanceof FailureCase) {
92             final FailureCase f = ((FailureCase) reply.getResult());
93             if (f != null) {
94                 serializeObject(f.getNoPath(), buffer);
95                 serializeObject(f.getLspa(), buffer);
96                 serializeObject(f.getBandwidth(), buffer);
97                 if (f.getMetrics() != null) {
98                     for (final Metrics m : f.getMetrics()) {
99                         serializeObject(m.getMetric(), buffer);
100                     }
101                 }
102                 serializeObject(f.getIro(), buffer);
103             }
104             return;
105         }
106         final SuccessCase s = (SuccessCase) reply.getResult();
107         if (s != null && s.getSuccess() != null) {
108             for (final Paths p : s.getSuccess().getPaths()) {
109                 serializeObject(p.getEro(), buffer);
110                 serializeObject(p.getLspa(), buffer);
111                 serializeObject(p.getOf(), buffer);
112                 serializeObject(p.getBandwidth(), buffer);
113                 if (p.getMetrics() != null) {
114                     for (final Metrics m : p.getMetrics()) {
115                         serializeObject(m.getMetric(), buffer);
116                     }
117                 }
118                 serializeObject(p.getIro(), buffer);
119             }
120             serializeVendorInformationObjects(s.getSuccess().getVendorInformationObject(), buffer);
121         }
122         serializeMonitoringMetrics(reply, buffer);
123     }
124
125     private void serializeMonitoring(final Replies reply, final ByteBuf buffer) {
126         serializeObject(reply.getMonitoring(), buffer);
127         serializeObject(reply.getPccIdReq(), buffer);
128     }
129
130     private void serializeMonitoringMetrics(final Replies reply, final ByteBuf buffer) {
131         if (reply.getMetricPce() != null) {
132             for (final MetricPce metricPce : reply.getMetricPce()) {
133                 serializeMetricPce(metricPce, buffer);
134             }
135         }
136     }
137
138     protected void serializeMetricPce(final MetricPce metricPce, final ByteBuf buffer) {
139         Preconditions.checkArgument(metricPce.getPceId() != null, "PCE-ID must be present.");
140         serializeObject(metricPce.getPceId(), buffer);
141         serializeObject(metricPce.getProcTime(), buffer);
142         serializeObject(metricPce.getOverload(), buffer);
143     }
144
145     @Override
146     protected Pcrep validate(final List<Object> objects, final List<Message> errors) throws PCEPDeserializerException {
147         if (objects == null) {
148             throw new IllegalArgumentException("Passed list can't be null.");
149         }
150         if (objects.isEmpty()) {
151             throw new PCEPDeserializerException("Pcrep message cannot be empty.");
152         }
153         final List<Replies> replies = new ArrayList<>();
154         while (!objects.isEmpty()) {
155             final Replies r = this.getValidReply(objects, errors);
156             if (r != null) {
157                 replies.add(r);
158             }
159         }
160         if (!objects.isEmpty()) {
161             throw new PCEPDeserializerException("Unprocessed Objects: " + objects);
162         }
163         return new PcrepBuilder().setPcrepMessage(new PcrepMessageBuilder().setReplies(replies).build()).build();
164     }
165
166     protected Replies getValidReply(final List<Object> objects, final List<Message> errors) throws PCEPDeserializerException {
167         if (!(objects.get(0) instanceof Rp)) {
168             errors.add(createErrorMsg(PCEPErrors.RP_MISSING, Optional.<Rp>absent()));
169             return null;
170         }
171         final Rp rp = (Rp) objects.get(0);
172         objects.remove(0);
173         final RepliesBuilder repliesBuilder = new RepliesBuilder();
174         if (!objects.isEmpty() && objects.get(0) instanceof Monitoring) {
175             repliesBuilder.setMonitoring((Monitoring) objects.get(0));
176             objects.remove(0);
177         }
178         if (!objects.isEmpty() && objects.get(0) instanceof PccIdReq) {
179             repliesBuilder.setPccIdReq((PccIdReq) objects.get(0));
180             objects.remove(0);
181         }
182         final List<VendorInformationObject> vendorInfo = addVendorInformationObjects(objects);
183         Result res = null;
184         if (!objects.isEmpty()) {
185             if (objects.get(0) instanceof NoPath) {
186                 final NoPath noPath = (NoPath) objects.get(0);
187                 objects.remove(0);
188                 final FailureCaseBuilder builder = new FailureCaseBuilder();
189                 builder.setNoPath(noPath);
190                 while (!objects.isEmpty() && !(objects.get(0) instanceof PceId)) {
191                     this.parseAttributes(builder, objects);
192                 }
193                 res = builder.build();
194             } else if (objects.get(0) instanceof Ero) {
195                 final Ero ero = (Ero) objects.get(0);
196                 objects.remove(0);
197                 final SuccessBuilder builder = new SuccessBuilder();
198                 final List<Paths> paths = new ArrayList<>();
199                 final PathsBuilder pBuilder = new PathsBuilder();
200                 pBuilder.setEro(ero);
201                 while (!objects.isEmpty() && !(objects.get(0) instanceof PceId)) {
202                     final List<VendorInformationObject> vendorInfoObjects = addVendorInformationObjects(objects);
203                     if (!vendorInfoObjects.isEmpty()) {
204                         builder.setVendorInformationObject(vendorInfoObjects);
205                     }
206                     this.parsePath(pBuilder, objects);
207                     paths.add(pBuilder.build());
208                 }
209                 builder.setPaths(paths);
210                 res = new SuccessCaseBuilder().setSuccess(builder.build()).build();
211             }
212         }
213         final List<MetricPce> metricPceList = new ArrayList<>();
214         if (!objects.isEmpty() && objects.get(0) instanceof PceId) {
215             while (!objects.isEmpty()) {
216                 metricPceList.add(validateMetricPce(objects));
217             }
218         }
219         if (!vendorInfo.isEmpty()) {
220             repliesBuilder.setVendorInformationObject(vendorInfo);
221         }
222         if (!metricPceList.isEmpty()) {
223             repliesBuilder.setMetricPce(metricPceList);
224         }
225         return repliesBuilder.setRp(rp).setResult(res).build();
226     }
227
228     protected void parseAttributes(final FailureCaseBuilder builder, final List<Object> objects) {
229         final List<Metrics> pathMetrics = new ArrayList<>();
230
231         Object obj;
232         State state = State.INIT;
233         while (!objects.isEmpty() && !state.equals(State.END)) {
234             obj = objects.get(0);
235
236             switch (state) {
237             case INIT:
238                 state = State.LSPA_IN;
239                 if (obj instanceof Lspa) {
240                     builder.setLspa((Lspa) obj);
241                     break;
242                 }
243             case LSPA_IN:
244                 state = State.BANDWIDTH_IN;
245                 if (obj instanceof Bandwidth) {
246                     builder.setBandwidth((Bandwidth) obj);
247                     break;
248                 }
249             case BANDWIDTH_IN:
250                 state = State.METRIC_IN;
251                 if (obj instanceof Metric) {
252                     pathMetrics.add(new MetricsBuilder().setMetric((Metric) obj).build());
253                     state = State.METRIC_IN;
254                     break;
255                 }
256             case METRIC_IN:
257                 state = State.IRO_IN;
258                 if (obj instanceof Iro) {
259                     builder.setIro((Iro) obj);
260                     break;
261                 }
262             case IRO_IN:
263                 state = State.END;
264                 break;
265             case END:
266                 break;
267             default:
268                 break;
269             }
270             if (!state.equals(State.END)) {
271                 objects.remove(0);
272             }
273         }
274         if (!pathMetrics.isEmpty()) {
275             builder.setMetrics(pathMetrics);
276         }
277     }
278
279     protected void parsePath(final PathsBuilder builder, final List<Object> objects) {
280         final List<Metrics> pathMetrics = new ArrayList<>();
281
282         Object obj;
283         State state = State.INIT;
284         while (!objects.isEmpty() && !state.equals(State.END)) {
285             obj = objects.get(0);
286
287             switch (state) {
288             case INIT:
289                 state = State.LSPA_IN;
290                 if (obj instanceof Lspa) {
291                     builder.setLspa((Lspa) obj);
292                     break;
293                 }
294             case LSPA_IN:
295                 state = State.OF_IN;
296                 if (obj instanceof Of) {
297                     builder.setOf((Of) obj);
298                     break;
299                 }
300             case OF_IN:
301                 state = State.BANDWIDTH_IN;
302                 if (obj instanceof Bandwidth) {
303                     builder.setBandwidth((Bandwidth) obj);
304                     break;
305                 }
306             case BANDWIDTH_IN:
307                 state = State.METRIC_IN;
308                 if (obj instanceof Metric) {
309                     pathMetrics.add(new MetricsBuilder().setMetric((Metric) obj).build());
310                     state = State.BANDWIDTH_IN;
311                     break;
312                 }
313             case METRIC_IN:
314                 state = State.IRO_IN;
315                 if (obj instanceof Iro) {
316                     builder.setIro((Iro) obj);
317                     break;
318                 }
319             case IRO_IN:
320                 state = State.END;
321                 break;
322             case END:
323                 break;
324             default:
325                 break;
326             }
327             if (!state.equals(State.END)) {
328                 objects.remove(0);
329             }
330         }
331         if (!pathMetrics.isEmpty()) {
332             builder.setMetrics(pathMetrics);
333         }
334     }
335
336     private enum State {
337         INIT, LSPA_IN, OF_IN, BANDWIDTH_IN, METRIC_IN, IRO_IN, END
338     }
339
340     protected MetricPce validateMetricPce(final List<Object> objects) throws PCEPDeserializerException {
341         final MetricPceBuilder metricPceBuilder = new MetricPceBuilder();
342         if (!(objects.get(0) instanceof PceId)) {
343             throw new PCEPDeserializerException("metric-pce-list must start with PCE-ID object.");
344         }
345         metricPceBuilder.setPceId((PceId) (objects.get(0)));
346         objects.remove(0);
347         MetricPceState state = MetricPceState.START;
348         while (!objects.isEmpty() && !state.equals(MetricPceState.END)) {
349             final Object obj = objects.get(0);
350             switch(state) {
351             case START :
352                 state = MetricPceState.PROC_TIME;
353                 if (obj instanceof ProcTime) {
354                     metricPceBuilder.setProcTime((ProcTime) obj);
355                     break;
356                 }
357             case PROC_TIME :
358                 state = MetricPceState.OVERLOAD;
359                 if (obj instanceof Overload) {
360                     metricPceBuilder.setOverload((Overload) obj);
361                     break;
362                 }
363             case OVERLOAD :
364                 state = MetricPceState.END;
365                 break;
366             case END :
367                 break;
368             }
369             if (!state.equals(MetricPceState.END)) {
370                 objects.remove(0);
371             }
372         }
373         return metricPceBuilder.build();
374     }
375
376     private enum MetricPceState {
377         START, PROC_TIME, OVERLOAD, END;
378     }
379 }