Move pcep base parser Activator to its own bundle
[bgpcep.git] / pcep / base-parser / src / main / java / org / opendaylight / protocol / pcep / parser / message / PCEPRequestMessageParser.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.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.Pcreq;
23 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.message.rev131007.PcreqBuilder;
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.classtype.object.ClassType;
28 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev131005.endpoints.object.EndpointsObj;
29 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev131005.exclude.route.object.Xro;
30 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev131005.gc.object.Gc;
31 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev131005.include.route.object.Iro;
32 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev131005.load.balancing.object.LoadBalancing;
33 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev131005.lsp.attributes.Metrics;
34 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev131005.lsp.attributes.MetricsBuilder;
35 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev131005.lspa.object.Lspa;
36 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev131005.metric.object.Metric;
37 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev131005.monitoring.object.Monitoring;
38 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev131005.of.object.Of;
39 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev131005.path.key.object.PathKey;
40 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev131005.pcc.id.req.object.PccIdReq;
41 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev131005.pce.id.object.PceId;
42 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev131005.pcreq.message.PcreqMessage;
43 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev131005.pcreq.message.PcreqMessageBuilder;
44 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev131005.pcreq.message.pcreq.message.MonitoringRequest;
45 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev131005.pcreq.message.pcreq.message.MonitoringRequestBuilder;
46 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev131005.pcreq.message.pcreq.message.Requests;
47 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev131005.pcreq.message.pcreq.message.RequestsBuilder;
48 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev131005.pcreq.message.pcreq.message.Svec;
49 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev131005.pcreq.message.pcreq.message.SvecBuilder;
50 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev131005.pcreq.message.pcreq.message.monitoring.request.PceIdList;
51 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev131005.pcreq.message.pcreq.message.monitoring.request.PceIdListBuilder;
52 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev131005.pcreq.message.pcreq.message.requests.PathKeyExpansionBuilder;
53 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev131005.pcreq.message.pcreq.message.requests.SegmentComputation;
54 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev131005.pcreq.message.pcreq.message.requests.SegmentComputationBuilder;
55 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev131005.pcreq.message.pcreq.message.requests.segment.computation.P2p;
56 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev131005.pcreq.message.pcreq.message.requests.segment.computation.P2pBuilder;
57 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev131005.pcreq.message.pcreq.message.requests.segment.computation.p2p.ReportedRoute;
58 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev131005.pcreq.message.pcreq.message.requests.segment.computation.p2p.ReportedRouteBuilder;
59 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev131005.reported.route.object.Rro;
60 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev131005.rp.object.Rp;
61 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev131005.vendor.information.objects.VendorInformationObject;
62
63 /**
64  * Parser for {@link Pcreq}
65  */
66 public class PCEPRequestMessageParser extends AbstractMessageParser {
67
68     public static final int TYPE = 3;
69
70     public PCEPRequestMessageParser(final ObjectRegistry registry, final VendorInformationObjectRegistry viRegistry) {
71         super(registry, viRegistry);
72     }
73
74     @Override
75     public void serializeMessage(final Message message, final ByteBuf out) {
76         Preconditions.checkArgument(message instanceof Pcreq, "Wrong instance of Message. Passed instance of %s. Need Pcreq.", message.getClass());
77         final PcreqMessage msg = ((Pcreq) message).getPcreqMessage();
78         Preconditions.checkArgument(msg.getRequests() != null && !msg.getRequests().isEmpty(), "Requests cannot be null or empty.");
79         final ByteBuf buffer = Unpooled.buffer();
80         if (msg.getMonitoringRequest() != null) {
81             serializeMonitoringRequest(msg.getMonitoringRequest(), buffer);
82         }
83         if (msg.getSvec() != null) {
84             serializeSvec(msg, buffer);
85         }
86         serializeRequest(msg, buffer);
87         MessageUtil.formatMessage(TYPE, buffer, out);
88     }
89
90     protected void serializeRequest(final PcreqMessage msg, final ByteBuf buffer) {
91         for (final Requests req : msg.getRequests()) {
92             serializeObject(req.getRp(), buffer);
93             serializeVendorInformationObjects(req.getVendorInformationObject(), buffer);
94             if (req.getPathKeyExpansion() != null) {
95                 serializeObject(req.getPathKeyExpansion().getPathKey(), buffer);
96             }
97             if (req.getSegmentComputation() != null) {
98                 final SegmentComputation sc = req.getSegmentComputation();
99                 if (sc.getP2p() != null) {
100                     serializeP2P(buffer, sc.getP2p());
101                 }
102             }
103         }
104     }
105
106     protected void serializeSvec(final PcreqMessage msg, final ByteBuf buffer) {
107         for (final Svec s : msg.getSvec()) {
108             serializeObject(s.getSvec(), buffer);
109             serializeObject(s.getOf(), buffer);
110             serializeObject(s.getGc(), buffer);
111             serializeObject(s.getXro(), buffer);
112             if (s.getMetric() != null) {
113                 for (final org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev131005.pcreq.message.pcreq.message.svec.Metric m : s.getMetric()) {
114                     serializeObject(m.getMetric(), buffer);
115                 }
116             }
117             serializeVendorInformationObjects(s.getVendorInformationObject(), buffer);
118         }
119     }
120
121     protected void serializeP2P(final ByteBuf buffer, final P2p p2p) {
122         serializeObject(p2p.getEndpointsObj(), buffer);
123         serializeVendorInformationObjects(p2p.getVendorInformationObject(), buffer);
124         if (p2p.getReportedRoute() != null) {
125             final ReportedRoute rr = p2p.getReportedRoute();
126             if (rr != null) {
127                 serializeObject(rr.getRro(), buffer);
128                 serializeObject(rr.getBandwidth(), buffer);
129             }
130         }
131         serializeObject(p2p.getLoadBalancing(), buffer);
132         serializeObject(p2p.getLspa(), buffer);
133         serializeObject(p2p.getBandwidth(), buffer);
134         if (p2p.getMetrics() != null) {
135             for (final Metrics m : p2p.getMetrics()) {
136                 serializeObject(m.getMetric(), buffer);
137             }
138         }
139         serializeObject(p2p.getIro(), buffer);
140         serializeObject(p2p.getRro(), buffer);
141         serializeObject(p2p.getXro(), buffer);
142         serializeObject(p2p.getOf(), buffer);
143         serializeObject(p2p.getClassType(), buffer);
144     }
145
146     protected void serializeMonitoringRequest(final MonitoringRequest monReq, final ByteBuf out) {
147         serializeObject(monReq.getMonitoring(), out);
148         serializeObject(monReq.getPccIdReq(), out);
149         if (monReq.getPceIdList() != null) {
150             for (final PceIdList pceId : monReq.getPceIdList()) {
151                 serializeObject(pceId.getPceId(), out);
152             }
153         }
154     }
155
156     @Override
157     protected Message validate(final List<Object> objects, final List<Message> errors) throws PCEPDeserializerException {
158         Preconditions.checkArgument(objects != null, "Passed list can't be null.");
159         if (objects.isEmpty()) {
160             throw new PCEPDeserializerException("Pcrep message cannot be empty.");
161         }
162         final PcreqMessageBuilder mBuilder = new PcreqMessageBuilder();
163         mBuilder.setMonitoringRequest(getMonitoring(objects));
164         final List<Svec> svecs = getSvecs(objects, errors);
165         if (!svecs.isEmpty()) {
166             mBuilder.setSvec(svecs);
167         }
168         final List<Requests> requests = getRequests(objects, errors);
169         if (requests != null) {
170             mBuilder.setRequests(requests);
171         } else {
172             errors.add(createErrorMsg(PCEPErrors.RP_MISSING, Optional.<Rp>absent()));
173         }
174         if (!objects.isEmpty()) {
175             throw new PCEPDeserializerException("Unprocessed Objects: " + objects);
176         }
177         return new PcreqBuilder().setPcreqMessage(mBuilder.build()).build();
178     }
179
180     protected List<Svec> getSvecs(final List<Object> objects, final List<Message> errors) {
181         final List<Svec> svecList = new ArrayList<>();
182         while (!objects.isEmpty()) {
183             final SvecBuilder sBuilder = new SvecBuilder();
184             final Svec svecComp = getValidSvec(sBuilder, objects);
185             if (svecComp == null) {
186                 break;
187             }
188             svecList.add(svecComp);
189         }
190         return svecList;
191     }
192
193     protected List<Requests> getRequests(final List<Object> objects, final List<Message> errors) {
194         final List<Requests> requests = new ArrayList<>();
195         while (!objects.isEmpty()) {
196             final RequestsBuilder rBuilder = new RequestsBuilder();
197             Rp rpObj = null;
198             if (!(objects.get(0) instanceof Rp)) {
199                 // if RP obj is missing return error only
200                 errors.add(createErrorMsg(PCEPErrors.RP_MISSING, Optional.<Rp>absent()));
201                 return null;
202             }
203             rpObj = (Rp) objects.get(0);
204             objects.remove(0);
205             if (!rpObj.isProcessingRule()) {
206                 errors.add(createErrorMsg(PCEPErrors.P_FLAG_NOT_SET, Optional.<Rp>absent()));
207             } else {
208                 rBuilder.setRp(rpObj);
209             }
210             final List<VendorInformationObject> vendorInfo = addVendorInformationObjects(objects);
211             if (!vendorInfo.isEmpty()) {
212                 rBuilder.setVendorInformationObject(vendorInfo);
213             }
214             // expansion
215             if (rpObj.isPathKey() && objects.get(0) instanceof PathKey) {
216                 rBuilder.setPathKeyExpansion(new PathKeyExpansionBuilder().setPathKey((PathKey) objects.get(0)).build());
217             }
218
219             final P2pBuilder p2pBuilder = new P2pBuilder();
220
221             if (!objects.isEmpty() && objects.get(0) instanceof EndpointsObj) {
222                 final EndpointsObj ep = (EndpointsObj) objects.get(0);
223                 objects.remove(0);
224                 if (!ep.isProcessingRule()) {
225                     errors.add(createErrorMsg(PCEPErrors.P_FLAG_NOT_SET, Optional.of(rpObj)));
226                 } else {
227                     p2pBuilder.setEndpointsObj(ep);
228                 }
229             } else {
230                 errors.add(createErrorMsg(PCEPErrors.END_POINTS_MISSING, Optional.of(rpObj)));
231                 return null;
232             }
233             // p2p
234             if (!rpObj.isP2mp()) {
235                 final SegmentComputation segm = getSegmentComputation(p2pBuilder, objects, errors, rpObj);
236                 if (segm != null) {
237                     rBuilder.setSegmentComputation(segm);
238                 }
239             }
240             requests.add(rBuilder.build());
241         }
242         return requests;
243     }
244
245     protected SegmentComputation getSegmentComputation(final P2pBuilder builder, final List<Object> objects, final List<Message> errors,
246             final Rp rp) {
247         final List<Metrics> metrics = new ArrayList<>();
248         final List<VendorInformationObject> viObjects = new ArrayList<>();
249
250         State state = State.INIT;
251         while (!objects.isEmpty() && state != State.END) {
252             state = insertObject(state, objects, viObjects, builder, metrics, errors, rp);
253             if (!state.equals(State.END)) {
254                 objects.remove(0);
255             }
256         }
257         if (!metrics.isEmpty()) {
258             builder.setMetrics(metrics);
259         }
260         if (!viObjects.isEmpty()) {
261             builder.setVendorInformationObject(viObjects);
262         }
263
264         if (rp.isReoptimization()
265                 && builder.getBandwidth() != null
266                 && !builder.getReportedRoute().getBandwidth().getBandwidth().equals(
267                         new org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.network.concepts.rev131125.Bandwidth(new byte[] { 0 }))
268                 && builder.getReportedRoute().getRro() == null) {
269             errors.add(createErrorMsg(PCEPErrors.RRO_MISSING, Optional.of(rp)));
270             return null;
271         }
272         return new SegmentComputationBuilder().setP2p(builder.build()).build();
273     }
274
275     private State insertObject(final State state, final List<Object> objects, final List<VendorInformationObject> viObjects, final P2pBuilder builder, final List<Metrics> metrics, final List<Message> errors, final Rp rp) {
276         final Object obj = objects.get(0);
277         switch (state) {
278         case INIT:
279             if (obj instanceof Rro) {
280                 final ReportedRouteBuilder rrBuilder = new ReportedRouteBuilder();
281                 rrBuilder.setRro((Rro) obj);
282                 objects.remove(0);
283                 final Object nextObj = objects.get(0);
284                 if (nextObj instanceof org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev131005.reoptimization.bandwidth.object.Bandwidth) {
285                     rrBuilder.setBandwidth((org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev131005.reoptimization.bandwidth.object.Bandwidth) nextObj);
286                 }
287                 return State.REPORTED_IN;
288             }
289         case REPORTED_IN:
290             if (obj instanceof VendorInformationObject) {
291                 viObjects.add((VendorInformationObject) obj);
292                 return State.REPORTED_IN;
293             }
294         case VENDOR_INFO_LIST:
295             if (obj instanceof LoadBalancing) {
296                 builder.setLoadBalancing((LoadBalancing) obj);
297                 return State.LOAD_BIN;
298             }
299         case LOAD_BIN:
300             if (obj instanceof Lspa) {
301                 builder.setLspa((Lspa) obj);
302                 return State.LSPA_IN;
303             }
304         case LSPA_IN:
305             if (obj instanceof Bandwidth) {
306                 builder.setBandwidth((Bandwidth) obj);
307                 return State.BANDWIDTH_IN;
308             }
309         case BANDWIDTH_IN:
310             if (obj instanceof Metric) {
311                 metrics.add(new MetricsBuilder().setMetric((Metric) obj).build());
312                 return State.BANDWIDTH_IN;
313             }
314         case METRIC_IN:
315             if (obj instanceof Iro) {
316                 builder.setIro((Iro) obj);
317                 return State.IRO_IN;
318             }
319         case IRO_IN:
320             if (obj instanceof Rro) {
321                 builder.setRro((Rro) obj);
322                 return State.RRO_IN;
323             }
324         case RRO_IN:
325             if (obj instanceof Xro) {
326                 builder.setXro((Xro) obj);
327                 return State.XRO_IN;
328             }
329         case XRO_IN:
330             if (obj instanceof Of) {
331                 builder.setOf((Of) obj);
332                 return State.OF_IN;
333             }
334         case OF_IN:
335             if (obj instanceof ClassType) {
336                 final ClassType classType = (ClassType) obj;
337                 if (!classType.isProcessingRule()) {
338                     errors.add(createErrorMsg(PCEPErrors.P_FLAG_NOT_SET, Optional.of(rp)));
339                 } else {
340                     builder.setClassType(classType);
341                 }
342                 return State.CT_IN;
343             }
344         case CT_IN:
345         case END:
346             return State.END;
347         default:
348             return state;
349         }
350     }
351
352     private enum State {
353         INIT, REPORTED_IN, VENDOR_INFO_LIST, LOAD_BIN, LSPA_IN, BANDWIDTH_IN, METRIC_IN, IRO_IN, RRO_IN, XRO_IN, OF_IN, CT_IN, END
354     }
355
356     private Svec getValidSvec(final SvecBuilder builder, final List<Object> objects) {
357         Preconditions.checkArgument(objects != null && !objects.isEmpty(), "Passed list can't be null or empty.");
358
359         if (objects.get(0) instanceof org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev131005.svec.object.Svec) {
360             builder.setSvec((org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev131005.svec.object.Svec) objects.get(0));
361             objects.remove(0);
362         } else {
363             return null;
364         }
365
366         final List<Metrics> metrics = new ArrayList<>();
367         final List<VendorInformationObject> viObjects = new ArrayList<>();
368
369         Object obj = null;
370         SvecState state = SvecState.INIT;
371         while (!objects.isEmpty() && !state.equals(SvecState.END)) {
372             obj = objects.get(0);
373             state = insertObject(state, obj, builder, metrics, viObjects);
374             if (!state.equals(SvecState.END)) {
375                 objects.remove(0);
376             }
377         }
378         if (!viObjects.isEmpty()) {
379             builder.setVendorInformationObject(viObjects);
380         }
381         return builder.build();
382     }
383
384     private SvecState insertObject(final SvecState state, final Object obj, final SvecBuilder builder, final List<Metrics> metrics, final List<VendorInformationObject> viObjects) {
385         switch (state) {
386         case INIT:
387             if (obj instanceof Of) {
388                 builder.setOf((Of) obj);
389                 return SvecState.OF_IN;
390             }
391         case OF_IN:
392             if (obj instanceof Gc) {
393                 builder.setGc((Gc) obj);
394                 return SvecState.GC_IN;
395             }
396         case GC_IN:
397             if (obj instanceof Xro) {
398                 builder.setXro((Xro) obj);
399                 return SvecState.XRO_IN;
400             }
401         case XRO_IN:
402             if (obj instanceof Metric) {
403                 metrics.add(new MetricsBuilder().setMetric((Metric) obj).build());
404                 return SvecState.XRO_IN;
405             }
406         case METRIC_IN:
407             if (obj instanceof VendorInformationObject) {
408                 viObjects.add((VendorInformationObject) obj);
409                 return SvecState.METRIC_IN;
410             }
411         case VENDOR_INFO:
412         case END:
413             return SvecState.END;
414         default:
415             return state;
416         }
417     }
418
419     private enum SvecState {
420         INIT, OF_IN, GC_IN, XRO_IN, METRIC_IN, VENDOR_INFO, END
421     }
422
423     protected MonitoringRequest getMonitoring(final List<Object> objects) {
424         final MonitoringRequestBuilder builder = new MonitoringRequestBuilder();
425         if (!objects.isEmpty() && objects.get(0) instanceof Monitoring) {
426             builder.setMonitoring((Monitoring) objects.get(0));
427             objects.remove(0);
428         } else {
429             return null;
430         }
431         if (!objects.isEmpty() && objects.get(0) instanceof PccIdReq) {
432             builder.setPccIdReq((PccIdReq) objects.get(0));
433             objects.remove(0);
434         }
435         final List<PceIdList> pceIdList = new ArrayList<>();
436         while(!objects.isEmpty() && objects.get(0) instanceof PceId) {
437             pceIdList.add(new PceIdListBuilder().setPceId((PceId) objects.get(0)).build());
438             objects.remove(0);
439         }
440         if (!pceIdList.isEmpty()) {
441             builder.setPceIdList(pceIdList);
442         }
443         return builder.build();
444     }
445 }