Fix to NPE during instantiation after moving the instantiation of the gateIidMap...
[packetcable.git] / packetcable-policy-server / src / main / java / org / opendaylight / controller / packetcable / provider / ValidateInstanceData.java
1 /**
2  * Validate all instance data received from the config datastore via the onDataChange() notification.
3  *
4  * N.B. that yang typedefs are not validated when a PUT operation places them into the config datastore.
5  * This means that they can arrive at onDataChange() with invalid values.
6  *
7  * In particular integer range values and string patterns (such as IP prefix/len) are not checked
8  * and accessing these values via any object.getValue() method call will cause an exception (as yang
9  * finally gets around to actually enforcing the typedef).
10  */
11 package org.opendaylight.controller.packetcable.provider;
12
13 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
14 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.*;
15 import org.opendaylight.yang.gen.v1.urn.packetcable.rev150327.ServiceClassName;
16 import org.opendaylight.yang.gen.v1.urn.packetcable.rev150327.ServiceFlowDirection;
17 import org.opendaylight.yang.gen.v1.urn.packetcable.rev150327.TosByte;
18 import org.opendaylight.yang.gen.v1.urn.packetcable.rev150327.TpProtocol;
19 import org.opendaylight.yang.gen.v1.urn.packetcable.rev150327.ccap.Ccaps;
20 import org.opendaylight.yang.gen.v1.urn.packetcable.rev150327.ccap.CcapsBuilder;
21 import org.opendaylight.yang.gen.v1.urn.packetcable.rev150327.ccap.attributes.AmId;
22 import org.opendaylight.yang.gen.v1.urn.packetcable.rev150327.ccap.attributes.AmIdBuilder;
23 import org.opendaylight.yang.gen.v1.urn.packetcable.rev150327.ccap.attributes.Connection;
24 import org.opendaylight.yang.gen.v1.urn.packetcable.rev150327.ccap.attributes.ConnectionBuilder;
25 import org.opendaylight.yang.gen.v1.urn.packetcable.rev150327.pcmm.qos.classifier.Classifier;
26 import org.opendaylight.yang.gen.v1.urn.packetcable.rev150327.pcmm.qos.classifier.ClassifierBuilder;
27 import org.opendaylight.yang.gen.v1.urn.packetcable.rev150327.pcmm.qos.ext.classifier.ExtClassifier;
28 import org.opendaylight.yang.gen.v1.urn.packetcable.rev150327.pcmm.qos.ext.classifier.ExtClassifierBuilder;
29 import org.opendaylight.yang.gen.v1.urn.packetcable.rev150327.pcmm.qos.gate.spec.GateSpec;
30 import org.opendaylight.yang.gen.v1.urn.packetcable.rev150327.pcmm.qos.gate.spec.GateSpecBuilder;
31 import org.opendaylight.yang.gen.v1.urn.packetcable.rev150327.pcmm.qos.gates.apps.subs.Gates;
32 import org.opendaylight.yang.gen.v1.urn.packetcable.rev150327.pcmm.qos.gates.apps.subs.GatesBuilder;
33 import org.opendaylight.yang.gen.v1.urn.packetcable.rev150327.pcmm.qos.ipv6.classifier.Ipv6Classifier;
34 import org.opendaylight.yang.gen.v1.urn.packetcable.rev150327.pcmm.qos.ipv6.classifier.Ipv6ClassifierBuilder;
35 import org.opendaylight.yang.gen.v1.urn.packetcable.rev150327.pcmm.qos.traffic.profile.TrafficProfile;
36 import org.opendaylight.yang.gen.v1.urn.packetcable.rev150327.pcmm.qos.traffic.profile.TrafficProfileBuilder;
37 import org.opendaylight.yangtools.yang.binding.DataObject;
38 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
39 import org.slf4j.Logger;
40 import org.slf4j.LoggerFactory;
41
42 import java.lang.reflect.Method;
43 import java.util.List;
44 import java.util.Map;
45 import java.util.concurrent.ConcurrentHashMap;
46 import java.util.concurrent.ExecutorService;
47 import java.util.concurrent.Executors;
48
49 public class ValidateInstanceData {
50
51         private final static Logger logger = LoggerFactory.getLogger(ValidateInstanceData.class);
52
53         // Final members
54         private final DataBroker dataBroker;
55         private final ExecutorService executor;
56
57         // Gate Identities
58         private final Map<InstanceIdentifier<Gates>, Gates> gateIidMap;
59
60         // CCAP Identity
61         private transient Ccaps ccap;
62         private transient InstanceIdentifier<Ccaps> ccapIID;
63
64         public ValidateInstanceData(final DataBroker dataBroker, final Map<InstanceIdentifier<?>, DataObject> thisData) {
65                 executor = Executors.newCachedThreadPool();
66                 this.dataBroker = dataBroker;
67                 getCcap(thisData);
68
69                 // Must be instantiated prior to retreiving the gates below
70                 gateIidMap = new ConcurrentHashMap<>();
71
72                 // TODO FIXME - this value is always null???
73                 if (ccap == null) {
74                         getGates(thisData);
75                 }
76         }
77         public boolean isResponseEcho() {
78                 // see if there is a response object in the updated data
79                 // if so this is an echo of the response message insertion so our caller can exit right away
80                 if (ccap != null && ccap.getResponse() != null) {
81                         return true;
82                 } else if (! gateIidMap.isEmpty() && gateIidMap.values().iterator().next().getResponse() != null) {
83                         return true;
84                 }
85                 return false;
86         }
87         public boolean validateYang() {
88                 final String badText = "400 Bad Request - Invalid Element Values in json object - ";
89                 if (isResponseEcho()) {
90                         // don't validiate the echo again
91                         return true;
92                 }
93                 if (ccap != null) {
94                         Response response = new Response(dataBroker, ccapIID, ccap, badText);
95                         if (! validateCcap(ccap, response)) {
96                                 logger.error("Validate CCAP {} failed - {}", ccap.getCcapId(), response.getMessage());
97                                 executor.execute(response);
98                                 return false;
99                         }
100                 } else if (! gateIidMap.isEmpty()) {
101                         for (Map.Entry<InstanceIdentifier<Gates>, Gates> entry : gateIidMap.entrySet()) {
102                                 InstanceIdentifier<Gates> gateIID = entry.getKey();
103                                 Gates gate = entry.getValue();
104                                 Response response = new Response(dataBroker, gateIID, gate, badText);
105                                 if (! validateGate(gate, response)) {
106                                         logger.error("Validate Gate {} failed - {}", gate.getGateId(), response.getMessage());
107                                         executor.execute(response);
108                                         return false;
109                                 }
110                         }
111                 }
112                 return true;
113         }
114
115         private void getCcap(final Map<InstanceIdentifier<?>, DataObject> thisData) {
116                 for (final Map.Entry<InstanceIdentifier<?>, DataObject> entry : thisData.entrySet()) {
117                         if (entry.getValue() instanceof Ccaps) {
118                     ccap = (Ccaps)entry.getValue();
119                                 // TODO FIXME - ClassCastException waiting to occur here!!!
120                     ccapIID = (InstanceIdentifier<Ccaps>) entry.getKey();
121                 }
122             }
123         }
124
125         private void getGates(final Map<InstanceIdentifier<?>, DataObject> thisData) {
126                 for (final Map.Entry<InstanceIdentifier<?>, DataObject> entry : thisData.entrySet()) {
127                         if (entry.getValue() instanceof Gates) {
128                                 final Gates gate = (Gates)entry.getValue();
129                                 // TODO FIXME - ClassCastException waiting to occur here!!!
130                                 final InstanceIdentifier<Gates> gateIID = (InstanceIdentifier<Gates>)entry.getKey();
131                                 gateIidMap.put(gateIID, gate);
132                         }
133             }
134         }
135         private String validateMethod(final Class<?> thisClass, final Object thisObj, final String methodName) {
136                 try {
137                         final Method method = thisClass.getMethod(methodName);
138                         method.invoke(thisObj);
139                 } catch (IllegalArgumentException e) {
140                         return e.getMessage();
141                 } catch (Exception e) {
142                         return " ";
143 //                      error = String.format("%s.%s(): Method failed: %s ", thisClass.getSimpleName(), methodName, e.getMessage());
144                 }
145                 return null;
146         }
147
148         private boolean validateGateSpec(final Gates gate, final GatesBuilder gateBuilder, final Response response) {
149                 // gate-spec
150                 String message = "";
151                 String error;
152                 boolean valid = true;
153                 GateSpec gateSpec = gate.getGateSpec();
154                 if (gateSpec != null) {
155                         final ServiceFlowDirection dir;
156                         error = validateMethod(GateSpec.class, gateSpec, "getDirection");
157                         if (error == null) {
158                                 dir = gateSpec.getDirection();
159                                 if (dir != null) {
160                                         if (gate.getTrafficProfile().getServiceClassName() != null) {
161                                                 message += " gate-spec.direction not allowed for traffic-profile.SCN;";
162                                                 valid = false;
163                                         }
164                                 }
165                         } else {
166                                 message += " gate-spec.direction invalid: must be 'us' or 'ds' -" + error;
167                                 dir = null;
168                                 valid = false;
169                         }
170                         final TosByte tosByte;
171                         error = validateMethod(GateSpec.class, gateSpec, "getDscpTosOverwrite");
172                         if (error == null) {
173                                 tosByte = gateSpec.getDscpTosOverwrite();
174                         } else {
175                                 message += " gate-spec.dscp-tos-overwrite invalid: " + error;
176                                 tosByte = null;
177                                 valid = false;
178                         }
179                         final TosByte tosMask;
180                         error = validateMethod(GateSpec.class, gateSpec, "getDscpTosMask");
181                         if (error == null) {
182                                 tosMask = gateSpec.getDscpTosMask();
183                                 if (tosByte != null && tosMask == null) {
184                                         message += " gate-spec.dscp-tos-mask missing;";
185                                         valid = false;
186                                 }
187                         } else {
188                                 message += " gate-spec.dscp-tos-mask invalid: " + error;
189                                 tosMask = null;
190                                 valid = false;
191                         }
192                         if (! valid) {
193                                 // rebuild the gateSpec with nulls replacing bad values
194                                 final GateSpecBuilder gateSpecBuilder = new GateSpecBuilder();
195                                 gateSpecBuilder.setDirection(dir);
196                                 gateSpecBuilder.setDscpTosOverwrite(tosByte);
197                                 gateSpecBuilder.setDscpTosMask(tosMask);
198                                 gateSpec = gateSpecBuilder.build();
199                                 // update the gate
200                                 gateBuilder.setGateSpec(gateSpec);
201                         }
202                 }
203                 if (! valid) {
204                         response.addMessage(message);
205                 }
206                 return valid;
207         }
208
209         private boolean validateTrafficProfile(final Gates gate, final GatesBuilder gateBuilder, final Response response) {
210                 // traffic-profile
211                 String message = "";
212                 boolean valid = true;
213                 TrafficProfile profile = gate.getTrafficProfile();
214                 if (profile == null) {
215                         message += " traffic-profile is required;";
216                         valid = false;
217                 } else {
218                         final ServiceClassName scn;
219                         final String error = validateMethod(TrafficProfile.class, profile, "getServiceClassName");
220                         if (error == null) {
221                                 scn = profile.getServiceClassName();
222                                 if (scn == null) {
223                                         message += " traffic-profile.service-class-name missing;";
224                                         valid = false;
225                                 }
226                         } else {
227                                 message += " traffic-profile.service-class-name invalid: must be 2-16 characters " + error;
228                                 scn = null;
229                                 valid = false;
230                         }
231                         if (! valid) {
232                                 final TrafficProfileBuilder profileBuilder = new TrafficProfileBuilder();
233                                 // TODO FIXME - scn is always null???
234                                 profileBuilder.setServiceClassName(scn);
235                                 profile = profileBuilder.build();
236                                 // update the gate
237                                 gateBuilder.setTrafficProfile(profile);
238                         }
239                 }
240                 if (! valid) {
241                         response.addMessage(message);
242                 }
243                 return valid;
244         }
245
246         // TODO FIXME - Break this method apart
247         private boolean validateClassifier(final Gates gate, final GatesBuilder gateBuilder, final Response response) {
248                 // validate classifier
249                 String message = "";
250                 boolean valid = true;
251                 int count = 0;
252                 Classifier classifier = gate.getClassifier();
253                 // SIP
254                 final Ipv4Address sip;
255                 String error = validateMethod(Classifier.class, classifier, "getSrcIp");
256                 if (error == null) {
257                         sip = classifier.getSrcIp();
258                         count++;
259                 } else {
260                         message += " classifier.srcIp invalid: - " + error;
261                         sip = null;
262                         valid = false;
263                 }
264                 // DIP
265                 final Ipv4Address dip;
266                 error = validateMethod(Classifier.class, classifier, "getDstIp");
267                 if (error == null) {
268                         dip = classifier.getDstIp();
269                         count++;
270                 } else {
271                         message += " classifier.dstIp invalid: - " + error;
272                         dip = null;
273                         valid = false;
274                 }
275                 // Protocol
276                 final TpProtocol proto;
277                 error = validateMethod(Classifier.class, classifier, "getProtocol");
278                 if (error == null) {
279                         proto = classifier.getProtocol();
280                         count++;
281                 } else {
282                         message += " classifier.protocol invalid: - " + error;
283                         proto = null;
284                         valid = false;
285                 }
286                 // Source Port
287                 final PortNumber sport;
288                 error = validateMethod(Classifier.class, classifier, "getSrcPort");
289                 if (error == null) {
290                         sport = classifier.getSrcPort();
291                         count++;
292                 } else {
293                         message += " classifier.srcPort invalid: - " + error;
294                         sport = null;
295                         valid = false;
296                 }
297                 // Destination Port
298                 final PortNumber dport;
299                 error = validateMethod(Classifier.class, classifier, "getDstPort");
300                 if (error == null) {
301                         dport = classifier.getDstPort();
302                         count++;
303                 } else {
304                         message += " classifier.dstPort invalid: - " + error;
305                         dport = null;
306                         valid = false;
307                 }
308                 // TOS
309                 final TosByte tosByte;
310                 error = validateMethod(Classifier.class, classifier, "getTosByte");
311                 if (error == null) {
312                         tosByte = classifier.getTosByte();
313                         count++;
314                 } else {
315                         message += " classifier.tosByte invalid: " + error;
316                         tosByte = null;
317                         valid = false;
318                 }
319                 final TosByte tosMask;
320                 error = validateMethod(Classifier.class, classifier, "getTosMask");
321                 if (error == null) {
322                         tosMask = classifier.getTosMask();
323                         if (tosByte != null && tosMask == null) {
324                                 message += " classifier.tosMask missing;";
325                                 valid = false;
326                         }
327                 } else {
328                         message += " classifier.tosMask invalid: " + error;
329                         tosMask = null;
330                         valid = false;
331                 }
332                 if (count == 0) {
333                         message += " classifer must have at least one match field";
334                         valid = false;
335                 }
336                 if (! valid) {
337                         final ClassifierBuilder cBuilder = new ClassifierBuilder();
338                         cBuilder.setSrcIp(sip);
339                         cBuilder.setDstIp(dip);
340                         cBuilder.setProtocol(proto);
341                         cBuilder.setSrcPort(sport);
342                         cBuilder.setDstPort(dport);
343                         cBuilder.setTosByte(tosByte);
344                         cBuilder.setTosMask(tosMask);
345                         classifier = cBuilder.build();
346                         gateBuilder.setClassifier(classifier);
347                         response.addMessage(message);
348                 }
349                 return valid;
350         }
351
352         // TODO FIXME - breakup this method
353         private boolean validateExtClassifier(final Gates gate, final GatesBuilder gateBuilder, final Response response) {
354                 // validate ext-classifier
355                 String message = "";
356                 String error;
357                 boolean valid = true;
358                 int count = 0;
359                 ExtClassifier extClassifier = gate.getExtClassifier();
360                 // SIP & mask
361                 final Ipv4Address sip;
362                 error = validateMethod(ExtClassifier.class, extClassifier, "getSrcIp");
363                 if (error == null) {
364                         sip = extClassifier.getSrcIp();
365                         count++;
366                 } else {
367                         message += " ext-classifier.srcIp invalid: - " + error;
368                         sip = null;
369                         valid = false;
370                 }
371                 final Ipv4Address sipMask;
372                 error = validateMethod(ExtClassifier.class, extClassifier, "getSrcIpMask");
373                 if (error == null) {
374                         sipMask = extClassifier.getSrcIpMask();
375                         count++;
376                 } else {
377                         message += " ext-classifier.srcIpMask invalid: - " + error;
378                         sipMask = null;
379                         valid = false;
380                 }
381                 if (sip != null && sipMask == null) {
382                         message += " ext-classifier.srcIpMask missing";
383                         valid = false;
384                 }
385                 // DIP & mask
386                 final Ipv4Address dip;
387                 error = validateMethod(ExtClassifier.class, extClassifier, "getDstIp");
388                 if (error == null) {
389                         dip = extClassifier.getDstIp();
390                         count++;
391                 } else {
392                         message += " ext-classifier.dstIp invalid: - " + error;
393                         dip = null;
394                         valid = false;
395                 }
396                 final Ipv4Address dipMask;
397                 error = validateMethod(ExtClassifier.class, extClassifier, "getDstIpMask");
398                 if (error == null) {
399                         dipMask = extClassifier.getDstIpMask();
400                         count++;
401                 } else {
402                         message += " ext-classifier.srcIpMask invalid: - " + error;
403                         dipMask = null;
404                         valid = false;
405                 }
406                 if (dip != null && dipMask == null) {
407                         message += " ext-classifier.dstIpMask missing;";
408                         valid = false;
409                 }
410                 // Protocol
411                 final TpProtocol proto;
412                 error = validateMethod(ExtClassifier.class, extClassifier, "getProtocol");
413                 if (error == null) {
414                         proto = extClassifier.getProtocol();
415                         count++;
416                 } else {
417                         message += " ext-classifier.protocol invalid: - " + error;
418                         proto = null;
419                         valid = false;
420                 }
421                 // Source port range
422                 final PortNumber sportStart;
423                 error = validateMethod(ExtClassifier.class, extClassifier, "getSrcPortStart");
424                 if (error == null) {
425                         sportStart = extClassifier.getSrcPortStart();
426                         count++;
427                 } else {
428                         message += " ext-classifier.srcPortStart invalid: - " + error;
429                         sportStart = null;
430                         valid = false;
431                 }
432                 final PortNumber sportEnd;
433                 error = validateMethod(ExtClassifier.class, extClassifier, "getSrcPortEnd");
434                 if (error == null) {
435                         sportEnd = extClassifier.getSrcPortEnd();
436                         count++;
437                 } else {
438                         message += " ext-classifier.srcPortEnd invalid: - " + error;
439                         sportEnd = null;
440                         valid = false;
441                 }
442                 if (sportStart != null && sportEnd != null) {
443                         if (sportStart.getValue() > sportEnd.getValue()) {
444                                 message += " ext-classifier.srcPortStart greater than srcPortEnd";
445                                 valid = false;
446                         }
447                 }
448                 // Destination port range
449                 final PortNumber dportStart;
450                 error = validateMethod(ExtClassifier.class, extClassifier, "getDstPortStart");
451                 if (error == null) {
452                         dportStart = extClassifier.getDstPortStart();
453                         count++;
454                 } else {
455                         message += " ext-classifier.dstPortStart invalid: - " + error;
456                         dportStart = null;
457                         valid = false;
458                 }
459                 final PortNumber dportEnd;
460                 error = validateMethod(ExtClassifier.class, extClassifier, "getDstPortEnd");
461                 if (error == null) {
462                         dportEnd = extClassifier.getDstPortEnd();
463                         count++;
464                 } else {
465                         message += " ext-classifier.dstPortEnd invalid: - " + error;
466                         dportEnd = null;
467                         valid = false;
468                 }
469                 if (dportStart != null && dportEnd != null) {
470                         if (dportStart.getValue() > dportEnd.getValue()) {
471                                 message += " ext-classifier.dstPortStart greater than dstPortEnd";
472                                 valid = false;
473                         }
474                 }
475                 // TOS byte
476                 final TosByte tosByte;
477                 error = validateMethod(ExtClassifier.class, extClassifier, "getTosByte");
478                 if (error == null) {
479                         tosByte = extClassifier.getTosByte();
480                         count++;
481                 } else {
482                         message += " ext-classifier.tosByte invalid: " + error;
483                         tosByte = null;
484                         valid = false;
485                 }
486                 final TosByte tosMask;
487                 error = validateMethod(ExtClassifier.class, extClassifier, "getTosMask");
488                 if (error == null) {
489                         tosMask = extClassifier.getTosMask();
490                         if (tosByte != null && tosMask == null) {
491                                 message += " ext-classifier.tosMask missing;";
492                                 valid = false;
493                         }
494                 } else {
495                         message += " ext-classifier.tosMask invalid: " + error;
496                         tosMask = null;
497                         valid = false;
498                 }
499                 if (count == 0) {
500                         message += " ext-classifer must have at least one match field";
501                         valid = false;
502                 }
503                 if (! valid) {
504                         final ExtClassifierBuilder cBuilder = new ExtClassifierBuilder();
505                         cBuilder.setSrcIp(sip);
506                         cBuilder.setSrcIpMask(sipMask);
507                         cBuilder.setDstIp(dip);
508                         cBuilder.setDstIpMask(dipMask);
509                         cBuilder.setProtocol(proto);
510                         cBuilder.setSrcPortStart(sportStart);
511                         cBuilder.setSrcPortEnd(sportEnd);
512                         cBuilder.setDstPortStart(dportStart);
513                         cBuilder.setDstPortEnd(dportEnd);
514                         cBuilder.setTosByte(tosByte);
515                         cBuilder.setTosMask(tosMask);
516                         extClassifier = cBuilder.build();
517                         gateBuilder.setExtClassifier(extClassifier);
518                         response.addMessage(message);
519                 }
520                 return valid;
521         }
522
523         // TODO FIXME - break apart this method.
524         private boolean validateIpv6Classifier(final Gates gate, final GatesBuilder gateBuilder, final Response response) {
525                 // validate ipv6-classifier
526                 String message = "";
527                 String error;
528                 boolean valid = true;
529                 int count = 0;
530                 Ipv6Classifier ipv6Classifier = gate.getIpv6Classifier();
531                 // Source IPv6 prefix
532                 final Ipv6Prefix sip6;
533                 error = validateMethod(Ipv6Classifier.class, ipv6Classifier, "getSrcIp6");
534                 if (error == null) {
535                         sip6 = ipv6Classifier.getSrcIp6();
536                         count++;
537                 } else {
538                         message += " ipv6-classifier.srcIp invalid: - " + error;
539                         sip6 = null;
540                         valid = false;
541                 }
542                 // Destination IPv6 prefix
543                 final Ipv6Prefix dip6;
544                 error = validateMethod(Ipv6Classifier.class, ipv6Classifier, "getDstIp6");
545                 if (error == null) {
546                         dip6 = ipv6Classifier.getDstIp6();
547                         count++;
548                 } else {
549                         message += " ipv6-classifier.dstIp invalid: - " + error;
550                         dip6 = null;
551                         valid = false;
552                 }
553                 // Flow label
554                 Long flowLabel;
555                 error = validateMethod(Ipv6Classifier.class, ipv6Classifier, "getFlowLabel");
556                 if (error == null) {
557                         flowLabel = ipv6Classifier.getFlowLabel();
558                         if (flowLabel > 1048575) {
559                                 message += " ipv6-classifier.flowLabel invalid: - must be 0..1048575";
560                                 flowLabel = null;
561                                 valid = false;
562                         } else {
563                                 count++;
564                         }
565                 } else {
566                         message += " ipv6-classifier.flowLabel invalid: - " + error;
567                         flowLabel = null;
568                         valid = false;
569                 }
570                 // Next Hdr
571                 final TpProtocol nxtHdr;
572                 error = validateMethod(Ipv6Classifier.class, ipv6Classifier, "getNextHdr");
573                 if (error == null) {
574                         nxtHdr = ipv6Classifier.getNextHdr();
575                         count++;
576                 } else {
577                         message += " ipv6-classifier.nextHdr invalid: - " + error;
578                         nxtHdr = null;
579                         valid = false;
580                 }
581                 // Source port range
582                 final PortNumber sportStart;
583                 error = validateMethod(Ipv6Classifier.class, ipv6Classifier, "getSrcPortStart");
584                 if (error == null) {
585                         sportStart = ipv6Classifier.getSrcPortStart();
586                         count++;
587                 } else {
588                         message += " ipv6-classifier.srcPortStart invalid: - " + error;
589                         sportStart = null;
590                         valid = false;
591                 }
592                 final PortNumber sportEnd;
593                 error = validateMethod(Ipv6Classifier.class, ipv6Classifier, "getSrcPortEnd");
594                 if (error == null) {
595                         sportEnd = ipv6Classifier.getSrcPortEnd();
596                         count++;
597                 } else {
598                         message += " ipv6-classifier.srcPortEnd invalid: - " + error;
599                         sportEnd = null;
600                         valid = false;
601                 }
602                 if (sportStart != null && sportEnd != null) {
603                         if (sportStart.getValue() > sportEnd.getValue()) {
604                                 message += " ipv6-classifier.srcPortStart greater than srcPortEnd";
605                                 valid = false;
606                         }
607                 }
608                 // Destination port range
609                 final PortNumber dportStart;
610                 error = validateMethod(Ipv6Classifier.class, ipv6Classifier, "getDstPortStart");
611                 if (error == null) {
612                         dportStart = ipv6Classifier.getDstPortStart();
613                         count++;
614                 } else {
615                         message += " ipv6-classifier.dstPortStart invalid: - " + error;
616                         dportStart = null;
617                         valid = false;
618                 }
619                 final PortNumber dportEnd;
620                 error = validateMethod(Ipv6Classifier.class, ipv6Classifier, "getDstPortEnd");
621                 if (error == null) {
622                         dportEnd = ipv6Classifier.getDstPortEnd();
623                         count++;
624                 } else {
625                         message += " ipv6-classifier.dstPortEnd invalid: - " + error;
626                         dportEnd = null;
627                         valid = false;
628                 }
629                 if (dportStart != null && dportEnd != null) {
630                         if (dportStart.getValue() > dportEnd.getValue()) {
631                                 message += " ipv6-classifier.dstPortStart greater than dstPortEnd";
632                                 valid = false;
633                         }
634                 }
635                 // TC byte
636                 final TosByte tcLow;
637                 error = validateMethod(Ipv6Classifier.class, ipv6Classifier, "getTcLow");
638                 if (error == null) {
639                         tcLow = ipv6Classifier.getTcLow();
640                         count++;
641                 } else {
642                         message += " ipv6-classifier.tc-low invalid: " + error;
643                         tcLow = null;
644                         valid = false;
645                 }
646                 final TosByte tcHigh;
647                 error = validateMethod(Ipv6Classifier.class, ipv6Classifier, "getTcHigh");
648                 if (error == null) {
649                         tcHigh = ipv6Classifier.getTcHigh();
650                         count++;
651                 } else {
652                         message += " ipv6-classifier.tc-high invalid: " + error;
653                         tcHigh = null;
654                         valid = false;
655                 }
656                 if (tcLow != null && tcHigh != null) {
657                         if (tcLow.getValue() > tcHigh.getValue()) {
658                                 message += " ipv6-classifier.tc-low is greater than tc-high";
659                                 valid = false;
660                         }
661                 }
662                 final TosByte tcMask;
663                 error = validateMethod(Ipv6Classifier.class, ipv6Classifier, "getTcMask");
664                 if (error == null) {
665                         tcMask = ipv6Classifier.getTcMask();
666                 } else {
667                         message += " ipv6-classifier.tc-mask invalid: " + error;
668                         tcMask = null;
669                         valid = false;
670                 }
671                 if (tcLow != null && tcHigh != null && tcMask == null) {
672                         message += " ipv6-classifier.tc-mask missing;";
673                         valid = false;
674                 }
675                 if (count == 0) {
676                         message += " ipv6-classifer must have at least one match field";
677                         valid = false;
678                 }
679                 // rebuild ?
680                 if (! valid) {
681                         final Ipv6ClassifierBuilder cBuilder = new Ipv6ClassifierBuilder();
682                         cBuilder.setSrcIp6(sip6);
683                         cBuilder.setDstIp6(dip6);
684                         cBuilder.setFlowLabel(flowLabel);
685                         cBuilder.setNextHdr(nxtHdr);
686                         cBuilder.setSrcPortStart(sportStart);
687                         cBuilder.setSrcPortEnd(sportEnd);
688                         cBuilder.setDstPortStart(dportStart);
689                         cBuilder.setDstPortEnd(dportEnd);
690                         cBuilder.setTcLow(tcLow);
691                         cBuilder.setTcHigh(tcHigh);
692                         cBuilder.setTcMask(tcMask);
693                         ipv6Classifier = cBuilder.build();
694                         gateBuilder.setIpv6Classifier(ipv6Classifier);
695                         response.addMessage(message);
696                 }
697                 return valid;
698         }
699
700         // TODO FIXME - Do we really want the gate parameter object to be muted by this method?
701         private boolean validateGate(Gates gate, final Response response) {
702                 // validate gate elements and null out invalid elements as we go
703                 final GatesBuilder gateBuilder = new GatesBuilder();
704                 String message = "";
705                 boolean rebuild = false;
706                 // gate-spec
707                 if (! validateGateSpec(gate, gateBuilder, response)) {
708                         rebuild = true;
709                 }
710                 // traffic-profile
711                 if (! validateTrafficProfile(gate, gateBuilder, response)) {
712                         rebuild = true;
713                 }
714                 // classifiers (one of legacy classifier, ext-classifier, or ipv6 classifier
715                 final Classifier classifier = gate.getClassifier();
716                 final ExtClassifier extClassifier = gate.getExtClassifier();
717                 final Ipv6Classifier ipv6Classifier = gate.getIpv6Classifier();
718                 int count = 0;
719                 if (classifier != null) { count++; }
720                 if (extClassifier != null) { count++; }
721                 if (ipv6Classifier != null) { count++; }
722                 if (count < 1){
723                         response.addMessage(" Missing classifer: must have only 1 of classifier, ext-classifier, or ipv6-classifier");
724                         rebuild = true;
725                 } else if (count > 1) {
726                         response.addMessage(" Multiple classifiers: must have only 1 of classifier, ext-classifier, or ipv6-classifier");
727                         rebuild = true;
728                 } else if (count == 1) {
729                         if (classifier != null) {
730                                 // validate classifier
731                                 if (! validateClassifier(gate, gateBuilder, response)) {
732                                         rebuild = true;
733                                 }
734                         } else if (extClassifier != null) {
735                                 //validate ext-classifier
736                                 if (! validateExtClassifier(gate, gateBuilder, response)) {
737                                         rebuild = true;
738                                 }
739                         } else if (ipv6Classifier != null) {
740                                 // TODO FIXME - ipv6Classifier is always null???
741                                 // validate ipv6-classifier
742                                 if (! validateIpv6Classifier(gate, gateBuilder, response)) {
743                                         rebuild = true;
744                                 }
745                         }
746                 }
747                 // rebuild the gate object with valid data and set the response
748                 if (rebuild) {
749                         gateBuilder.setGateId(gate.getGateId());
750                         gateBuilder.setKey(gate.getKey());
751                         // TODO FIXME - the input parameter "gate" is being muted here???
752                         gate = gateBuilder.build();
753                         response.setGateBase(gate);
754                         response.addMessage(message);
755                 }
756                 return (! rebuild);
757         }
758
759         private boolean validateAmId(final Ccaps ccap, final CcapsBuilder ccapBuilder, final Response response) {
760                 // amId
761                 String message = "";
762                 String error;
763                 boolean valid = true;
764                 AmId amId = ccap.getAmId();
765                 if (amId == null) {
766                         message += " amId is required;";
767                         valid = false;
768                 } else {
769                         final Integer amTag;
770                         error = validateMethod(AmId.class, amId, "getAmTag");
771                         if (error == null) {
772                                 amTag = amId.getAmTag();
773                                 if (amTag == null) {
774                                         message += " amId.amTag missing;";
775                                         valid = false;
776                                 }
777                         } else {
778                                 message += " amId.amTag invalid: " + error;
779                                 amTag = null;
780                                 valid = false;
781                         }
782                         final Integer amType;
783                         error = validateMethod(AmId.class, amId, "getAmType");
784                         if (error == null) {
785                                 amType = amId.getAmType();
786                                 if (amType == null) {
787                                         message += " amId.amType missing;";
788                                         valid = false;
789                                 }
790                         } else {
791                                 message += " amId.amType invalid: " + error;
792                                 amType = null;
793                                 valid = false;
794                         }
795                         if (! valid) {
796                                 final AmIdBuilder amIdBuilder = new AmIdBuilder();
797                                 amIdBuilder.setAmTag(amTag);
798                                 amIdBuilder.setAmType(amType);
799                                 amId = amIdBuilder.build();
800                                 ccapBuilder.setAmId(amId);
801                         }
802                 }
803                 if (! valid) {
804                         response.addMessage(message);
805                 }
806                 return valid;
807         }
808
809         private boolean validateConnection(final Ccaps ccap, final CcapsBuilder ccapBuilder, final Response response) {
810                 // connection
811                 String message = "";
812                 String error;
813                 boolean valid = true;
814                 Connection conn = ccap.getConnection();
815                 if (conn == null) {
816                         message += " connection is required;";
817                         valid = false;
818                 } else {
819                         // IP address
820                         final IpAddress ipAddress;
821                         error = validateMethod(Connection.class, conn, "getIpAddress");
822                         if (error == null) {
823                                 ipAddress = conn.getIpAddress();
824                                 if (ipAddress == null) {
825                                         message += " connection.ipAddress missing;";
826                                         valid = false;
827                                 }
828                         } else {
829                                 message += " connection.ipAddress invalid: " + error;
830                                 ipAddress = null;
831                                 valid = false;
832                         }
833                         // Port number
834                         final PortNumber portNum;
835                         error = validateMethod(Connection.class, conn, "getPort");
836                         if (error == null) {
837                                 portNum = conn.getPort();
838                         } else {
839                                 message += " connection.port invalid: " + error;
840                                 portNum = null;
841                                 valid = false;
842                         }
843                         if (! valid) {
844                                 final ConnectionBuilder connBuilder = new ConnectionBuilder();
845                                 connBuilder.setIpAddress(ipAddress);
846                                 connBuilder.setPort(portNum);
847                                 conn = connBuilder.build();
848                                 ccapBuilder.setConnection(conn);
849                         }
850                 }
851                 if (! valid) {
852                         response.addMessage(message);
853                 }
854                 return valid;
855         }
856
857         private boolean validateSubscriberSubnets(final Ccaps ccap, final CcapsBuilder ccapBuilder,
858                                                                                           final Response response) {
859                 // subscriber-subnets
860                 String message = "";
861                 String error;
862                 boolean valid = true;
863                 List<IpPrefix> subnets = null;
864                 error = validateMethod(Ccaps.class, ccap, "getSubscriberSubnets");
865                 if (error == null) {
866                         subnets = ccap.getSubscriberSubnets();
867                         if (subnets == null) {
868                                 message += " subscriber-subnets is required;";
869                                 valid = false;
870                         }
871                 } else {
872                         message += " subscriber-subnets contains invalid IpPrefix - must be <ipaddress>/<prefixlen> format;" + error;
873                         valid = false;
874                 }
875                 if (! valid) {
876                         // TODO FIXME - subnets is always null???
877                         ccapBuilder.setSubscriberSubnets(subnets);
878                         response.addMessage(message);
879                 }
880                 return valid;
881         }
882
883         private boolean validateUpstreamScns(final Ccaps ccap, final CcapsBuilder ccapBuilder, final Response response) {
884                 // upstream-scns
885                 String message = "";
886                 String error;
887                 boolean valid = true;
888                 List<ServiceClassName> usScns = null;
889                 error = validateMethod(Ccaps.class, ccap, "getUpstreamScns");
890                 if (error == null) {
891                         usScns = ccap.getUpstreamScns();
892                         if (usScns == null) {
893                                 message += " upstream-scns is required;";
894                                 valid = false;
895                         }
896                 } else {
897                         message += " upstream-scns contains invalid SCN - must be 2-16 characters;" + error;
898                         valid = false;
899                 }
900                 if (! valid) {
901                         // TODO FIXME - usScns is always null???
902                         ccapBuilder.setUpstreamScns(usScns);
903                         response.addMessage(message);
904                 }
905                 return valid;
906         }
907
908         private boolean validateDownstreamScns(final Ccaps ccap, final CcapsBuilder ccapBuilder, final Response response) {
909                 // downstream-scns
910                 String message = "";
911                 boolean valid = true;
912                 List<ServiceClassName> dsScns = null;
913                 final String error = validateMethod(Ccaps.class, ccap, "getDownstreamScns");
914                 if (error == null) {
915                         dsScns = ccap.getDownstreamScns();
916                         if (dsScns == null) {
917                                 message += " downstream-scns is required;";
918                                 valid = false;
919                         }
920                 } else {
921                         message += " downstream-scns contains invalid SCN - must be 2-16 characters;" + error;
922                         valid = false;
923                 }
924                 if (! valid) {
925                         // TODO FIXME - dsScns is always null???
926                         ccapBuilder.setDownstreamScns(dsScns);
927                         response.addMessage(message);
928                 }
929                 return valid;
930         }
931
932
933         // TODO FIXME - Do we really want the ccap parameter object to be muted by this method?
934         private boolean validateCcap(Ccaps ccap, final Response response) {
935                 // validate ccap and null out invalid elements as we go
936                 final CcapsBuilder ccapBuilder = new CcapsBuilder();
937                 String message = "";
938                 boolean rebuild = false;
939                 // amId
940                 if ( ! validateAmId(ccap, ccapBuilder, response))        {
941                         rebuild = true;
942                 }
943                 // connection
944                 if ( ! validateConnection(ccap, ccapBuilder, response))        {
945                         rebuild = true;
946                 }
947                 // subscriber-subnets
948                 if ( ! validateSubscriberSubnets(ccap, ccapBuilder, response))        {
949                         rebuild = true;
950                 }
951                 // upstream-scns
952                 if ( ! validateUpstreamScns(ccap, ccapBuilder, response))        {
953                         rebuild = true;
954                 }
955                 // downstream-scns
956                 if ( ! validateDownstreamScns(ccap, ccapBuilder, response))        {
957                         rebuild = true;
958                 }
959                 // rebuild the ccap object with valid data and set the response
960                 if (rebuild) {
961                         ccapBuilder.setCcapId(ccap.getCcapId());
962                         ccapBuilder.setKey(ccap.getKey());
963                         // TODO FIXME - the input parameter "ccap" is being muted here???
964                         ccap = ccapBuilder.build();
965                         response.setCcapBase(ccap);
966                         response.addMessage(message);
967                 }
968                 return (! rebuild);
969         }
970 }
971