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