Rework parser infrastructure to support partial message processing
[bgpcep.git] / pcep / impl / src / main / java / org / opendaylight / protocol / pcep / impl / 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.impl.message;
9
10 import io.netty.buffer.ByteBuf;
11
12 import java.util.List;
13
14 import org.opendaylight.protocol.pcep.PCEPDocumentedException;
15 import org.opendaylight.protocol.pcep.PCEPErrors;
16 import org.opendaylight.protocol.pcep.UnknownObject;
17 import org.opendaylight.protocol.pcep.spi.ObjectHandlerRegistry;
18 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.message.rev131007.Pcrep;
19 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.message.rev131007.PcrepBuilder;
20 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev131005.Message;
21 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev131005.Object;
22 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev131005.PcrepMessage;
23 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev131005.bandwidth.object.Bandwidth;
24 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev131005.explicit.route.object.Ero;
25 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev131005.include.route.object.Iro;
26 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev131005.lsp.attributes.Metrics;
27 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev131005.lsp.attributes.MetricsBuilder;
28 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev131005.lspa.object.Lspa;
29 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev131005.metric.object.Metric;
30 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev131005.of.object.Of;
31 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev131005.pcrep.message.PcrepMessageBuilder;
32 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev131005.pcrep.message.pcrep.message.Replies;
33 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev131005.pcrep.message.pcrep.message.RepliesBuilder;
34 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev131005.pcrep.message.pcrep.message.replies.Result;
35 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev131005.pcrep.message.pcrep.message.replies.result.Failure;
36 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev131005.pcrep.message.pcrep.message.replies.result.FailureBuilder;
37 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev131005.pcrep.message.pcrep.message.replies.result.Success;
38 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev131005.pcrep.message.pcrep.message.replies.result.SuccessBuilder;
39 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev131005.pcrep.message.pcrep.message.replies.result.failure.NoPath;
40 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev131005.pcrep.message.pcrep.message.replies.result.success.Paths;
41 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev131005.pcrep.message.pcrep.message.replies.result.success.PathsBuilder;
42 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev131005.rp.object.Rp;
43
44 import com.google.common.collect.Lists;
45
46 /**
47  * Parser for {@link PcrepMessage}
48  */
49 public class PCEPReplyMessageParser extends AbstractMessageParser {
50
51         public static final int TYPE = 4;
52
53         public PCEPReplyMessageParser(final ObjectHandlerRegistry registry) {
54                 super(registry);
55         }
56
57         @Override
58         public void serializeMessage(final Message message, final ByteBuf buffer) {
59                 if (!(message instanceof Pcrep)) {
60                         throw new IllegalArgumentException("Wrong instance of Message. Passed instance of " + message.getClass()
61                                         + ". Nedded PcrepMessage.");
62                 }
63                 final org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev131005.pcrep.message.PcrepMessage repMsg = ((Pcrep) message).getPcrepMessage();
64                 if (repMsg.getReplies() == null || repMsg.getReplies().isEmpty()) {
65                         throw new IllegalArgumentException("Replies cannot be null or empty.");
66                 }
67                 for (final Replies reply : repMsg.getReplies()) {
68                         if (reply.getRp() == null) {
69                                 throw new IllegalArgumentException("Reply must contain RP object.");
70                         }
71                         buffer.writeBytes(serializeObject(reply.getRp()));
72                         if (reply.getResult() != null) {
73                                 if (reply.getResult() instanceof Failure) {
74                                         final Failure f = (Failure) reply.getResult();
75                                         buffer.writeBytes(serializeObject(f.getNoPath()));
76                                         if (f.getLspa() != null) {
77                                                 buffer.writeBytes(serializeObject(f.getLspa()));
78                                         }
79                                         if (f.getBandwidth() != null) {
80                                                 buffer.writeBytes(serializeObject(f.getBandwidth()));
81                                         }
82                                         if (f.getMetrics() != null && !f.getMetrics().isEmpty()) {
83                                                 for (final Metrics m : f.getMetrics()) {
84                                                         buffer.writeBytes(serializeObject(m.getMetric()));
85                                                 }
86                                         }
87                                         if (f.getIro() != null) {
88                                                 buffer.writeBytes(serializeObject(f.getIro()));
89                                         }
90                                 } else {
91                                         final Success s = (Success) reply.getResult();
92                                         for (final Paths p : s.getPaths()) {
93                                                 buffer.writeBytes(serializeObject(p.getEro()));
94                                                 if (p.getLspa() != null) {
95                                                         buffer.writeBytes(serializeObject(p.getLspa()));
96                                                 }
97                                                 if (p.getOf() != null) {
98                                                         buffer.writeBytes(serializeObject(p.getOf()));
99                                                 }
100                                                 if (p.getBandwidth() != null) {
101                                                         buffer.writeBytes(serializeObject(p.getBandwidth()));
102                                                 }
103                                                 if (p.getMetrics() != null && !p.getMetrics().isEmpty()) {
104                                                         for (final Metrics m : p.getMetrics()) {
105                                                                 buffer.writeBytes(serializeObject(m.getMetric()));
106                                                         }
107                                                 }
108                                                 if (p.getIro() != null) {
109                                                         buffer.writeBytes(serializeObject(p.getIro()));
110                                                 }
111                                         }
112                                 }
113                         }
114                 }
115         }
116
117         @Override
118         protected Pcrep validate(final List<Object> objects, final List<Message> errors) throws PCEPDocumentedException {
119                 final List<Replies> replies = Lists.newArrayList();
120                 while (!objects.isEmpty()) {
121                         replies.add(this.getValidReply(objects));
122                 }
123                 return new PcrepBuilder().setPcrepMessage(new PcrepMessageBuilder().setReplies(replies).build()).build();
124         }
125
126         private Replies getValidReply(final List<Object> objects) throws PCEPDocumentedException {
127                 if (!(objects.get(0) instanceof Rp)) {
128                         throw new PCEPDocumentedException("Pcrep message must contain at least one RP object.", PCEPErrors.RP_MISSING);
129                 }
130                 final Rp rp = (Rp) objects.get(0);
131                 objects.remove(0);
132                 Result res = null;
133                 if (!objects.isEmpty()) {
134                         if (objects.get(0) instanceof NoPath) {
135                                 final NoPath noPath = (NoPath) objects.get(0);
136                                 objects.remove(0);
137                                 final FailureBuilder builder = new FailureBuilder();
138                                 builder.setNoPath(noPath);
139                                 while (!objects.isEmpty()) {
140                                         this.parseAttributes(builder, objects);
141                                 }
142                                 res = builder.build();
143                         } else if (objects.get(0) instanceof Ero) {
144                                 final Ero ero = (Ero) objects.get(0);
145                                 objects.remove(0);
146                                 final SuccessBuilder builder = new SuccessBuilder();
147                                 final List<Paths> paths = Lists.newArrayList();
148                                 final PathsBuilder pBuilder = new PathsBuilder();
149                                 pBuilder.setEro(ero);
150                                 while (!objects.isEmpty()) {
151                                         this.parsePath(pBuilder, objects);
152                                         paths.add(pBuilder.build());
153                                 }
154                                 builder.setPaths(paths);
155                                 res = builder.build();
156                         }
157                 }
158                 return new RepliesBuilder().setRp(rp).setResult(res).build();
159         }
160
161         private void parseAttributes(final FailureBuilder builder, final List<Object> objects) throws PCEPDocumentedException {
162                 final List<Metrics> pathMetrics = Lists.newArrayList();
163
164                 Object obj;
165                 State state = State.Init;
166                 while (!objects.isEmpty() && !state.equals(State.End)) {
167                         obj = objects.get(0);
168
169                         switch (state) {
170                         case Init:
171                                 state = State.LspaIn;
172                                 if (obj instanceof Lspa) {
173                                         builder.setLspa((Lspa) obj);
174                                         break;
175                                 }
176                         case LspaIn:
177                                 state = State.BandwidthIn;
178                                 if (obj instanceof Bandwidth) {
179                                         builder.setBandwidth((Bandwidth) obj);
180                                         break;
181                                 }
182                         case BandwidthIn:
183                                 state = State.MetricIn;
184                                 if (obj instanceof Metric) {
185                                         pathMetrics.add(new MetricsBuilder().setMetric((Metric) obj).build());
186                                         state = State.MetricIn;
187                                         break;
188                                 }
189                         case MetricIn:
190                                 state = State.IroIn;
191                                 if (obj instanceof Iro) {
192                                         builder.setIro((Iro) obj);
193                                         break;
194                                 }
195                         case IroIn:
196                                 state = State.End;
197                                 break;
198                         case End:
199                                 break;
200                         default:
201                                 throw new PCEPDocumentedException("Unknown object", ((UnknownObject) obj).getError());
202                         }
203                         if (!state.equals(State.End)) {
204                                 objects.remove(0);
205                         }
206                 }
207                 builder.setMetrics(pathMetrics);
208         }
209
210         private void parsePath(final PathsBuilder builder, final List<Object> objects) throws PCEPDocumentedException {
211                 final List<Metrics> pathMetrics = Lists.newArrayList();
212
213                 Object obj;
214                 State state = State.Init;
215                 while (!objects.isEmpty() && !state.equals(State.End)) {
216                         obj = objects.get(0);
217
218                         switch (state) {
219                         case Init:
220                                 state = State.LspaIn;
221                                 if (obj instanceof Lspa) {
222                                         builder.setLspa((Lspa) obj);
223                                         break;
224                                 }
225                         case LspaIn:
226                                 state = State.OfIn;
227                                 if (obj instanceof Of) {
228                                         builder.setOf((Of) obj);
229                                         break;
230                                 }
231                         case OfIn:
232                                 state = State.BandwidthIn;
233                                 if (obj instanceof Bandwidth) {
234                                         builder.setBandwidth((Bandwidth) obj);
235                                         break;
236                                 }
237                         case BandwidthIn:
238                                 state = State.MetricIn;
239                                 if (obj instanceof Metric) {
240                                         pathMetrics.add(new MetricsBuilder().setMetric((Metric) obj).build());
241                                         state = State.BandwidthIn;
242                                         break;
243                                 }
244                         case MetricIn:
245                                 state = State.IroIn;
246                                 if (obj instanceof Iro) {
247                                         builder.setIro((Iro) obj);
248                                         break;
249                                 }
250                         case IroIn:
251                                 state = State.End;
252                                 break;
253                         case End:
254                                 break;
255                         default:
256                                 throw new PCEPDocumentedException("Unknown object", ((UnknownObject) obj).getError());
257                         }
258                         if (!state.equals(State.End)) {
259                                 objects.remove(0);
260                         }
261                 }
262                 builder.setMetrics(pathMetrics);
263         }
264
265         private enum State {
266                 Init, LspaIn, OfIn, BandwidthIn, MetricIn, IroIn, End
267         }
268
269         @Override
270         public int getMessageType() {
271                 return TYPE;
272         }
273 }