Clean pcep/base-parser code
[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         if (failure.getMetrics() != null) {
105             for (final Metrics m : failure.getMetrics()) {
106                 serializeObject(m.getMetric(), buffer);
107             }
108         }
109         serializeObject(failure.getIro(), buffer);
110     }
111
112     private void serializeSuccess(final SuccessCase success, final ByteBuf buffer) {
113         if (success == null || success.getSuccess() == null) {
114             return;
115         }
116         for (final Paths p : success.getSuccess().getPaths()) {
117             serializeObject(p.getEro(), buffer);
118             serializeObject(p.getLspa(), buffer);
119             serializeObject(p.getOf(), buffer);
120             serializeObject(p.getBandwidth(), buffer);
121             if (p.getMetrics() != null) {
122                 for (final Metrics m : p.getMetrics()) {
123                     serializeObject(m.getMetric(), buffer);
124                 }
125             }
126             serializeObject(p.getIro(), buffer);
127         }
128         serializeVendorInformationObjects(success.getSuccess().getVendorInformationObject(), buffer);
129     }
130
131     private void serializeMonitoring(final Replies reply, final ByteBuf buffer) {
132         serializeObject(reply.getMonitoring(), buffer);
133         serializeObject(reply.getPccIdReq(), buffer);
134     }
135
136     private void serializeMonitoringMetrics(final Replies reply, final ByteBuf buffer) {
137         if (reply.getMetricPce() != null) {
138             for (final MetricPce metricPce : reply.getMetricPce()) {
139                 serializeMetricPce(metricPce, buffer);
140             }
141         }
142     }
143
144     protected void serializeMetricPce(final MetricPce metricPce, final ByteBuf buffer) {
145         Preconditions.checkArgument(metricPce.getPceId() != null, "PCE-ID must be present.");
146         serializeObject(metricPce.getPceId(), buffer);
147         serializeObject(metricPce.getProcTime(), buffer);
148         serializeObject(metricPce.getOverload(), buffer);
149     }
150
151     @Override
152     protected Pcrep validate(final List<Object> objects, final List<Message> errors) throws PCEPDeserializerException {
153         Preconditions.checkArgument(objects != null, "Passed list can't be null.");
154         if (objects.isEmpty()) {
155             throw new PCEPDeserializerException("Pcrep message cannot be empty.");
156         }
157         final List<Replies> replies = new ArrayList<>();
158         while (!objects.isEmpty()) {
159             final Replies r = this.getValidReply(objects, errors);
160             if (r != null) {
161                 replies.add(r);
162             }
163         }
164         if (!objects.isEmpty()) {
165             throw new PCEPDeserializerException("Unprocessed Objects: " + objects);
166         }
167         return new PcrepBuilder().setPcrepMessage(new PcrepMessageBuilder().setReplies(replies).build()).build();
168     }
169
170     protected Replies getValidReply(final List<Object> objects, final List<Message> errors)
171             throws PCEPDeserializerException {
172         Object object = objects.remove(0);
173         if (!(object instanceof Rp)) {
174             errors.add(createErrorMsg(PCEPErrors.RP_MISSING, Optional.empty()));
175             return null;
176         }
177         final Rp rp = (Rp) object;
178         final RepliesBuilder repliesBuilder = new RepliesBuilder();
179         if (!objects.isEmpty() && objects.get(0) instanceof Monitoring) {
180             repliesBuilder.setMonitoring((Monitoring) objects.get(0));
181             objects.remove(0);
182         }
183         if (!objects.isEmpty() && objects.get(0) instanceof PccIdReq) {
184             repliesBuilder.setPccIdReq((PccIdReq) objects.get(0));
185             objects.remove(0);
186         }
187         final List<VendorInformationObject> vendorInfo = addVendorInformationObjects(objects);
188         Result res = null;
189         if (!objects.isEmpty()) {
190             if (objects.get(0) instanceof NoPath) {
191                 res = handleNoPath((NoPath) objects.get(0), objects);
192             } else if (objects.get(0) instanceof Ero) {
193                 res = handleEros(objects);
194             }
195         }
196         final List<MetricPce> metricPceList = new ArrayList<>();
197         if (!objects.isEmpty() && objects.get(0) instanceof PceId) {
198             while (!objects.isEmpty()) {
199                 metricPceList.add(Util.validateMonitoringMetrics(objects));
200             }
201         }
202         if (!vendorInfo.isEmpty()) {
203             repliesBuilder.setVendorInformationObject(vendorInfo);
204         }
205         if (!metricPceList.isEmpty()) {
206             repliesBuilder.setMetricPce(metricPceList);
207         }
208         return repliesBuilder.setRp(rp).setResult(res).build();
209     }
210
211     private Result handleNoPath(final NoPath noPath, final List<Object> objects) {
212         objects.remove(0);
213         final FailureCaseBuilder builder = new FailureCaseBuilder().setNoPath(noPath);
214         while (!objects.isEmpty() && !(objects.get(0) instanceof PceId)) {
215             this.parseAttributes(builder, objects);
216         }
217         return builder.build();
218     }
219
220     private Result handleEros(final List<Object> objects) {
221         final SuccessBuilder builder = new SuccessBuilder();
222         final List<Paths> paths = new ArrayList<>();
223         while (!objects.isEmpty() && !(objects.get(0) instanceof PceId)) {
224             final PathsBuilder pBuilder = new PathsBuilder();
225             if (objects.get(0) instanceof Ero) {
226                 pBuilder.setEro((Ero ) objects.remove(0));
227             }
228             final List<VendorInformationObject> vendorInfoObjects = addVendorInformationObjects(objects);
229             if (!vendorInfoObjects.isEmpty()) {
230                 builder.setVendorInformationObject(vendorInfoObjects);
231             }
232             this.parsePath(pBuilder, objects);
233             paths.add(pBuilder.build());
234         }
235         builder.setPaths(paths);
236         return new SuccessCaseBuilder().setSuccess(builder.build()).build();
237     }
238
239     protected void parseAttributes(final FailureCaseBuilder builder, final List<Object> objects) {
240         final List<Metrics> pathMetrics = new ArrayList<>();
241
242         Object obj;
243         State state = State.INIT;
244         while (!objects.isEmpty() && !state.equals(State.END)) {
245             obj = objects.get(0);
246             state = insertObject(state, obj, builder, pathMetrics);
247             if (!state.equals(State.END)) {
248                 objects.remove(0);
249             }
250         }
251         if (!pathMetrics.isEmpty()) {
252             builder.setMetrics(pathMetrics);
253         }
254     }
255
256     private static State insertObject(final State state, final Object obj, final FailureCaseBuilder builder,
257             final List<Metrics> pathMetrics) {
258         switch (state) {
259             case INIT:
260                 if (obj instanceof Lspa) {
261                     builder.setLspa((Lspa) obj);
262                     return State.LSPA_IN;
263                 }
264                 // fallthrough
265             case LSPA_IN:
266                 if (obj instanceof Bandwidth) {
267                     builder.setBandwidth((Bandwidth) obj);
268                     return State.BANDWIDTH_IN;
269                 }
270                 // fallthrough
271             case BANDWIDTH_IN:
272                 if (obj instanceof Metric) {
273                     pathMetrics.add(new MetricsBuilder().setMetric((Metric) obj).build());
274                     return State.BANDWIDTH_IN;
275                 }
276                 // fallthrough
277             case METRIC_IN:
278                 if (obj instanceof Iro) {
279                     builder.setIro((Iro) obj);
280                     return State.IRO_IN;
281                 }
282                 // fallthrough
283             case IRO_IN:
284             case END:
285                 return State.END;
286             default:
287                 return state;
288         }
289     }
290
291     private static State insertObject(final State state, final Object obj, final PathsBuilder builder,
292             final List<Metrics> pathMetrics) {
293         switch (state) {
294             case INIT:
295                 if (obj instanceof Lspa) {
296                     builder.setLspa((Lspa) obj);
297                     return State.LSPA_IN;
298                 }
299                 // fallthrough
300             case LSPA_IN:
301                 if (obj instanceof Of) {
302                     builder.setOf((Of) obj);
303                     return State.OF_IN;
304                 }
305                 // fallthrough
306             case OF_IN:
307                 if (obj instanceof Bandwidth) {
308                     builder.setBandwidth((Bandwidth) obj);
309                     return State.BANDWIDTH_IN;
310                 }
311                 // fallthrough
312             case BANDWIDTH_IN:
313                 if (obj instanceof Metric) {
314                     pathMetrics.add(new MetricsBuilder().setMetric((Metric) obj).build());
315                     return State.BANDWIDTH_IN;
316                 }
317                 // fallthrough
318             case METRIC_IN:
319                 if (obj instanceof Iro) {
320                     builder.setIro((Iro) obj);
321                     return State.IRO_IN;
322                 }
323                 // fallthrough
324             case IRO_IN:
325             case END:
326                 return State.END;
327             default:
328                 return state;
329         }
330     }
331
332     protected void parsePath(final PathsBuilder builder, final List<Object> objects) {
333         final List<Metrics> pathMetrics = new ArrayList<>();
334
335         Object obj;
336         State state = State.INIT;
337         while (!objects.isEmpty() && !state.equals(State.END)) {
338             obj = objects.get(0);
339             state = insertObject(state, obj, builder, pathMetrics);
340             if (!state.equals(State.END)) {
341                 objects.remove(0);
342             }
343         }
344         if (!pathMetrics.isEmpty()) {
345             builder.setMetrics(pathMetrics);
346         }
347     }
348
349     private enum State {
350         INIT, LSPA_IN, OF_IN, BANDWIDTH_IN, METRIC_IN, IRO_IN, END
351     }
352 }