Relocate config subsystem.
[packetcable.git] / packetcable-policy-server / src / main / java / org / opendaylight / controller / packetcable / provider / PacketcableProvider.java
1 package org.opendaylight.controller.packetcable.provider;
2
3 import java.net.InetAddress;
4 import java.net.UnknownHostException;
5 import java.util.ArrayList;
6 import java.util.HashMap;
7 import java.util.HashSet;
8 import java.util.List;
9 import java.util.Map;
10 import java.util.Set;
11 import java.util.concurrent.ConcurrentHashMap;
12 import java.util.concurrent.ExecutionException;
13 import java.util.concurrent.ExecutorService;
14 import java.util.concurrent.Executors;
15
16 import javax.annotation.concurrent.ThreadSafe;
17
18 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
19 import org.opendaylight.controller.md.sal.binding.api.DataChangeListener;
20 import org.opendaylight.controller.md.sal.common.api.data.AsyncDataChangeEvent;
21 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
22 import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.ProviderContext;
23 import org.opendaylight.controller.sal.binding.api.BindingAwareProvider;
24 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.IpPrefix;
25 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Ipv4Prefix;
26 import org.opendaylight.yang.gen.v1.urn.packetcable.rev150327.Ccap;
27 import org.opendaylight.yang.gen.v1.urn.packetcable.rev150327.Qos;
28 import org.opendaylight.yang.gen.v1.urn.packetcable.rev150327.ServiceClassName;
29 import org.opendaylight.yang.gen.v1.urn.packetcable.rev150327.ServiceFlowDirection;
30 import org.opendaylight.yang.gen.v1.urn.packetcable.rev150327.ccap.Ccaps;
31 import org.opendaylight.yang.gen.v1.urn.packetcable.rev150327.ccap.CcapsKey;
32 import org.opendaylight.yang.gen.v1.urn.packetcable.rev150327.pcmm.qos.gates.Apps;
33 import org.opendaylight.yang.gen.v1.urn.packetcable.rev150327.pcmm.qos.gates.AppsKey;
34 import org.opendaylight.yang.gen.v1.urn.packetcable.rev150327.pcmm.qos.gates.apps.Subs;
35 import org.opendaylight.yang.gen.v1.urn.packetcable.rev150327.pcmm.qos.gates.apps.SubsKey;
36 import org.opendaylight.yang.gen.v1.urn.packetcable.rev150327.pcmm.qos.gates.apps.subs.Gates;
37 import org.opendaylight.yang.gen.v1.urn.packetcable.rev150327.pcmm.qos.gates.apps.subs.GatesKey;
38 import org.opendaylight.yangtools.concepts.ListenerRegistration;
39 import org.opendaylight.yangtools.yang.binding.DataObject;
40 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
41 import org.pcmm.rcd.IPCMMClient;
42 import org.slf4j.Logger;
43 import org.slf4j.LoggerFactory;
44
45 /**
46  * Called by ODL framework to start this bundle.
47  *
48  * This class is responsible for processing messages received from ODL's restconf interface.
49  * TODO - Remove some of these state maps and move some of this into the PCMMService
50  */
51 @ThreadSafe
52 public class PacketcableProvider implements BindingAwareProvider, DataChangeListener, AutoCloseable {
53
54     private static final Logger logger = LoggerFactory.getLogger(PacketcableProvider.class);
55
56     // keys to the /restconf/config/packetcable:ccap and /restconf/config/packetcable:qos config datastore
57     public static final InstanceIdentifier<Ccap> ccapIID = InstanceIdentifier.builder(Ccap.class).build();
58     public static final InstanceIdentifier<Qos> qosIID = InstanceIdentifier.builder(Qos.class).build();
59
60     /**
61      * The ODL object used to broker messages throughout the framework
62      */
63     private DataBroker dataBroker;
64
65     private ListenerRegistration<DataChangeListener> ccapDataChangeListenerRegistration;
66     private ListenerRegistration<DataChangeListener> qosDataChangeListenerRegistration;
67
68     /**
69      * The thread pool executor
70      */
71     private final ExecutorService executor;
72
73     // TODO - Revisit these maps and remove the ones no longer necessary
74     private final Map<String, Ccaps> ccapMap = new ConcurrentHashMap<>();
75     private final Map<String, Gates> gateMap = new ConcurrentHashMap<>();
76     private final Map<String, String> gateCcapMap = new ConcurrentHashMap<>();
77     private final Map<Subnet, Ccaps> subscriberSubnetsMap = new ConcurrentHashMap<>();
78     private final Map<ServiceClassName, List<Ccaps>> downstreamScnMap = new ConcurrentHashMap<>();
79     private final Map<ServiceClassName, List<Ccaps>> upstreamScnMap = new ConcurrentHashMap<>();
80
81     /**
82      * Holds a PCMMService object for each CCAP being managed.
83      */
84     private final Map<String, PCMMService> pcmmServiceMap = new ConcurrentHashMap<>();
85
86     /**
87      * Constructor
88      */
89     public PacketcableProvider() {
90         logger.info("Starting provider");
91         executor = Executors.newCachedThreadPool();
92     }
93
94     @Override
95     public void onSessionInitiated(ProviderContext session) {
96         logger.info("Packetcable Session Initiated");
97
98         dataBroker =  session.getSALService(DataBroker.class);
99
100         ccapDataChangeListenerRegistration =
101                 dataBroker.registerDataChangeListener(LogicalDatastoreType.CONFIGURATION,
102                         PacketcableProvider.ccapIID, this, DataBroker.DataChangeScope.SUBTREE );
103
104         qosDataChangeListenerRegistration =
105                 dataBroker.registerDataChangeListener(LogicalDatastoreType.CONFIGURATION,
106                         PacketcableProvider.qosIID, this, DataBroker.DataChangeScope.SUBTREE );
107     }
108     /**
109      * Implemented from the AutoCloseable interface.
110      */
111     @Override
112     public void close() throws ExecutionException, InterruptedException {
113         executor.shutdown();
114         if (ccapDataChangeListenerRegistration != null) {
115             ccapDataChangeListenerRegistration.close();
116         }
117
118         if (qosDataChangeListenerRegistration != null) {
119             qosDataChangeListenerRegistration.close();
120         }
121     }
122
123     public InetAddress getInetAddress(final String subId){
124         try {
125             return InetAddress.getByName(subId);
126         } catch (UnknownHostException e) {
127             logger.error("getInetAddress: {} FAILED: {}", subId, e.getMessage());
128             return null;
129         }
130     }
131
132     private String getIpPrefixStr(final IpPrefix ipPrefix) {
133         final Ipv4Prefix ipv4 = ipPrefix.getIpv4Prefix();
134         if (ipv4 != null) {
135             return ipv4.getValue();
136         } else {
137             return ipPrefix.getIpv6Prefix().getValue();
138         }
139     }
140
141     private void updateCcapMaps(final Ccaps ccap) {
142         // add ccap to the subscriberSubnets map
143         for (final IpPrefix ipPrefix : ccap.getSubscriberSubnets()) {
144             try {
145                 subscriberSubnetsMap.put(Subnet.createInstance(getIpPrefixStr(ipPrefix)), ccap);
146             } catch (UnknownHostException e) {
147                 logger.error("updateSubscriberSubnets: {}:{} FAILED: {}", ipPrefix, ccap, e.getMessage());
148             }
149         }
150         // ccap to upstream SCN map
151         for (final ServiceClassName scn : ccap.getUpstreamScns()) {
152             if (upstreamScnMap.containsKey(scn)) {
153                 upstreamScnMap.get(scn).add(ccap);
154             } else {
155                 final List<Ccaps> ccapList = new ArrayList<>();
156                 ccapList.add(ccap);
157                 upstreamScnMap.put(scn, ccapList);
158             }
159         }
160         // ccap to downstream SCN map
161         for (final ServiceClassName scn : ccap.getDownstreamScns()) {
162             if (downstreamScnMap.containsKey(scn)) {
163                 downstreamScnMap.get(scn).add(ccap);
164             } else {
165                 final List<Ccaps> ccapList = new ArrayList<>();
166                 ccapList.add(ccap);
167                 downstreamScnMap.put(scn, ccapList);
168             }
169         }
170     }
171
172     private void removeCcapFromAllMaps(final Ccaps ccap) {
173         // remove the ccap from all maps
174         // subscriberSubnets map
175         for (final Map.Entry<Subnet, Ccaps> entry : subscriberSubnetsMap.entrySet()) {
176             if (entry.getValue() == ccap) {
177                 subscriberSubnetsMap.remove(entry.getKey());
178             }
179         }
180         // ccap to upstream SCN map
181         for (final Map.Entry<ServiceClassName, List<Ccaps>> entry : upstreamScnMap.entrySet()) {
182             final List<Ccaps> ccapList = entry.getValue();
183             ccapList.remove(ccap);
184             if (ccapList.isEmpty()) {
185                 upstreamScnMap.remove(entry.getKey());
186             }
187         }
188         // ccap to downstream SCN map
189         for (final Map.Entry<ServiceClassName, List<Ccaps>> entry : downstreamScnMap.entrySet()) {
190             final List<Ccaps> ccapList = entry.getValue();
191             ccapList.remove(ccap);
192             if (ccapList.isEmpty()) {
193                 downstreamScnMap.remove(entry.getKey());
194             }
195         }
196
197         final PCMMService service = pcmmServiceMap.remove(ccap.getCcapId());
198         if (service != null) service.disconect();
199     }
200
201     private Ccaps findCcapForSubscriberId(final InetAddress inetAddr) {
202         Ccaps matchedCcap = null;
203         int longestPrefixLen = -1;
204         for (final Map.Entry<Subnet, Ccaps> entry : subscriberSubnetsMap.entrySet()) {
205             final Subnet subnet = entry.getKey();
206             if (subnet.isInNet(inetAddr)) {
207                 int prefixLen = subnet.getPrefixLen();
208                 if (prefixLen > longestPrefixLen) {
209                     matchedCcap = entry.getValue();
210                     longestPrefixLen = prefixLen;
211                 }
212             }
213         }
214         return matchedCcap;
215     }
216
217     private ServiceFlowDirection findScnOnCcap(final ServiceClassName scn, final Ccaps ccap) {
218         if (upstreamScnMap.containsKey(scn)) {
219             final List<Ccaps> ccapList = upstreamScnMap.get(scn);
220             if (ccapList.contains(ccap)) {
221                 return ServiceFlowDirection.Us;
222             }
223         } else if (downstreamScnMap.containsKey(scn)) {
224             final List<Ccaps> ccapList = downstreamScnMap.get(scn);
225             if (ccapList.contains(ccap)) {
226                 return ServiceFlowDirection.Ds;
227             }
228         }
229         return null;
230     }
231
232     /**
233      * Implemented from the DataChangeListener interface.
234      */
235
236     private class InstanceData {
237         // CCAP Identity
238         public final Map<InstanceIdentifier<Ccaps>, Ccaps> ccapIidMap = new HashMap<>();
239         // Gate Identity
240         public String subId;
241         public final Map<String, String> gatePathMap = new HashMap<>();
242         public String gatePath;
243         public final Map<InstanceIdentifier<Gates>, Gates> gateIidMap = new HashMap<>();
244         // remove path for either CCAP or Gates
245         public final Set<String> removePathList = new HashSet<>();
246
247         public InstanceData(final Map<InstanceIdentifier<?>, DataObject> thisData) {
248             // only used to parse createdData or updatedData
249             getCcaps(thisData);
250             if (ccapIidMap.isEmpty()) {
251                 getGates(thisData);
252                 if (! gateIidMap.isEmpty()){
253                     gatePath = gatePathMap.get("appId") + "/" + gatePathMap.get("subId");
254                 }
255             }
256         }
257
258         public InstanceData(final Set<InstanceIdentifier<?>> thisData) {
259             // only used to parse the removedData paths
260             for (final InstanceIdentifier<?> removeThis : thisData) {
261                 getGatePathMap(removeThis);
262                 if (gatePathMap.containsKey("ccapId")) {
263                     gatePath = gatePathMap.get("ccapId");
264                     removePathList.add(gatePath);
265                 } else if (gatePathMap.containsKey("gateId")) {
266                     gatePath = gatePathMap.get("appId") + "/" + gatePathMap.get("subId") + "/" + gatePathMap.get("gateId");
267                     removePathList.add(gatePath);
268                 }
269             }
270         }
271         private void getGatePathMap(final InstanceIdentifier<?> thisInstance) {
272             logger.info("onDataChanged().getGatePathMap(): " + thisInstance);
273             try {
274                 final InstanceIdentifier<Ccaps> ccapInstance = thisInstance.firstIdentifierOf(Ccaps.class);
275                 if (ccapInstance != null) {
276                     final CcapsKey ccapKey = InstanceIdentifier.keyOf(ccapInstance);
277                     if (ccapKey != null) {
278                         gatePathMap.put("ccapId", ccapKey.getCcapId());
279                     }
280                 } else {
281                     // get the gate path keys from the InstanceIdentifier Map key set if they are there
282                     final InstanceIdentifier<Apps> appsInstance = thisInstance.firstIdentifierOf(Apps.class);
283                     if (appsInstance != null) {
284                         final AppsKey appKey = InstanceIdentifier.keyOf(appsInstance);
285                         if (appKey != null) {
286                             gatePathMap.put("appId", appKey.getAppId());
287                         }
288                     }
289                     final InstanceIdentifier<Subs> subsInstance = thisInstance.firstIdentifierOf(Subs.class);
290                     if (subsInstance != null) {
291                         final SubsKey subKey = InstanceIdentifier.keyOf(subsInstance);
292                         if (subKey != null) {
293                             subId = subKey.getSubId();
294                             gatePathMap.put("subId", subId);
295                         }
296                     }
297                     final InstanceIdentifier<Gates> gatesInstance = thisInstance.firstIdentifierOf(Gates.class);
298                     if (gatesInstance != null) {
299                         final GatesKey gateKey = InstanceIdentifier.keyOf(gatesInstance);
300                         if (gateKey != null) {
301                             gatePathMap.put("gateId", gateKey.getGateId());
302                         }
303                     }
304                 }
305             } catch (ClassCastException err) {
306                 logger.warn("Unexpected exception", err);
307             }
308         }
309
310         private void getCcaps(final Map<InstanceIdentifier<?>, DataObject> thisData) {
311             logger.info("onDataChanged().getCcaps(): " + thisData);
312             for (final Map.Entry<InstanceIdentifier<?>, DataObject> entry : thisData.entrySet()) {
313                 if (entry.getValue() instanceof Ccaps) {
314                     // TODO FIXME - Potential ClassCastException thrown here!!!
315                     ccapIidMap.put((InstanceIdentifier<Ccaps>)entry.getKey(), (Ccaps)entry.getValue());
316                 }
317             }
318         }
319
320         private void getGates(final Map<InstanceIdentifier<?>, DataObject> thisData) {
321             logger.info("onDataChanged().getGates(): " + thisData);
322             for (final Map.Entry<InstanceIdentifier<?>, DataObject> entry : thisData.entrySet()) {
323                 if (entry.getValue() instanceof Gates) {
324                     final Gates gate = (Gates)entry.getValue();
325
326                     // TODO FIXME - Potential ClassCastException thrown here!!!
327                     final InstanceIdentifier<Gates> gateIID = (InstanceIdentifier<Gates>)entry.getKey();
328                     getGatePathMap(gateIID);
329                     gateIidMap.put(gateIID, gate);
330                 }
331             }
332         }
333     }
334
335     @Override
336     public void onDataChanged(final AsyncDataChangeEvent<InstanceIdentifier<?>, DataObject> change) {
337         logger.info("onDataChanged");
338         // Determine what change action took place by looking at the change object's InstanceIdentifier sets
339         // and validate all instance data
340         if (!change.getCreatedData().isEmpty()) {
341             if (!new ValidateInstanceData(dataBroker, change.getCreatedData()).validateYang()) {
342                 // leave now -- a bad yang object has been detected and a response object has been inserted
343                 return;
344             }
345             onCreate(new InstanceData(change.getCreatedData()));
346         } else if (!change.getRemovedPaths().isEmpty()) {
347             onRemove(new InstanceData(change.getRemovedPaths()));
348         } else if (!change.getUpdatedData().isEmpty()) {
349             if (new ValidateInstanceData(dataBroker, change.getUpdatedData()).isResponseEcho()) {
350                 // leave now -- this is an echo of the inserted response object
351                 return;
352             }
353             onUpdate(new InstanceData(change.getUpdatedData()));
354         } else {
355             // we should not be here -- complain bitterly and return
356             logger.error("onDataChanged(): Unknown change action: " + change);
357         }
358     }
359
360     private void onCreate(final InstanceData thisData) {
361         logger.info("onCreate(): " + thisData);
362
363         // get the CCAP parameters
364         String message;
365         if (! thisData.ccapIidMap.isEmpty()) {
366             for (Map.Entry<InstanceIdentifier<Ccaps>, Ccaps> entry : thisData.ccapIidMap.entrySet()) {
367                 final Ccaps thisCcap = entry.getValue();
368                 // get the CCAP node identity from the Instance Data
369                 final String ccapId = thisCcap.getCcapId();
370
371                 if (pcmmServiceMap.get(thisCcap.getCcapId()) == null) {
372                     final PCMMService pcmmService = new PCMMService(IPCMMClient.CLIENT_TYPE, thisCcap);
373                     // TODO - may want to use the AMID but for the client type but probably not???
374 /*
375                             final PCMMService pcmmService = new PCMMService(
376                                     thisCcap.getAmId().getAmType().shortValue(), thisCcap);
377 */
378                     pcmmServiceMap.put(thisCcap.getCcapId(), pcmmService);
379                     message = pcmmService.addCcap();
380                     if (message.contains("200 OK")) {
381                         ccapMap.put(ccapId, thisCcap);
382                         updateCcapMaps(thisCcap);
383                         logger.info("Created CCAP: {}/{} : {}", thisData.gatePath, thisCcap, message);
384                         logger.info("Created CCAP: {} : {}", thisData.gatePath, message);
385                     } else {
386                         // TODO - when a connection cannot be made, need to remove CCAP from ODL cache.
387                         logger.error("Create CCAP Failed: {} : {}", thisData.gatePath, message);
388                     }
389                     // set the response string in the config ccap object using a new thread
390                     executor.execute(new Response(dataBroker, entry.getKey(), thisCcap, message));
391                 } else {
392                     logger.error("Already monitoring CCAP - " + thisCcap);
393                     break;
394                 }
395             }
396         } else {
397             // get the PCMM gate parameters from the ccapId/appId/subId/gateId path in the Maps entry (if new gate)
398             for (final Map.Entry<InstanceIdentifier<Gates>, Gates> entry : thisData.gateIidMap.entrySet()) {
399                 message = null;
400                 final Gates gate = entry.getValue();
401                 final String gateId = gate.getGateId();
402                 final String gatePathStr = thisData.gatePath + "/" + gateId ;
403                 final InetAddress subId = getInetAddress(thisData.subId);
404                 if (subId != null) {
405                     final Ccaps thisCcap = findCcapForSubscriberId(subId);
406                     if (thisCcap != null) {
407                         final String ccapId = thisCcap.getCcapId();
408                         // verify SCN exists on CCAP and force gateSpec.Direction to align with SCN direction
409                         final ServiceClassName scn = gate.getTrafficProfile().getServiceClassName();
410                         if (scn != null) {
411                             final ServiceFlowDirection scnDir = findScnOnCcap(scn, thisCcap);
412                             if (scnDir != null) {
413                                 if (pcmmServiceMap.get(thisCcap.getCcapId()) != null) {
414                                     message = pcmmServiceMap.get(thisCcap.getCcapId()).sendGateSet(gatePathStr, subId, gate, scnDir);
415                                     gateMap.put(gatePathStr, gate);
416                                     gateCcapMap.put(gatePathStr, thisCcap.getCcapId());
417
418                                     if (message.contains("200 OK")) {
419                                         logger.info("Created QoS gate {} for {}/{}/{} - {}",
420                                                 gateId, ccapId, gatePathStr, gate, message);
421                                         logger.info("Created QoS gate {} for {}/{} - {}",
422                                                 gateId, ccapId, gatePathStr, message);
423                                     } else {
424                                         logger.info("Unable to create QoS gate {} for {}/{}/{} - {}",
425                                                 gateId, ccapId, gatePathStr, gate, message);
426                                         logger.error("Unable to create QoS gate {} for {}/{} - {}",
427                                                 gateId, ccapId, gatePathStr, message);
428                                     }
429                                 } else {
430                                     logger.error("Unable to locate PCMM Service for CCAP - " + thisCcap);
431                                     break;
432                                 }
433                             } else {
434                                 logger.error("PCMMService: sendGateSet(): SCN {} not found on CCAP {} for {}/{}",
435                                         scn.getValue(), thisCcap, gatePathStr, gate);
436                                 message = String.format("404 Not Found - SCN %s not found on CCAP %s for %s",
437                                         scn.getValue(), thisCcap.getCcapId(), gatePathStr);
438                             }
439                         }
440                     } else {
441                         final String subIdStr = thisData.subId;
442                         message = String.format("404 Not Found - no CCAP found for subscriber %s in %s",
443                                 subIdStr, gatePathStr);
444                         logger.info("Create QoS gate {} FAILED: no CCAP found for subscriber {}: @ {}/{}",
445                                 gateId, subIdStr, gatePathStr, gate);
446                         logger.error("Create QoS gate {} FAILED: no CCAP found for subscriber {}: @ {}",
447                                 gateId, subIdStr, gatePathStr);
448                     }
449                 } else {
450                     final String subIdStr = thisData.subId;
451                     message = String.format("400 Bad Request - subId must be a valid IP address for subscriber %s in %s",
452                             subIdStr, gatePathStr);
453                     logger.info("Create QoS gate {} FAILED: subId must be a valid IP address for subscriber {}: @ {}/{}",
454                             gateId, subIdStr, gatePathStr, gate);
455                     logger.error("Create QoS gate {} FAILED: subId must be a valid IP address for subscriber {}: @ {}",
456                             gateId, subIdStr, gatePathStr);
457                 }
458                 // set the response message in the config gate object using a new thread
459                 executor.execute(new Response(dataBroker, entry.getKey(), gate, message));
460             }
461         }
462     }
463
464     private void onRemove(final InstanceData thisData) {
465         logger.info("onRemove(): " + thisData);
466         for (final String gatePathStr: thisData.removePathList) {
467             if (gateMap.containsKey(gatePathStr)) {
468                 final Gates thisGate = gateMap.remove(gatePathStr);
469                 final String gateId = thisGate.getGateId();
470                 final String ccapId = gateCcapMap.remove(gatePathStr);
471                 final Ccaps thisCcap = ccapMap.get(ccapId);
472                 final PCMMService service = pcmmServiceMap.get(thisCcap.getCcapId());
473                 if (service != null) {
474                     service.sendGateDelete(gatePathStr);
475                     logger.info("onDataChanged(): removed QoS gate {} for {}/{}/{}: ", gateId, ccapId, gatePathStr, thisGate);
476                     logger.info("onDataChanged(): removed QoS gate {} for {}/{}: ", gateId, ccapId, gatePathStr);
477                 } else
478                     logger.warn("Unable to send to locate PCMMService to send gate delete message with CCAP - "
479                             + thisCcap);
480             }
481         }
482         for (final String ccapIdStr: thisData.removePathList) {
483             if (ccapMap.containsKey(ccapIdStr)) {
484                 final Ccaps thisCcap = ccapMap.remove(ccapIdStr);
485                 removeCcapFromAllMaps(thisCcap);
486             }
487         }
488     }
489
490     private void onUpdate(final InstanceData oldData) {
491         logger.info("onUpdate(): " + oldData);
492         // update operation not allowed -- restore the original config object and complain
493         if (! oldData.ccapIidMap.isEmpty()) {
494             for (final Map.Entry<InstanceIdentifier<Ccaps>, Ccaps> entry : oldData.ccapIidMap.entrySet()) {
495                 final Ccaps ccap = entry.getValue();
496                 final String ccapId = ccap.getCcapId();
497                 String message = String.format("405 Method Not Allowed - %s: CCAP update not permitted (use delete); ",
498                         ccapId);
499                 // push new error message onto existing response
500                 message += ccap.getResponse();
501                 // set the response message in the config object using a new thread -- also restores the original data
502                 executor.execute(new Response(dataBroker, entry.getKey(), ccap, message));
503                 logger.error("onDataChanged(): CCAP update not permitted {}/{}", ccapId, ccap);
504             }
505         } else {
506             for (final Map.Entry<InstanceIdentifier<Gates>, Gates> entry : oldData.gateIidMap.entrySet()) {
507                 final Gates gate = entry.getValue();
508                 final String gatePathStr = oldData.gatePath + "/" + gate.getGateId() ;
509                 String message = String.format("405 Method Not Allowed - %s: QoS Gate update not permitted (use delete); ", gatePathStr);
510                 // push new error message onto existing response
511                 message += gate.getResponse();
512                 // set the response message in the config object using a new thread -- also restores the original data
513                 executor.execute(new Response(dataBroker, entry.getKey(), gate, message));
514                 logger.error("onDataChanged(): QoS Gate update not permitted: {}/{}", gatePathStr, gate);
515             }
516         }
517     }
518 }