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