Updated model yang file to use recommended practices found on wiki, then updated...
[packetcable.git] / packetcable-policy-server / src / main / java / org / opendaylight / controller / packetcable / provider / PacketcableProvider.java
index 2350e7502ebe4a3802a2d405654355ef0cf6a15f..894eccc0305e42fa5b5f428007f7fd08b7949c53 100644 (file)
@@ -1,39 +1,44 @@
 package org.opendaylight.controller.packetcable.provider;
 
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ExecutionException;
+import javax.annotation.concurrent.ThreadSafe;
 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
 import org.opendaylight.controller.md.sal.binding.api.DataChangeListener;
 import org.opendaylight.controller.md.sal.common.api.data.AsyncDataChangeEvent;
-import org.opendaylight.controller.md.sal.common.api.data.AsyncReadWriteTransaction;
 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.ProviderContext;
+import org.opendaylight.controller.sal.binding.api.BindingAwareProvider;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.IpPrefix;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Ipv4Prefix;
-import org.opendaylight.yang.gen.v1.urn.packetcable.rev150327.Ccap;
-import org.opendaylight.yang.gen.v1.urn.packetcable.rev150327.Qos;
-import org.opendaylight.yang.gen.v1.urn.packetcable.rev150327.ServiceClassName;
-import org.opendaylight.yang.gen.v1.urn.packetcable.rev150327.ServiceFlowDirection;
-import org.opendaylight.yang.gen.v1.urn.packetcable.rev150327.ccap.Ccaps;
-import org.opendaylight.yang.gen.v1.urn.packetcable.rev150327.ccap.CcapsKey;
-import org.opendaylight.yang.gen.v1.urn.packetcable.rev150327.pcmm.qos.gates.Apps;
-import org.opendaylight.yang.gen.v1.urn.packetcable.rev150327.pcmm.qos.gates.AppsKey;
-import org.opendaylight.yang.gen.v1.urn.packetcable.rev150327.pcmm.qos.gates.apps.Subs;
-import org.opendaylight.yang.gen.v1.urn.packetcable.rev150327.pcmm.qos.gates.apps.SubsKey;
-import org.opendaylight.yang.gen.v1.urn.packetcable.rev150327.pcmm.qos.gates.apps.subs.Gates;
-import org.opendaylight.yang.gen.v1.urn.packetcable.rev150327.pcmm.qos.gates.apps.subs.GatesKey;
+import org.opendaylight.yang.gen.v1.urn.packetcable.rev151026.Ccaps;
+import org.opendaylight.yang.gen.v1.urn.packetcable.rev151026.Qos;
+import org.opendaylight.yang.gen.v1.urn.packetcable.rev151026.ServiceClassName;
+import org.opendaylight.yang.gen.v1.urn.packetcable.rev151026.ServiceFlowDirection;
+import org.opendaylight.yang.gen.v1.urn.packetcable.rev151026.ccap.attributes.Connection;
+import org.opendaylight.yang.gen.v1.urn.packetcable.rev151026.ccaps.Ccap;
+import org.opendaylight.yang.gen.v1.urn.packetcable.rev151026.ccaps.CcapKey;
+import org.opendaylight.yang.gen.v1.urn.packetcable.rev151026.pcmm.qos.gates.apps.App;
+import org.opendaylight.yang.gen.v1.urn.packetcable.rev151026.pcmm.qos.gates.apps.AppKey;
+import org.opendaylight.yang.gen.v1.urn.packetcable.rev151026.pcmm.qos.gates.apps.app.subscribers.Subscriber;
+import org.opendaylight.yang.gen.v1.urn.packetcable.rev151026.pcmm.qos.gates.apps.app.subscribers.SubscriberKey;
+import org.opendaylight.yang.gen.v1.urn.packetcable.rev151026.pcmm.qos.gates.apps.app.subscribers.subscriber.gates.Gate;
+import org.opendaylight.yang.gen.v1.urn.packetcable.rev151026.pcmm.qos.gates.apps.app.subscribers.subscriber.gates.GateKey;
+import org.opendaylight.yangtools.concepts.ListenerRegistration;
 import org.opendaylight.yangtools.yang.binding.DataObject;
 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
 import org.pcmm.rcd.IPCMMClient;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-import javax.annotation.concurrent.ThreadSafe;
-import java.net.InetAddress;
-import java.net.UnknownHostException;
-import java.util.*;
-import java.util.concurrent.ConcurrentHashMap;
-import java.util.concurrent.ExecutionException;
-import java.util.concurrent.ExecutorService;
-import java.util.concurrent.Executors;
-
 /**
  * Called by ODL framework to start this bundle.
  *
@@ -41,59 +46,71 @@ import java.util.concurrent.Executors;
  * TODO - Remove some of these state maps and move some of this into the PCMMService
  */
 @ThreadSafe
-public class PacketcableProvider implements DataChangeListener, AutoCloseable {
+public class PacketcableProvider implements BindingAwareProvider, DataChangeListener, AutoCloseable {
 
     private static final Logger logger = LoggerFactory.getLogger(PacketcableProvider.class);
 
     // keys to the /restconf/config/packetcable:ccap and /restconf/config/packetcable:qos config datastore
-    public static final InstanceIdentifier<Ccap> ccapIID = InstanceIdentifier.builder(Ccap.class).build();
+    public static final InstanceIdentifier<Ccaps> ccapIID = InstanceIdentifier.builder(Ccaps.class).build();
     public static final InstanceIdentifier<Qos> qosIID = InstanceIdentifier.builder(Qos.class).build();
 
     /**
      * The ODL object used to broker messages throughout the framework
      */
-    private final DataBroker dataBroker;
+    private DataBroker dataBroker;
 
-    /**
-     * The thread pool executor
-     */
-    private final ExecutorService executor;
+    private MdsalUtils mdsalUtils;
+
+    private ListenerRegistration<DataChangeListener> ccapDataChangeListenerRegistration;
+    private ListenerRegistration<DataChangeListener> qosDataChangeListenerRegistration;
 
     // TODO - Revisit these maps and remove the ones no longer necessary
-    private final Map<String, Ccaps> ccapMap = new ConcurrentHashMap<>();
-    private final Map<String, Gates> gateMap = new ConcurrentHashMap<>();
+    private final Map<String, Ccap> ccapMap = new ConcurrentHashMap<>();
+    private final Map<String, Gate> gateMap = new ConcurrentHashMap<>();
     private final Map<String, String> gateCcapMap = new ConcurrentHashMap<>();
-    private final Map<Subnet, Ccaps> subscriberSubnetsMap = new ConcurrentHashMap<>();
-    private final Map<ServiceClassName, List<Ccaps>> downstreamScnMap = new ConcurrentHashMap<>();
-    private final Map<ServiceClassName, List<Ccaps>> upstreamScnMap = new ConcurrentHashMap<>();
+    private final Map<Subnet, Ccap> subscriberSubnetsMap = new ConcurrentHashMap<>();
+    private final Map<ServiceClassName, List<Ccap>> downstreamScnMap = new ConcurrentHashMap<>();
+    private final Map<ServiceClassName, List<Ccap>> upstreamScnMap = new ConcurrentHashMap<>();
 
     /**
      * Holds a PCMMService object for each CCAP being managed.
      */
-    private final Map<Ccaps, PCMMService> pcmmServiceMap = new ConcurrentHashMap<>();
+    private final Map<String, PCMMService> pcmmServiceMap = new ConcurrentHashMap<>();
 
     /**
      * Constructor
      */
-    public PacketcableProvider(final DataBroker dataBroker) {
+    public PacketcableProvider() {
         logger.info("Starting provider");
-        this.dataBroker = dataBroker;
-        executor = Executors.newCachedThreadPool();
     }
 
+    @Override
+    public void onSessionInitiated(ProviderContext session) {
+        logger.info("Packetcable Session Initiated");
+
+        dataBroker =  session.getSALService(DataBroker.class);
+
+        mdsalUtils = new MdsalUtils(dataBroker);
+
+        ccapDataChangeListenerRegistration =
+                dataBroker.registerDataChangeListener(LogicalDatastoreType.CONFIGURATION,
+                        PacketcableProvider.ccapIID, this, DataBroker.DataChangeScope.SUBTREE );
+
+        qosDataChangeListenerRegistration =
+                dataBroker.registerDataChangeListener(LogicalDatastoreType.CONFIGURATION,
+                        PacketcableProvider.qosIID, this, DataBroker.DataChangeScope.SUBTREE );
+    }
     /**
      * Implemented from the AutoCloseable interface.
      */
     @Override
     public void close() throws ExecutionException, InterruptedException {
-        executor.shutdown();
-        if (dataBroker != null) {
-            // remove our config datastore instances
-            final AsyncReadWriteTransaction<InstanceIdentifier<?>, ?> tx = dataBroker.newReadWriteTransaction();
-            tx.delete(LogicalDatastoreType.CONFIGURATION, ccapIID);
-            tx.delete(LogicalDatastoreType.CONFIGURATION, qosIID);
-            // TODO - commit() below has been deprecated
-            tx.commit().get();
+        if (ccapDataChangeListenerRegistration != null) {
+            ccapDataChangeListenerRegistration.close();
+        }
+
+        if (qosDataChangeListenerRegistration != null) {
+            qosDataChangeListenerRegistration.close();
         }
     }
 
@@ -115,7 +132,7 @@ public class PacketcableProvider implements DataChangeListener, AutoCloseable {
         }
     }
 
-    private void updateCcapMaps(final Ccaps ccap) {
+    private void updateCcapMaps(final Ccap ccap) {
         // add ccap to the subscriberSubnets map
         for (final IpPrefix ipPrefix : ccap.getSubscriberSubnets()) {
             try {
@@ -129,7 +146,7 @@ public class PacketcableProvider implements DataChangeListener, AutoCloseable {
             if (upstreamScnMap.containsKey(scn)) {
                 upstreamScnMap.get(scn).add(ccap);
             } else {
-                final List<Ccaps> ccapList = new ArrayList<>();
+                final List<Ccap> ccapList = new ArrayList<>();
                 ccapList.add(ccap);
                 upstreamScnMap.put(scn, ccapList);
             }
@@ -139,46 +156,46 @@ public class PacketcableProvider implements DataChangeListener, AutoCloseable {
             if (downstreamScnMap.containsKey(scn)) {
                 downstreamScnMap.get(scn).add(ccap);
             } else {
-                final List<Ccaps> ccapList = new ArrayList<>();
+                final List<Ccap> ccapList = new ArrayList<>();
                 ccapList.add(ccap);
                 downstreamScnMap.put(scn, ccapList);
             }
         }
     }
 
-    private void removeCcapFromAllMaps(final Ccaps ccap) {
+    private void removeCcapFromAllMaps(final Ccap ccap) {
         // remove the ccap from all maps
         // subscriberSubnets map
-        for (final Map.Entry<Subnet, Ccaps> entry : subscriberSubnetsMap.entrySet()) {
+        for (final Map.Entry<Subnet, Ccap> entry : subscriberSubnetsMap.entrySet()) {
             if (entry.getValue() == ccap) {
                 subscriberSubnetsMap.remove(entry.getKey());
             }
         }
         // ccap to upstream SCN map
-        for (final Map.Entry<ServiceClassName, List<Ccaps>> entry : upstreamScnMap.entrySet()) {
-            final List<Ccaps> ccapList = entry.getValue();
+        for (final Map.Entry<ServiceClassName, List<Ccap>> entry : upstreamScnMap.entrySet()) {
+            final List<Ccap> ccapList = entry.getValue();
             ccapList.remove(ccap);
             if (ccapList.isEmpty()) {
                 upstreamScnMap.remove(entry.getKey());
             }
         }
         // ccap to downstream SCN map
-        for (final Map.Entry<ServiceClassName, List<Ccaps>> entry : downstreamScnMap.entrySet()) {
-            final List<Ccaps> ccapList = entry.getValue();
+        for (final Map.Entry<ServiceClassName, List<Ccap>> entry : downstreamScnMap.entrySet()) {
+            final List<Ccap> ccapList = entry.getValue();
             ccapList.remove(ccap);
             if (ccapList.isEmpty()) {
                 downstreamScnMap.remove(entry.getKey());
             }
         }
 
-        final PCMMService service = pcmmServiceMap.remove(ccap);
+        final PCMMService service = pcmmServiceMap.remove(ccap.getCcapId());
         if (service != null) service.disconect();
     }
 
-    private Ccaps findCcapForSubscriberId(final InetAddress inetAddr) {
-        Ccaps matchedCcap = null;
+    private Ccap findCcapForSubscriberId(final InetAddress inetAddr) {
+        Ccap matchedCcap = null;
         int longestPrefixLen = -1;
-        for (final Map.Entry<Subnet, Ccaps> entry : subscriberSubnetsMap.entrySet()) {
+        for (final Map.Entry<Subnet, Ccap> entry : subscriberSubnetsMap.entrySet()) {
             final Subnet subnet = entry.getKey();
             if (subnet.isInNet(inetAddr)) {
                 int prefixLen = subnet.getPrefixLen();
@@ -191,14 +208,14 @@ public class PacketcableProvider implements DataChangeListener, AutoCloseable {
         return matchedCcap;
     }
 
-    private ServiceFlowDirection findScnOnCcap(final ServiceClassName scn, final Ccaps ccap) {
+    private ServiceFlowDirection findScnOnCcap(final ServiceClassName scn, final Ccap ccap) {
         if (upstreamScnMap.containsKey(scn)) {
-            final List<Ccaps> ccapList = upstreamScnMap.get(scn);
+            final List<Ccap> ccapList = upstreamScnMap.get(scn);
             if (ccapList.contains(ccap)) {
                 return ServiceFlowDirection.Us;
             }
         } else if (downstreamScnMap.containsKey(scn)) {
-            final List<Ccaps> ccapList = downstreamScnMap.get(scn);
+            final List<Ccap> ccapList = downstreamScnMap.get(scn);
             if (ccapList.contains(ccap)) {
                 return ServiceFlowDirection.Ds;
             }
@@ -212,15 +229,17 @@ public class PacketcableProvider implements DataChangeListener, AutoCloseable {
 
     private class InstanceData {
         // CCAP Identity
-        public final Map<InstanceIdentifier<Ccaps>, Ccaps> ccapIidMap = new HashMap<>();
+        public final Map<InstanceIdentifier<Ccap>, Ccap> ccapIidMap = new HashMap<>();
         // Gate Identity
         public String subId;
         public final Map<String, String> gatePathMap = new HashMap<>();
         public String gatePath;
-        public final Map<InstanceIdentifier<Gates>, Gates> gateIidMap = new HashMap<>();
-        // remove path for either CCAP or Gates
+        public final Map<InstanceIdentifier<Gate>, Gate> gateIidMap = new HashMap<>();
+        // remove path for either CCAP or Gate
         public final Set<String> removePathList = new HashSet<>();
 
+        public final Set<InstanceIdentifier<?>> reqCcapIds = new HashSet<>();
+
         public InstanceData(final Map<InstanceIdentifier<?>, DataObject> thisData) {
             // only used to parse createdData or updatedData
             getCcaps(thisData);
@@ -248,32 +267,32 @@ public class PacketcableProvider implements DataChangeListener, AutoCloseable {
         private void getGatePathMap(final InstanceIdentifier<?> thisInstance) {
             logger.info("onDataChanged().getGatePathMap(): " + thisInstance);
             try {
-                final InstanceIdentifier<Ccaps> ccapInstance = thisInstance.firstIdentifierOf(Ccaps.class);
+                final InstanceIdentifier<Ccap> ccapInstance = thisInstance.firstIdentifierOf(Ccap.class);
                 if (ccapInstance != null) {
-                    final CcapsKey ccapKey = InstanceIdentifier.keyOf(ccapInstance);
+                    final CcapKey ccapKey = InstanceIdentifier.keyOf(ccapInstance);
                     if (ccapKey != null) {
                         gatePathMap.put("ccapId", ccapKey.getCcapId());
                     }
                 } else {
                     // get the gate path keys from the InstanceIdentifier Map key set if they are there
-                    final InstanceIdentifier<Apps> appsInstance = thisInstance.firstIdentifierOf(Apps.class);
-                    if (appsInstance != null) {
-                        final AppsKey appKey = InstanceIdentifier.keyOf(appsInstance);
+                    final InstanceIdentifier<App> appInstance = thisInstance.firstIdentifierOf(App.class);
+                    if (appInstance != null) {
+                        final AppKey appKey = InstanceIdentifier.keyOf(appInstance);
                         if (appKey != null) {
                             gatePathMap.put("appId", appKey.getAppId());
                         }
                     }
-                    final InstanceIdentifier<Subs> subsInstance = thisInstance.firstIdentifierOf(Subs.class);
-                    if (subsInstance != null) {
-                        final SubsKey subKey = InstanceIdentifier.keyOf(subsInstance);
+                    final InstanceIdentifier<Subscriber> subInstance = thisInstance.firstIdentifierOf(Subscriber.class);
+                    if (subInstance != null) {
+                        final SubscriberKey subKey = InstanceIdentifier.keyOf(subInstance);
                         if (subKey != null) {
-                            subId = subKey.getSubId();
+                            subId = subKey.getSubscriberId();
                             gatePathMap.put("subId", subId);
                         }
                     }
-                    final InstanceIdentifier<Gates> gatesInstance = thisInstance.firstIdentifierOf(Gates.class);
+                    final InstanceIdentifier<Gate> gatesInstance = thisInstance.firstIdentifierOf(Gate.class);
                     if (gatesInstance != null) {
-                        final GatesKey gateKey = InstanceIdentifier.keyOf(gatesInstance);
+                        final GateKey gateKey = InstanceIdentifier.keyOf(gatesInstance);
                         if (gateKey != null) {
                             gatePathMap.put("gateId", gateKey.getGateId());
                         }
@@ -287,9 +306,16 @@ public class PacketcableProvider implements DataChangeListener, AutoCloseable {
         private void getCcaps(final Map<InstanceIdentifier<?>, DataObject> thisData) {
             logger.info("onDataChanged().getCcaps(): " + thisData);
             for (final Map.Entry<InstanceIdentifier<?>, DataObject> entry : thisData.entrySet()) {
-                if (entry.getValue() instanceof Ccaps) {
-                    // TODO FIXME - Potential ClassCastException thrown here!!!
-                    ccapIidMap.put((InstanceIdentifier<Ccaps>)entry.getKey(), (Ccaps)entry.getValue());
+
+                if (entry.getKey().getTargetType().equals(Ccap.class)) {
+                    Ccap ccaps = ((Ccap) entry.getValue());
+                    InstanceIdentifier<Ccap> ccapsIid = InstanceIdentifier.builder(Ccaps.class).child(Ccap.class, new CcapKey(ccaps.getCcapId())).build();
+                    ccapIidMap.put(ccapsIid, ccaps);
+                }
+
+                if (entry.getKey().getTargetType().equals(Connection.class) ||
+                        entry.getKey().getTargetType().equals(Ccap.class)) {
+                    reqCcapIds.add(entry.getKey());
                 }
             }
         }
@@ -297,14 +323,37 @@ public class PacketcableProvider implements DataChangeListener, AutoCloseable {
         private void getGates(final Map<InstanceIdentifier<?>, DataObject> thisData) {
             logger.info("onDataChanged().getGates(): " + thisData);
             for (final Map.Entry<InstanceIdentifier<?>, DataObject> entry : thisData.entrySet()) {
-                if (entry.getValue() instanceof Gates) {
-                    final Gates gate = (Gates)entry.getValue();
+                if (entry.getValue() instanceof Gate) {
+                    final Gate gate = (Gate)entry.getValue();
 
                     // TODO FIXME - Potential ClassCastException thrown here!!!
-                    final InstanceIdentifier<Gates> gateIID = (InstanceIdentifier<Gates>)entry.getKey();
+                    final InstanceIdentifier<Gate> gateIID = (InstanceIdentifier<Gate>)entry.getKey();
                     getGatePathMap(gateIID);
-                    gateIidMap.put(gateIID, gate);
+                    if (!gateIidMap.containsKey(gateIID)){
+                        gateIidMap.put(gateIID, gate);
+                    }
                 }
+                // TODO reconciliate gates
+//                if (entry.getValue() instanceof Qos) {
+//                    final Qos qos = (Qos) entry.getValue();
+//                    if (qos.getApps() != null) {
+//                        for (Apps apps : qos.getApps()) {
+//                            if (apps.getSubs() != null) {
+//                                for (Subs subs : apps.getSubs()) {
+//                                    if (subs.getGates() != null) {
+//                                        for (Gate gates : subs.getGates()) {
+//                                            final InstanceIdentifier<Gate> gateIID = (InstanceIdentifier<Gate>)entry.getKey();
+//                                            getGatePathMap(gateIID);
+//                                            if (!gateIidMap.containsKey(gateIID)){
+//                                                gateIidMap.put(gateIID, gates);
+//                                            }
+//                                        }
+//                                    }
+//                                }
+//                            }
+//                        }
+//                    }
+//                }
             }
         }
     }
@@ -315,7 +364,7 @@ public class PacketcableProvider implements DataChangeListener, AutoCloseable {
         // Determine what change action took place by looking at the change object's InstanceIdentifier sets
         // and validate all instance data
         if (!change.getCreatedData().isEmpty()) {
-            if (!new ValidateInstanceData(dataBroker, change.getCreatedData()).validateYang()) {
+            if (!new ValidateInstanceData(mdsalUtils, change.getCreatedData()).validateYang()) {
                 // leave now -- a bad yang object has been detected and a response object has been inserted
                 return;
             }
@@ -323,10 +372,6 @@ public class PacketcableProvider implements DataChangeListener, AutoCloseable {
         } else if (!change.getRemovedPaths().isEmpty()) {
             onRemove(new InstanceData(change.getRemovedPaths()));
         } else if (!change.getUpdatedData().isEmpty()) {
-            if (new ValidateInstanceData(dataBroker, change.getUpdatedData()).isResponseEcho()) {
-                // leave now -- this is an echo of the inserted response object
-                return;
-            }
             onUpdate(new InstanceData(change.getUpdatedData()));
         } else {
             // we should not be here -- complain bitterly and return
@@ -339,32 +384,33 @@ public class PacketcableProvider implements DataChangeListener, AutoCloseable {
 
         // get the CCAP parameters
         String message;
-        if (! thisData.ccapIidMap.isEmpty()) {
-            for (Map.Entry<InstanceIdentifier<Ccaps>, Ccaps> entry : thisData.ccapIidMap.entrySet()) {
-                final Ccaps thisCcap = entry.getValue();
+        if (! thisData.reqCcapIds.isEmpty()) {
+            for (Map.Entry<InstanceIdentifier<Ccap>, Ccap> entry : thisData.ccapIidMap.entrySet()) {
+                final Ccap thisCcap = entry.getValue();
                 // get the CCAP node identity from the Instance Data
                 final String ccapId = thisCcap.getCcapId();
 
-                if (pcmmServiceMap.get(thisCcap) == null) {
+                if (pcmmServiceMap.get(thisCcap.getCcapId()) == null) {
                     final PCMMService pcmmService = new PCMMService(IPCMMClient.CLIENT_TYPE, thisCcap);
                     // TODO - may want to use the AMID but for the client type but probably not???
 /*
                             final PCMMService pcmmService = new PCMMService(
                                     thisCcap.getAmId().getAmType().shortValue(), thisCcap);
 */
-                    pcmmServiceMap.put(thisCcap, pcmmService);
                     message = pcmmService.addCcap();
                     if (message.contains("200 OK")) {
+                        pcmmServiceMap.put(thisCcap.getCcapId(), pcmmService);
                         ccapMap.put(ccapId, thisCcap);
                         updateCcapMaps(thisCcap);
-                        logger.info("onDataChanged(): created CCAP: {}/{} : {}", thisData.gatePath, thisCcap, message);
-                        logger.info("onDataChanged(): created CCAP: {} : {}", thisData.gatePath, message);
+                        logger.info("Created CCAP: {}/{} : {}", thisData.gatePath, thisCcap, message);
+                        logger.info("Created CCAP: {} : {}", thisData.gatePath, message);
                     } else {
-                        // TODO - when a connection cannot be made, need to remove CCAP from ODL cache.
-                        logger.error("onDataChanged(): create CCAP Failed: {} : {}", thisData.gatePath, message);
+                        logger.error("Create CCAP Failed: {} : {}", thisData.gatePath, message);
+                        for (final InstanceIdentifier<?> instId : thisData.reqCcapIds) {
+                            mdsalUtils.delete(LogicalDatastoreType.CONFIGURATION, instId);
+                        }
+                        ccapMap.remove(ccapId);
                     }
-                    // set the response string in the config ccap object using a new thread
-                    executor.execute(new Response(dataBroker, entry.getKey(), thisCcap, message));
                 } else {
                     logger.error("Already monitoring CCAP - " + thisCcap);
                     break;
@@ -372,14 +418,14 @@ public class PacketcableProvider implements DataChangeListener, AutoCloseable {
             }
         } else {
             // get the PCMM gate parameters from the ccapId/appId/subId/gateId path in the Maps entry (if new gate)
-            for (final Map.Entry<InstanceIdentifier<Gates>, Gates> entry : thisData.gateIidMap.entrySet()) {
+            for (final Map.Entry<InstanceIdentifier<Gate>, Gate> entry : thisData.gateIidMap.entrySet()) {
                 message = null;
-                final Gates gate = entry.getValue();
+                final Gate gate = entry.getValue();
                 final String gateId = gate.getGateId();
                 final String gatePathStr = thisData.gatePath + "/" + gateId ;
                 final InetAddress subId = getInetAddress(thisData.subId);
                 if (subId != null) {
-                    final Ccaps thisCcap = findCcapForSubscriberId(subId);
+                    final Ccap thisCcap = findCcapForSubscriberId(subId);
                     if (thisCcap != null) {
                         final String ccapId = thisCcap.getCcapId();
                         // verify SCN exists on CCAP and force gateSpec.Direction to align with SCN direction
@@ -387,19 +433,20 @@ public class PacketcableProvider implements DataChangeListener, AutoCloseable {
                         if (scn != null) {
                             final ServiceFlowDirection scnDir = findScnOnCcap(scn, thisCcap);
                             if (scnDir != null) {
-                                if (pcmmServiceMap.get(thisCcap) != null) {
-                                    message = pcmmServiceMap.get(thisCcap).sendGateSet(gatePathStr, subId, gate, scnDir);
+                                if (pcmmServiceMap.get(thisCcap.getCcapId()) != null) {
+                                    message = pcmmServiceMap.get(thisCcap.getCcapId()).sendGateSet(gatePathStr, subId, gate, scnDir);
+                                    gateMap.put(gatePathStr, gate);
+                                    gateCcapMap.put(gatePathStr, thisCcap.getCcapId());
+
                                     if (message.contains("200 OK")) {
-                                        gateMap.put(gatePathStr, gate);
-                                        gateCcapMap.put(gatePathStr, thisCcap.getCcapId());
-                                        logger.info("onDataChanged(): created QoS gate {} for {}/{}/{} - {}",
+                                        logger.info("Created QoS gate {} for {}/{}/{} - {}",
                                                 gateId, ccapId, gatePathStr, gate, message);
-                                        logger.info("onDataChanged(): created QoS gate {} for {}/{} - {}",
+                                        logger.info("Created QoS gate {} for {}/{} - {}",
                                                 gateId, ccapId, gatePathStr, message);
                                     } else {
-                                        logger.info("onDataChanged(): Unable to create QoS gate {} for {}/{}/{} - {}",
+                                        logger.info("Unable to create QoS gate {} for {}/{}/{} - {}",
                                                 gateId, ccapId, gatePathStr, gate, message);
-                                        logger.error("onDataChanged(): Unable to create QoS gate {} for {}/{} - {}",
+                                        logger.error("Unable to create QoS gate {} for {}/{} - {}",
                                                 gateId, ccapId, gatePathStr, message);
                                     }
                                 } else {
@@ -417,22 +464,23 @@ public class PacketcableProvider implements DataChangeListener, AutoCloseable {
                         final String subIdStr = thisData.subId;
                         message = String.format("404 Not Found - no CCAP found for subscriber %s in %s",
                                 subIdStr, gatePathStr);
-                        logger.info("onDataChanged(): create QoS gate {} FAILED: no CCAP found for subscriber {}: @ {}/{}",
+                        logger.info("Create QoS gate {} FAILED: no CCAP found for subscriber {}: @ {}/{}",
                                 gateId, subIdStr, gatePathStr, gate);
-                        logger.error("onDataChanged(): create QoS gate {} FAILED: no CCAP found for subscriber {}: @ {}",
+                        logger.error("Create QoS gate {} FAILED: no CCAP found for subscriber {}: @ {}",
                                 gateId, subIdStr, gatePathStr);
                     }
                 } else {
                     final String subIdStr = thisData.subId;
                     message = String.format("400 Bad Request - subId must be a valid IP address for subscriber %s in %s",
                             subIdStr, gatePathStr);
-                    logger.info("onDataChanged(): create QoS gate {} FAILED: subId must be a valid IP address for subscriber {}: @ {}/{}",
+                    logger.info("Create QoS gate {} FAILED: subId must be a valid IP address for subscriber {}: @ {}/{}",
                             gateId, subIdStr, gatePathStr, gate);
-                    logger.error("onDataChanged(): create QoS gate {} FAILED: subId must be a valid IP address for subscriber {}: @ {}",
+                    logger.error("Create QoS gate {} FAILED: subId must be a valid IP address for subscriber {}: @ {}",
                             gateId, subIdStr, gatePathStr);
                 }
-                // set the response message in the config gate object using a new thread
-                executor.execute(new Response(dataBroker, entry.getKey(), gate, message));
+                if (!message.contains("200 OK")) {
+                    mdsalUtils.delete(LogicalDatastoreType.CONFIGURATION, entry.getKey());
+                }
             }
         }
     }
@@ -441,11 +489,11 @@ public class PacketcableProvider implements DataChangeListener, AutoCloseable {
         logger.info("onRemove(): " + thisData);
         for (final String gatePathStr: thisData.removePathList) {
             if (gateMap.containsKey(gatePathStr)) {
-                final Gates thisGate = gateMap.remove(gatePathStr);
+                final Gate thisGate = gateMap.remove(gatePathStr);
                 final String gateId = thisGate.getGateId();
                 final String ccapId = gateCcapMap.remove(gatePathStr);
-                final Ccaps thisCcap = ccapMap.get(ccapId);
-                final PCMMService service = pcmmServiceMap.get(thisCcap);
+                final Ccap thisCcap = ccapMap.get(ccapId);
+                final PCMMService service = pcmmServiceMap.get(thisCcap.getCcapId());
                 if (service != null) {
                     service.sendGateDelete(gatePathStr);
                     logger.info("onDataChanged(): removed QoS gate {} for {}/{}/{}: ", gateId, ccapId, gatePathStr, thisGate);
@@ -457,7 +505,7 @@ public class PacketcableProvider implements DataChangeListener, AutoCloseable {
         }
         for (final String ccapIdStr: thisData.removePathList) {
             if (ccapMap.containsKey(ccapIdStr)) {
-                final Ccaps thisCcap = ccapMap.remove(ccapIdStr);
+                final Ccap thisCcap = ccapMap.remove(ccapIdStr);
                 removeCcapFromAllMaps(thisCcap);
             }
         }
@@ -467,29 +515,21 @@ public class PacketcableProvider implements DataChangeListener, AutoCloseable {
         logger.info("onUpdate(): " + oldData);
         // update operation not allowed -- restore the original config object and complain
         if (! oldData.ccapIidMap.isEmpty()) {
-            for (final Map.Entry<InstanceIdentifier<Ccaps>, Ccaps> entry : oldData.ccapIidMap.entrySet()) {
-                final Ccaps ccap = entry.getValue();
+            for (final Map.Entry<InstanceIdentifier<Ccap>, Ccap> entry : oldData.ccapIidMap.entrySet()) {
+                final Ccap ccap = entry.getValue();
                 final String ccapId = ccap.getCcapId();
-                String message = String.format("405 Method Not Allowed - %s: CCAP update not permitted (use delete); ",
-                        ccapId);
-                // push new error message onto existing response
-                message += ccap.getResponse();
-                // set the response message in the config object using a new thread -- also restores the original data
-                executor.execute(new Response(dataBroker, entry.getKey(), ccap, message));
+                // restores the original data - although I don't think this is what is done here! I think the update data is put into the DS/config
+                mdsalUtils.merge(LogicalDatastoreType.CONFIGURATION, entry.getKey(), ccap);
                 logger.error("onDataChanged(): CCAP update not permitted {}/{}", ccapId, ccap);
             }
         } else {
-            for (final Map.Entry<InstanceIdentifier<Gates>, Gates> entry : oldData.gateIidMap.entrySet()) {
-                final Gates gate = entry.getValue();
+            for (final Map.Entry<InstanceIdentifier<Gate>, Gate> entry : oldData.gateIidMap.entrySet()) {
+                final Gate gate = entry.getValue();
                 final String gatePathStr = oldData.gatePath + "/" + gate.getGateId() ;
-                String message = String.format("405 Method Not Allowed - %s: QoS Gate update not permitted (use delete); ", gatePathStr);
-                // push new error message onto existing response
-                message += gate.getResponse();
-                // set the response message in the config object using a new thread -- also restores the original data
-                executor.execute(new Response(dataBroker, entry.getKey(), gate, message));
+             // restores the original data - although I don't think this is what is done here! I think the update data is put into the DS/config
+                mdsalUtils.merge(LogicalDatastoreType.CONFIGURATION, entry.getKey(), gate);
                 logger.error("onDataChanged(): QoS Gate update not permitted: {}/{}", gatePathStr, gate);
             }
         }
     }
-
 }