Improve InitiatedPCInitiateMessageParser diagnostics
[bgpcep.git] / pcep / ietf-stateful / src / main / java / org / opendaylight / protocol / pcep / ietf / initiated / InitiatedPCInitiateMessageParser.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.ietf.initiated;
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.NoSuchElementException;
17 import java.util.Queue;
18 import org.opendaylight.protocol.pcep.spi.AbstractMessageParser;
19 import org.opendaylight.protocol.pcep.spi.MessageUtil;
20 import org.opendaylight.protocol.pcep.spi.ObjectRegistry;
21 import org.opendaylight.protocol.pcep.spi.PCEPDeserializerException;
22 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.initiated.rev200720.Pcinitiate;
23 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.initiated.rev200720.PcinitiateBuilder;
24 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.initiated.rev200720.pcinitiate.message.PcinitiateMessageBuilder;
25 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.initiated.rev200720.pcinitiate.message.pcinitiate.message.Requests;
26 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.initiated.rev200720.pcinitiate.message.pcinitiate.message.RequestsBuilder;
27 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.stateful.rev200720.lsp.object.Lsp;
28 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.stateful.rev200720.srp.object.Srp;
29 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev181109.Message;
30 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev181109.Object;
31 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev181109.bandwidth.object.Bandwidth;
32 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev181109.endpoints.object.EndpointsObj;
33 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev181109.explicit.route.object.Ero;
34 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev181109.include.route.object.Iro;
35 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev181109.lsp.attributes.Metrics;
36 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev181109.lsp.attributes.MetricsBuilder;
37 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev181109.lspa.object.Lspa;
38 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev181109.metric.object.Metric;
39
40 /**
41  * Parser for {@link Pcinitiate}.
42  */
43 public class InitiatedPCInitiateMessageParser extends AbstractMessageParser {
44
45     public static final int TYPE = 12;
46
47     public InitiatedPCInitiateMessageParser(final ObjectRegistry registry) {
48         super(registry);
49     }
50
51     @Override
52     public void serializeMessage(final Message message, final ByteBuf out) {
53         checkArgument(message instanceof Pcinitiate,
54             "Wrong instance of Message. Passed instance of %s. Need PcinitiateMessage.", message.getClass());
55         final org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.initiated.rev200720
56             .pcinitiate.message.PcinitiateMessage init = ((Pcinitiate) message).getPcinitiateMessage();
57         final ByteBuf buffer = Unpooled.buffer();
58         for (final Requests req : init.getRequests()) {
59             serializeRequest(req, buffer);
60         }
61         MessageUtil.formatMessage(TYPE, buffer, out);
62     }
63
64     protected void serializeRequest(final Requests req, final ByteBuf buffer) {
65         serializeObject(req.getSrp(), buffer);
66         serializeObject(req.getLsp(), buffer);
67         serializeObject(req.getEndpointsObj(), buffer);
68         serializeObject(req.getEro(), buffer);
69         serializeObject(req.getLspa(), buffer);
70         serializeObject(req.getBandwidth(), buffer);
71         for (final Metrics m : req.nonnullMetrics()) {
72             serializeObject(m.getMetric(), buffer);
73         }
74         serializeObject(req.getIro(), buffer);
75     }
76
77     @Override
78     protected Message validate(final Queue<Object> objects, final List<Message> errors)
79             throws PCEPDeserializerException {
80         checkArgument(objects != null, "Passed list can't be null.");
81         final PcinitiateMessageBuilder builder = new PcinitiateMessageBuilder();
82         final List<Requests> reqs = new ArrayList<>();
83         while (!objects.isEmpty()) {
84             reqs.add(this.getValidRequest(objects));
85         }
86         builder.setRequests(reqs);
87         return new PcinitiateBuilder().setPcinitiateMessage(builder.build()).build();
88     }
89
90     protected Requests getValidRequest(final Queue<Object> objects) throws PCEPDeserializerException {
91         final RequestsBuilder builder = new RequestsBuilder()
92             .setSrp(consumeObject(objects, Srp.class))
93             .setLsp(consumeObject(objects, Lsp.class));
94
95         final List<Metrics> metrics = new ArrayList<>();
96         State state = State.INIT;
97         for (Object obj = objects.peek(); obj != null; obj = objects.peek()) {
98             state = insertObject(state, obj, builder, metrics);
99             if (state == State.END) {
100                 break;
101             }
102
103             objects.remove();
104         }
105
106         builder.setMetrics(metrics);
107         return builder.build();
108     }
109
110     private static <T extends Object> T consumeObject(final Queue<Object> objects, final Class<T> expectedClass)
111             throws PCEPDeserializerException {
112         final Object obj;
113         try {
114             obj = objects.remove();
115         } catch (NoSuchElementException e) {
116             throw new PCEPDeserializerException("No objects left when expecting " + expectedClass.getSimpleName(), e);
117         }
118         try {
119             return expectedClass.cast(obj);
120         } catch (ClassCastException e) {
121             throw new PCEPDeserializerException("Cannot interpret " + obj, e);
122         }
123     }
124
125     private static State insertObject(final State state, final Object obj, final RequestsBuilder builder,
126             final List<Metrics> metrics) {
127         switch (state) {
128             case INIT:
129                 if (obj instanceof EndpointsObj) {
130                     builder.setEndpointsObj((EndpointsObj) obj);
131                     return State.ENDPOINTS_IN;
132                 }
133                 // fall through
134             case ENDPOINTS_IN:
135                 if (obj instanceof Ero) {
136                     builder.setEro((Ero) obj);
137                     return State.ERO_IN;
138                 }
139                 // fall through
140             case ERO_IN:
141                 if (obj instanceof Lspa) {
142                     builder.setLspa((Lspa) obj);
143                     return State.LSPA_IN;
144                 }
145                 // fall through
146             case LSPA_IN:
147                 if (obj instanceof Bandwidth) {
148                     builder.setBandwidth((Bandwidth) obj);
149                     return State.BANDWIDTH_IN;
150                 }
151                 // fall through
152             case BANDWIDTH_IN:
153                 if (obj instanceof Metric) {
154                     metrics.add(new MetricsBuilder().setMetric((Metric) obj).build());
155                     return State.BANDWIDTH_IN;
156                 }
157                 // fall through
158             case METRIC_IN:
159                 if (obj instanceof Iro) {
160                     builder.setIro((Iro) obj);
161                     return State.IRO_IN;
162                 }
163                 // fall through
164             case IRO_IN:
165             case END:
166                 return State.END;
167             default:
168                 return state;
169         }
170     }
171
172     private enum State {
173         INIT, ENDPOINTS_IN, ERO_IN, LSPA_IN, BANDWIDTH_IN, METRIC_IN, IRO_IN, END
174     }
175 }