Convert packetcable-policy-server to blueprint
[packetcable.git] / packetcable-policy-server / src / main / java / org / opendaylight / controller / packetcable / provider / PacketcableProvider.java
1 /*
2  * Copyright (c) 2015 CableLabs and others.  All rights reserved.
3  *
4  * This program and the accompanying materials are made available under the
5  * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6  * and is available at http://www.eclipse.org/legal/epl-v10.html
7  */
8
9 package org.opendaylight.controller.packetcable.provider;
10
11 import static com.google.common.base.Preconditions.checkNotNull;
12
13 import com.google.common.base.Optional;
14 import com.google.common.collect.Sets;
15 import com.google.common.util.concurrent.CheckedFuture;
16 import com.google.common.util.concurrent.Futures;
17 import java.net.InetAddress;
18 import java.net.UnknownHostException;
19 import java.text.DateFormat;
20 import java.text.SimpleDateFormat;
21 import java.util.ArrayList;
22 import java.util.Collections;
23 import java.util.Date;
24 import java.util.List;
25 import java.util.Map;
26 import java.util.Objects;
27 import java.util.Set;
28 import java.util.concurrent.ConcurrentHashMap;
29 import java.util.concurrent.ExecutionException;
30 import java.util.concurrent.Executor;
31 import java.util.concurrent.Executors;
32 import java.util.concurrent.Future;
33 import javax.annotation.Nonnull;
34 import javax.annotation.concurrent.ThreadSafe;
35 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
36 import org.opendaylight.controller.md.sal.binding.api.DataTreeChangeListener;
37 import org.opendaylight.controller.md.sal.binding.api.DataTreeIdentifier;
38 import org.opendaylight.controller.md.sal.binding.api.DataTreeModification;
39 import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
40 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
41 import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException;
42 import org.opendaylight.controller.packetcable.provider.validation.DataValidator;
43 import org.opendaylight.controller.packetcable.provider.validation.ValidationException;
44 import org.opendaylight.controller.packetcable.provider.validation.impl.CcapsValidatorProviderFactory;
45 import org.opendaylight.controller.packetcable.provider.validation.impl.QosValidatorProviderFactory;
46 import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.RoutedRpcRegistration;
47 import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.RpcRegistration;
48 import org.opendaylight.controller.sal.binding.api.RpcProviderRegistry;
49 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpPrefix;
50 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv4Prefix;
51 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.DateAndTime;
52 import org.opendaylight.yang.gen.v1.urn.packetcable.rev170224.AppContext;
53 import org.opendaylight.yang.gen.v1.urn.packetcable.rev170224.CcapContext;
54 import org.opendaylight.yang.gen.v1.urn.packetcable.rev170224.CcapPollConnectionInput;
55 import org.opendaylight.yang.gen.v1.urn.packetcable.rev170224.CcapPollConnectionOutput;
56 import org.opendaylight.yang.gen.v1.urn.packetcable.rev170224.CcapPollConnectionOutputBuilder;
57 import org.opendaylight.yang.gen.v1.urn.packetcable.rev170224.CcapSetConnectionInput;
58 import org.opendaylight.yang.gen.v1.urn.packetcable.rev170224.CcapSetConnectionOutput;
59 import org.opendaylight.yang.gen.v1.urn.packetcable.rev170224.CcapSetConnectionOutputBuilder;
60 import org.opendaylight.yang.gen.v1.urn.packetcable.rev170224.Ccaps;
61 import org.opendaylight.yang.gen.v1.urn.packetcable.rev170224.FailureType;
62 import org.opendaylight.yang.gen.v1.urn.packetcable.rev170224.PacketcableService;
63 import org.opendaylight.yang.gen.v1.urn.packetcable.rev170224.Qos;
64 import org.opendaylight.yang.gen.v1.urn.packetcable.rev170224.QosDeleteGateInput;
65 import org.opendaylight.yang.gen.v1.urn.packetcable.rev170224.QosDeleteGateOutput;
66 import org.opendaylight.yang.gen.v1.urn.packetcable.rev170224.QosDeleteGateOutputBuilder;
67 import org.opendaylight.yang.gen.v1.urn.packetcable.rev170224.QosGateInfoInput;
68 import org.opendaylight.yang.gen.v1.urn.packetcable.rev170224.QosGateInfoOutput;
69 import org.opendaylight.yang.gen.v1.urn.packetcable.rev170224.QosGateInfoOutputBuilder;
70 import org.opendaylight.yang.gen.v1.urn.packetcable.rev170224.QosPollGatesInput;
71 import org.opendaylight.yang.gen.v1.urn.packetcable.rev170224.QosPollGatesOutput;
72 import org.opendaylight.yang.gen.v1.urn.packetcable.rev170224.QosPollGatesOutputBuilder;
73 import org.opendaylight.yang.gen.v1.urn.packetcable.rev170224.QosSetGateInput;
74 import org.opendaylight.yang.gen.v1.urn.packetcable.rev170224.QosSetGateOutput;
75 import org.opendaylight.yang.gen.v1.urn.packetcable.rev170224.QosSetGateOutputBuilder;
76 import org.opendaylight.yang.gen.v1.urn.packetcable.rev170224.ServiceClassName;
77 import org.opendaylight.yang.gen.v1.urn.packetcable.rev170224.ServiceFlowDirection;
78 import org.opendaylight.yang.gen.v1.urn.packetcable.rev170224.ccap.attributes.ConnectionBuilder;
79 import org.opendaylight.yang.gen.v1.urn.packetcable.rev170224.ccaps.Ccap;
80 import org.opendaylight.yang.gen.v1.urn.packetcable.rev170224.ccaps.CcapBuilder;
81 import org.opendaylight.yang.gen.v1.urn.packetcable.rev170224.pcmm.qos.gate.spec.GateSpec;
82 import org.opendaylight.yang.gen.v1.urn.packetcable.rev170224.pcmm.qos.gate.spec.GateSpecBuilder;
83 import org.opendaylight.yang.gen.v1.urn.packetcable.rev170224.pcmm.qos.gates.Apps;
84 import org.opendaylight.yang.gen.v1.urn.packetcable.rev170224.pcmm.qos.gates.apps.App;
85 import org.opendaylight.yang.gen.v1.urn.packetcable.rev170224.pcmm.qos.gates.apps.AppBuilder;
86 import org.opendaylight.yang.gen.v1.urn.packetcable.rev170224.pcmm.qos.gates.apps.AppKey;
87 import org.opendaylight.yang.gen.v1.urn.packetcable.rev170224.pcmm.qos.gates.apps.app.Subscribers;
88 import org.opendaylight.yang.gen.v1.urn.packetcable.rev170224.pcmm.qos.gates.apps.app.SubscribersBuilder;
89 import org.opendaylight.yang.gen.v1.urn.packetcable.rev170224.pcmm.qos.gates.apps.app.subscribers.Subscriber;
90 import org.opendaylight.yang.gen.v1.urn.packetcable.rev170224.pcmm.qos.gates.apps.app.subscribers.SubscriberBuilder;
91 import org.opendaylight.yang.gen.v1.urn.packetcable.rev170224.pcmm.qos.gates.apps.app.subscribers.SubscriberKey;
92 import org.opendaylight.yang.gen.v1.urn.packetcable.rev170224.pcmm.qos.gates.apps.app.subscribers.subscriber.Gates;
93 import org.opendaylight.yang.gen.v1.urn.packetcable.rev170224.pcmm.qos.gates.apps.app.subscribers.subscriber.GatesBuilder;
94 import org.opendaylight.yang.gen.v1.urn.packetcable.rev170224.pcmm.qos.gates.apps.app.subscribers.subscriber.gates.Gate;
95 import org.opendaylight.yang.gen.v1.urn.packetcable.rev170224.pcmm.qos.gates.apps.app.subscribers.subscriber.gates.GateBuilder;
96 import org.opendaylight.yang.gen.v1.urn.packetcable.rev170224.pcmm.qos.gates.apps.app.subscribers.subscriber.gates.GateKey;
97 import org.opendaylight.yang.gen.v1.urn.packetcable.rev170224.pcmm.qos.traffic.profile.TrafficProfile;
98 import org.opendaylight.yang.gen.v1.urn.packetcable.rev170224.pcmm.qos.traffic.profile.TrafficProfileBuilder;
99 import org.opendaylight.yang.gen.v1.urn.packetcable.rev170224.pcmm.qos.traffic.profile.traffic.profile.traffic.profile.choice.ServiceClassNameChoice;
100 import org.opendaylight.yang.gen.v1.urn.packetcable.rev170224.pcmm.qos.traffic.profile.traffic.profile.traffic.profile.choice.ServiceClassNameChoiceBuilder;
101 import org.opendaylight.yang.gen.v1.urn.packetcable.rev170224.pcmm.serviceclass.name.profile.ServiceClassNameProfile;
102 import org.opendaylight.yang.gen.v1.urn.packetcable.rev170224.pcmm.serviceclass.name.profile.ServiceClassNameProfileBuilder;
103 import org.opendaylight.yang.gen.v1.urn.packetcable.rev170224.qos.delete.gate.response.delete.response.type.DeleteFailure;
104 import org.opendaylight.yang.gen.v1.urn.packetcable.rev170224.qos.delete.gate.response.delete.response.type.DeleteFailureBuilder;
105 import org.opendaylight.yang.gen.v1.urn.packetcable.rev170224.qos.delete.gate.response.delete.response.type.DeleteSuccessful;
106 import org.opendaylight.yang.gen.v1.urn.packetcable.rev170224.qos.delete.gate.response.delete.response.type.DeleteSuccessfulBuilder;
107 import org.opendaylight.yang.gen.v1.urn.packetcable.rev170224.qos.gate.info.response.info.response.type.InfoFailure;
108 import org.opendaylight.yang.gen.v1.urn.packetcable.rev170224.qos.gate.info.response.info.response.type.InfoFailureBuilder;
109 import org.opendaylight.yang.gen.v1.urn.packetcable.rev170224.qos.gate.info.response.info.response.type.InfoSuccessful;
110 import org.opendaylight.yang.gen.v1.urn.packetcable.rev170224.qos.gate.info.response.info.response.type.InfoSuccessfulBuilder;
111 import org.opendaylight.yang.gen.v1.urn.packetcable.rev170224.qos.set.gate.response.set.response.type.SetFailure;
112 import org.opendaylight.yang.gen.v1.urn.packetcable.rev170224.qos.set.gate.response.set.response.type.SetFailureBuilder;
113 import org.opendaylight.yang.gen.v1.urn.packetcable.rev170224.qos.set.gate.response.set.response.type.SetSuccessful;
114 import org.opendaylight.yang.gen.v1.urn.packetcable.rev170224.qos.set.gate.response.set.response.type.SetSuccessfulBuilder;
115 import org.opendaylight.yangtools.concepts.ListenerRegistration;
116 import org.opendaylight.yangtools.yang.binding.DataObject;
117 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
118 import org.opendaylight.yangtools.yang.common.RpcResult;
119 import org.opendaylight.yangtools.yang.common.RpcResultBuilder;
120 import org.pcmm.rcd.IPCMMClient;
121 import org.slf4j.Logger;
122 import org.slf4j.LoggerFactory;
123
124 /**
125  * Called by ODL framework to start this bundle.
126  * <p>
127  * This class is responsible for processing messages received from ODL's restconf interface.
128  * TODO - Remove some of these state maps and move some of this into the PCMMService
129  * TODO Don't implement PacketcableService, move that into an inner class
130  */
131 @ThreadSafe
132 public class PacketcableProvider implements AutoCloseable, PacketcableService {
133
134     private static final Logger logger = LoggerFactory.getLogger(PacketcableProvider.class);
135
136     // keys to the /restconf/config/packetcable:ccaps and /restconf/config/packetcable:qos config datastore
137     private static final InstanceIdentifier<Ccaps> ccapsIID = InstanceIdentifier.builder(Ccaps.class).build();
138     private static final InstanceIdentifier<Qos> qosIID = InstanceIdentifier.builder(Qos.class).build();
139
140     // TODO - Revisit these maps and remove the ones no longer necessary
141     private final Map<String, Ccap> ccapMap = new ConcurrentHashMap<>();
142     private final Map<String, Gate> gateMap = new ConcurrentHashMap<>();
143     private final Map<String, String> gateCcapMap = new ConcurrentHashMap<>();
144     private final Map<Subnet, Ccap> subscriberSubnetsMap = new ConcurrentHashMap<>();
145     private final Map<ServiceClassName, List<Ccap>> downstreamScnMap = new ConcurrentHashMap<>();
146     private final Map<ServiceClassName, List<Ccap>> upstreamScnMap = new ConcurrentHashMap<>();
147
148     private final Executor executor = Executors.newSingleThreadExecutor();
149
150     /**
151      * Holds a PCMMService object for each CCAP being managed.
152      */
153     private final Map<String, PCMMService> pcmmServiceMap = new ConcurrentHashMap<>();
154
155     /**
156      * The ODL object used to broker messages throughout the framework
157      */
158     private final DataBroker dataBroker;
159     private final MdsalUtils mdsalUtils;
160
161     //Routed RPC Registration
162     private RoutedRpcRegistration<PacketcableService> routedRpcRegistration;
163
164     // unrouted RPC Registration
165     private RpcRegistration<PacketcableService> rpcRegistration;
166
167     // Data change listeners/registrations
168     private final CcapsDataTreeChangeListener ccapsDataTreeChangeListener = new CcapsDataTreeChangeListener();
169     private final QosDataTreeChangeListener qosDataTreeChangeListener = new QosDataTreeChangeListener();
170
171     private ListenerRegistration<DataTreeChangeListener> ccapsDataTreeChangeListenerRegistration;
172     private ListenerRegistration<DataTreeChangeListener> qosDataTreeChangeListenerRegistration;
173
174     private final RpcProviderRegistry rpcProviderRegistry;
175
176     /**
177      * Constructor
178      */
179     public PacketcableProvider(final DataBroker dataBroker, final RpcProviderRegistry rpcProviderRegistry) {
180         logger.info("Starting Packetcable Provider");
181         this.dataBroker = dataBroker;
182         this.rpcProviderRegistry = rpcProviderRegistry;
183         mdsalUtils = new MdsalUtils(dataBroker);
184     }
185
186     public void init() {
187         logger.info("logging levels: error={}, warn={}, info={}, debug={}, trace={}",
188                     logger.isErrorEnabled(), logger.isWarnEnabled(),
189                     logger.isInfoEnabled(), logger.isDebugEnabled(), logger.isTraceEnabled());
190
191         final DataTreeIdentifier<Ccap> ccapsDataTreeIid =
192                 new DataTreeIdentifier<>(LogicalDatastoreType.CONFIGURATION, ccapsIID.child(Ccap.class));
193
194         final DataTreeIdentifier<Gate> appDataTreeIid =
195                 new DataTreeIdentifier<>(LogicalDatastoreType.CONFIGURATION,
196                         qosIID.child(Apps.class).child(App.class).child(Subscribers.class).child(Subscriber.class).child(Gates.class).child(Gate.class));
197
198         ccapsDataTreeChangeListenerRegistration =
199                 dataBroker.registerDataTreeChangeListener(ccapsDataTreeIid, new CcapsDataTreeChangeListener());
200
201         qosDataTreeChangeListenerRegistration = dataBroker.registerDataTreeChangeListener(appDataTreeIid, new QosDataTreeChangeListener());
202
203         rpcRegistration = rpcProviderRegistry.addRpcImplementation(PacketcableService.class, this);
204         routedRpcRegistration = rpcProviderRegistry.addRoutedRpcImplementation(PacketcableService.class, this);
205
206         logger.info("Packetcable Session Initiated");
207     }
208
209     /**
210      * Implemented from the AutoCloseable interface.
211      */
212     @Override
213     public void close() throws ExecutionException, InterruptedException {
214         if (ccapsDataTreeChangeListenerRegistration != null) {
215             ccapsDataTreeChangeListenerRegistration.close();
216         }
217
218         if (qosDataTreeChangeListenerRegistration != null) {
219             qosDataTreeChangeListenerRegistration.close();
220         }
221
222         if (rpcRegistration != null) {
223             rpcRegistration.close();
224         }
225
226         if (routedRpcRegistration != null) {
227             routedRpcRegistration.close();
228         }
229     }
230
231     private void updateCcapMaps(final Ccap ccap) {
232         // add ccap to the subscriberSubnets map
233         for (final IpPrefix ipPrefix : ccap.getSubscriberSubnets()) {
234             try {
235                 subscriberSubnetsMap.put(Subnet.createInstance(getIpPrefixStr(ipPrefix)), ccap);
236             } catch (UnknownHostException e) {
237                 logger.error("updateSubscriberSubnets: {}:{} FAILED: {}", ipPrefix, ccap, e.getMessage());
238             }
239         }
240         // ccap to upstream SCN map
241         for (final ServiceClassName scn : ccap.getUpstreamScns()) {
242             if (upstreamScnMap.containsKey(scn)) {
243                 upstreamScnMap.get(scn).add(ccap);
244             } else {
245                 final List<Ccap> ccapList = new ArrayList<>();
246                 ccapList.add(ccap);
247                 upstreamScnMap.put(scn, ccapList);
248             }
249         }
250         // ccap to downstream SCN map
251         for (final ServiceClassName scn : ccap.getDownstreamScns()) {
252             if (downstreamScnMap.containsKey(scn)) {
253                 downstreamScnMap.get(scn).add(ccap);
254             } else {
255                 final List<Ccap> ccapList = new ArrayList<>();
256                 ccapList.add(ccap);
257                 downstreamScnMap.put(scn, ccapList);
258             }
259         }
260     }
261
262     private String getIpPrefixStr(final IpPrefix ipPrefix) {
263         final Ipv4Prefix ipv4 = ipPrefix.getIpv4Prefix();
264         if (ipv4 != null) {
265             return ipv4.getValue();
266         } else {
267             return ipPrefix.getIpv6Prefix().getValue();
268         }
269     }
270
271     public InetAddress getInetAddress(final String subId) {
272         try {
273             return InetAddress.getByName(subId);
274         } catch (UnknownHostException e) {
275             logger.error("getInetAddress: {} FAILED: {}", subId, e.getMessage());
276             return null;
277         }
278     }
279
280     private Ccap findCcapForSubscriberId(final InetAddress inetAddr) {
281         // TODO replace this with a loading cache, https://github.com/google/guava/wiki/CachesExplained
282         Ccap matchedCcap = null;
283         int longestPrefixLen = -1;
284         for (final Map.Entry<Subnet, Ccap> entry : subscriberSubnetsMap.entrySet()) {
285             final Subnet subnet = entry.getKey();
286             if (subnet.isInNet(inetAddr)) {
287                 int prefixLen = subnet.getPrefixLen();
288                 if (prefixLen > longestPrefixLen) {
289                     matchedCcap = entry.getValue();
290                     longestPrefixLen = prefixLen;
291                 }
292             }
293         }
294         return matchedCcap;
295     }
296
297     private ServiceFlowDirection findScnOnCcap(final ServiceClassName scn, final Ccap ccap) {
298         checkNotNull(scn);
299         checkNotNull(ccap);
300
301         if (upstreamScnMap.containsKey(scn)) {
302             final List<Ccap> ccapList = upstreamScnMap.get(scn);
303             if (ccapList.contains(ccap)) {
304                 return ServiceFlowDirection.Us;
305             }
306         } else if (downstreamScnMap.containsKey(scn)) {
307             final List<Ccap> ccapList = downstreamScnMap.get(scn);
308             if (ccapList.contains(ccap)) {
309                 return ServiceFlowDirection.Ds;
310             }
311         }
312         return null;
313     }
314
315     private void removeCcapFromAllMaps(final Ccap ccap) {
316         // remove the ccap from all maps
317         // subscriberSubnets map
318         for (final Map.Entry<Subnet, Ccap> entry : subscriberSubnetsMap.entrySet()) {
319             if (entry.getValue() == ccap) {
320                 subscriberSubnetsMap.remove(entry.getKey());
321             }
322         }
323         // ccap to upstream SCN map
324         for (final Map.Entry<ServiceClassName, List<Ccap>> entry : upstreamScnMap.entrySet()) {
325             final List<Ccap> ccapList = entry.getValue();
326             ccapList.remove(ccap);
327             if (ccapList.isEmpty()) {
328                 upstreamScnMap.remove(entry.getKey());
329             }
330         }
331         // ccap to downstream SCN map
332         for (final Map.Entry<ServiceClassName, List<Ccap>> entry : downstreamScnMap.entrySet()) {
333             final List<Ccap> ccapList = entry.getValue();
334             ccapList.remove(ccap);
335             if (ccapList.isEmpty()) {
336                 downstreamScnMap.remove(entry.getKey());
337             }
338         }
339
340         final PCMMService service = pcmmServiceMap.remove(ccap.getCcapId());
341         if (service != null) {
342             service.disconect();
343         }
344     }
345
346     // ValidationException does not need to be thrown again
347     @SuppressWarnings("ThrowableResultOfMethodCallIgnored")
348     private <T extends DataObject> void saveErrors(@Nonnull DataTreeModification<T> change, ValidationException exception) {
349
350         final WriteTransaction writeTransaction = dataBroker.newWriteOnlyTransaction();
351
352         InstanceIdentifier<T> iid = change.getRootPath().getRootIdentifier();
353         //final ValidationException exception = exceptionMap.get(change);
354         final T badData = change.getRootNode().getDataAfter();
355
356         if (badData instanceof Ccap) {
357             final Ccap ccap = (Ccap) badData;
358
359             final Ccap opperationalCcap =
360                     new CcapBuilder().setCcapId(ccap.getCcapId()).setError(exception.getErrorMessages()).build();
361
362             @SuppressWarnings("unchecked") final InstanceIdentifier<Ccap> ccapIID = (InstanceIdentifier<Ccap>) change;
363             writeTransaction.put(LogicalDatastoreType.OPERATIONAL, ccapIID, opperationalCcap);
364         } else if (badData instanceof Gate) {
365             final Gate gate = (Gate) badData;
366
367             final Gate operationalGate =
368                     new GateBuilder().setGateId(gate.getGateId()).setError(exception.getErrorMessages()).build();
369
370             final Gates operationalGates =
371                     new GatesBuilder().setGate(Collections.singletonList(operationalGate)).build();
372
373             final SubscriberKey subscriberKey = InstanceIdentifier.keyOf(iid.firstIdentifierOf(Subscriber.class));
374             final Subscriber operationalSubscriber =
375                     new SubscriberBuilder().setSubscriberId(subscriberKey.getSubscriberId())
376                             .setGates(operationalGates)
377                             .build();
378
379             final Subscribers operationalSubscribers =
380                     new SubscribersBuilder().setSubscriber(Collections.singletonList(operationalSubscriber))
381                             .build();
382
383             final InstanceIdentifier<App> appIID = iid.firstIdentifierOf(App.class);
384             final AppKey appKey = InstanceIdentifier.keyOf(appIID);
385             final App operationalApp =
386                     new AppBuilder().setAppId(appKey.getAppId()).setSubscribers(operationalSubscribers).build();
387
388
389             writeTransaction.put(LogicalDatastoreType.OPERATIONAL, appIID, operationalApp);
390         } else {
391             // If you get here a developer forgot to add a type above
392             logger.error("Unexpected type requested for error saving: {}", badData);
393             throw new IllegalStateException("Unsupported type for error saving");
394         }
395
396         CheckedFuture<Void, TransactionCommitFailedException> future = writeTransaction.submit();
397
398         try {
399             future.checkedGet();
400         } catch (TransactionCommitFailedException e) {
401             logger.error("Failed to write errors to operational datastore", e);
402         }
403     }
404
405     /**
406      * Removes Ccaps if all Ccap instances are removed
407      */
408     private class CcapsCleaner extends AbstractCleaner<Ccaps> {
409
410         public CcapsCleaner(final InstanceIdentifier<?> removedIID) {
411             super(removedIID, Ccaps.class, LogicalDatastoreType.OPERATIONAL);
412         }
413
414         @Override
415         protected boolean shouldClean(final Ccaps ccaps) {
416             return ccaps.getCcap().isEmpty();
417         }
418     }
419
420
421     /**
422      * Removes Subscriber if all Gate instances are removed
423      */
424     private class SubscriberCleaner extends AbstractCleaner<Subscriber> {
425
426         public SubscriberCleaner(InstanceIdentifier<Gate> removedGateIID) {
427             super(removedGateIID, Subscriber.class, LogicalDatastoreType.OPERATIONAL);
428         }
429
430         @Override
431         protected boolean shouldClean(final Subscriber subscriber) {
432             return subscriber.getGates().getGate().isEmpty();
433         }
434
435         @Override
436         protected void postRemove(InstanceIdentifier<Subscriber> subscriberIID) {
437             executor.execute(new AppCleaner(subscriberIID));
438         }
439     }
440
441
442     /**
443      * Removes App if all Subscribers are removed.
444      */
445     private class AppCleaner extends AbstractCleaner<App> {
446
447         public AppCleaner(InstanceIdentifier<Subscriber> removedSubscriberIID) {
448             super(removedSubscriberIID, App.class, LogicalDatastoreType.OPERATIONAL);
449         }
450
451         @Override
452         boolean shouldClean(final App app) {
453             return app.getSubscribers().getSubscriber().isEmpty();
454         }
455
456         @Override
457         void postRemove(final InstanceIdentifier<App> appIID) {
458             //unregister app rpc path
459             logger.info("Un-Registering App Routed RPC Path...");
460             routedRpcRegistration.unregisterPath(AppContext.class, appIID);
461             executor.execute(new AppsCleaner(appIID));
462         }
463     }
464
465
466     /**
467      * Removes Apps if all App instances are removed.
468      */
469     private class AppsCleaner extends AbstractCleaner<Apps> {
470
471         public AppsCleaner(InstanceIdentifier<App> removedAppIID) {
472             super(removedAppIID, Apps.class, LogicalDatastoreType.OPERATIONAL);
473         }
474
475         @Override
476         protected boolean shouldClean(final Apps apps) {
477             return apps.getApp().isEmpty();
478         }
479     }
480
481
482     /**
483      * Helper class to do the heavy lifting in removing object. Lets subclasses decide with
484      * {@link #shouldClean(DataObject)}. <br>
485      * <p>
486      * Subclasses can react after an instance is removed by overriding {@link #postRemove(InstanceIdentifier)}
487      *
488      * @param <T>
489      *         The type that will be removed
490      */
491     private abstract class AbstractCleaner<T extends DataObject> implements Runnable {
492         final InstanceIdentifier<?> removedIID;
493         final Class<T> tClass;
494         final LogicalDatastoreType datastoreType;
495
496         public AbstractCleaner(InstanceIdentifier<?> removedIID, Class<T> tClass, LogicalDatastoreType datastoreType) {
497             this.removedIID = checkNotNull(removedIID);
498             this.tClass = checkNotNull(tClass);
499             this.datastoreType = checkNotNull(datastoreType);
500         }
501
502         @Override
503         public void run() {
504             InstanceIdentifier<T> tIID = removedIID.firstIdentifierOf(tClass);
505             if (tIID != null) {
506                 Optional<T> optional = mdsalUtils.read(datastoreType, tIID);
507                 if (optional.isPresent()) {
508
509                     if (shouldClean(optional.get())) {
510                         if (mdsalUtils.delete(datastoreType, tIID)) {
511                             postRemove(tIID);
512                         } else {
513                             removeFailed(tIID);
514                         }
515                     }
516
517                 }
518             } else {
519                 logger.error("Expected to find InstanceIdentifier<{}> but was not found: {}", tClass.getSimpleName(),
520                         removedIID);
521             }
522         }
523
524         /**
525          * If returns true the object will be removed from the datastore
526          *
527          * @param object
528          *         The object that might be removed.
529          * @return true if it should be removed.
530          */
531         abstract boolean shouldClean(final T object);
532
533         /**
534          * Called after an instance is removed.
535          *
536          * @param tIID
537          *         the InstanceIdentifier of the removed object
538          */
539         void postRemove(InstanceIdentifier<T> tIID) {
540
541         }
542
543         void removeFailed(InstanceIdentifier<T> tIID) {
544             logger.error("Failed to remove {}", tIID);
545         }
546     }
547
548
549     /**
550      * Listener for the packetcable:ccaps tree
551      */
552     private class CcapsDataTreeChangeListener extends AbstractDataTreeChangeListener<Ccap> {
553
554         private final Set<InstanceIdentifier<Ccap>> updateQueue = Sets.newConcurrentHashSet();
555
556         public CcapsDataTreeChangeListener() {
557             super(Ccap.class,new DataValidator(new CcapsValidatorProviderFactory().build()));
558         }
559
560         @Override
561         protected void handleCreatedData(final DataTreeModification<Ccap> change) {
562             final Ccap ccap = change.getRootNode().getDataAfter();
563             InstanceIdentifier<Ccap> iid = change.getRootPath().getRootIdentifier();
564
565             // add service
566             if (pcmmServiceMap.containsKey(ccap.getCcapId())) {
567                 logger.error("Already monitoring CCAP - " + ccap);
568                 return;
569             }
570             final PCMMService pcmmService = new PCMMService(IPCMMClient.CLIENT_TYPE, ccap);
571             // TODO - may want to use the AMID but for the client type but probably not???
572 /*
573                     final PCMMService pcmmService = new PCMMService(
574                             thisCcap.getAmId().getAmType().shortValue(), thisCcap);
575 */
576             ConnectionBuilder connectionBuilder = new ConnectionBuilder();
577             String message = pcmmService.addCcap();
578             if (message.contains("200 OK")) {
579                 pcmmServiceMap.put(ccap.getCcapId(), pcmmService);
580                 ccapMap.put(ccap.getCcapId(), ccap);
581                 updateCcapMaps(ccap);
582                 logger.info("Created CCAP: {}/{} : {}", iid, ccap, message);
583                 logger.info("Created CCAP: {} : {}", iid, message);
584
585                 connectionBuilder.setConnected(true).setError(Collections.<String>emptyList());
586             } else {
587                 logger.error("Create CCAP Failed: {} : {}", iid, message);
588
589                 connectionBuilder.setConnected(false).setError(Collections.singletonList(message));
590             }
591
592             //register rpc
593             logger.info("Registering CCAP Routed RPC Path...");
594             routedRpcRegistration.registerPath(CcapContext.class, iid);
595
596             Optional<Ccap> optionalCcap = mdsalUtils.read(LogicalDatastoreType.OPERATIONAL, iid);
597
598             final CcapBuilder responseCcapBuilder;
599             if (optionalCcap.isPresent()) {
600                 responseCcapBuilder = new CcapBuilder(optionalCcap.get());
601             } else {
602                 responseCcapBuilder = new CcapBuilder();
603                 responseCcapBuilder.setCcapId(ccap.getCcapId());
604             }
605
606             responseCcapBuilder.setConnection(connectionBuilder.build());
607
608             mdsalUtils.put(LogicalDatastoreType.OPERATIONAL, iid, responseCcapBuilder.build());
609         }
610
611         @Override
612         protected void handleUpdatedData(final DataTreeModification<Ccap> change) {
613             InstanceIdentifier<Ccap> iid = change.getRootPath().getRootIdentifier();
614
615             // If this notification is coming from our modification ignore it.
616             if (updateQueue.contains(iid)) {
617                 updateQueue.remove(iid);
618                 return;
619             }
620
621             final Ccap updatedCcap = change.getRootNode().getDataAfter();
622
623             //register rpc
624             logger.info("Registering CCAP Routed RPC Path...");
625             routedRpcRegistration.registerPath(CcapContext.class, iid);
626
627             // restore the original data
628             updateQueue.add(iid);
629             mdsalUtils.put(LogicalDatastoreType.CONFIGURATION, iid, updatedCcap);
630         }
631
632         @Override
633         protected void handleRemovedData(final DataTreeModification<Ccap> change) {
634
635             InstanceIdentifier<Ccap> iid = change.getRootPath().getRootIdentifier();
636             final Ccap nukedCcap = change.getRootNode().getDataBefore();
637             removeCcapFromAllMaps(nukedCcap);
638
639             //unregister ccap rpc path
640             logger.info("Un-Registering CCAP Routed RPC Path...");
641             routedRpcRegistration.unregisterPath(CcapContext.class, iid);
642
643             mdsalUtils.delete(LogicalDatastoreType.OPERATIONAL, iid);
644
645             // clean up ccaps level if it is now empty
646             executor.execute(new CcapsCleaner(iid));
647         }
648
649         @Override
650         protected void handleInvalidData(final DataTreeModification<Ccap> change, ValidationException validationException){
651             // bad data write errors to operational datastore
652             saveErrors(change, validationException);
653         }
654
655     }
656
657     private class QosDataTreeChangeListener extends AbstractDataTreeChangeListener<Gate> {
658
659         private final Set<InstanceIdentifier<Gate>> updateQueue = Sets.newConcurrentHashSet();
660
661         public QosDataTreeChangeListener() {
662             super(Gate.class,new DataValidator(new QosValidatorProviderFactory().build()));
663         }
664
665         @Override
666         protected void handleCreatedData(final DataTreeModification<Gate> change) {
667
668             InstanceIdentifier<Gate> gateIID = change.getRootPath().getRootIdentifier();
669             final Gate newGate = change.getRootNode().getDataAfter();
670
671             final String newGatePathStr = makeGatePathString(gateIID);
672
673             // if a new app comes along add RPC registration
674             final InstanceIdentifier<App> appIID = gateIID.firstIdentifierOf(App.class);
675             // TBD verify if App ID exists first
676
677             //register appID RPC path
678             logger.info("Registering App Routed RPC Path...");
679             routedRpcRegistration.registerPath(AppContext.class, appIID);
680
681             final InstanceIdentifier<Subscriber> subscriberIID = gateIID.firstIdentifierOf(Subscriber.class);
682             final SubscriberKey subscriberKey = InstanceIdentifier.keyOf(subscriberIID);
683             final InetAddress subscriberAddr = getInetAddress(subscriberKey.getSubscriberId());
684             if (subscriberAddr == null) {
685                 final String msg = String.format("subscriberId must be a valid ipaddress: %s",
686                         subscriberKey.getSubscriberId());
687                 logger.error(msg);
688                 saveGateError(gateIID, newGatePathStr, msg);
689                 return;
690             }
691
692             final Ccap ccap = findCcapForSubscriberId(subscriberAddr);
693             if (ccap == null) {
694                 final String msg = String.format("Unable to find Ccap for subscriber %s: @ %s",
695                         subscriberKey.getSubscriberId(), newGatePathStr);
696                 logger.error(msg);
697                 saveGateError(gateIID, newGatePathStr, msg);
698                 return;
699             }
700
701             final PCMMService pcmmService = pcmmServiceMap.get(ccap.getCcapId());
702             if (pcmmService == null) {
703                 final String msg =
704                         String.format("Unable to locate PCMM Service for CCAP: %s ; with subscriber: %s", ccap,
705                                 subscriberKey.getSubscriberId());
706                 logger.error(msg);
707                 saveGateError(gateIID, newGatePathStr, msg);
708                 return;
709             }
710
711             //
712             // set up gate builder with known fields (and some empty ones)
713             //
714             final GateBuilder gateBuilder = new GateBuilder();
715             gateBuilder.setGateId(newGate.getGateId())
716                     .setGatePath(newGatePathStr)
717                     .setCcapId(ccap.getCcapId())
718                     .setClassifiers(newGate.getClassifiers())
719                     .setGateSpec(newGate.getGateSpec())
720                     .setCopsGateState("")
721                     .setCopsGateTimeInfo("")
722                     .setCopsGateUsageInfo("");
723
724             ServiceFlowDirection scnDirection = null;
725
726             if (newGate.getTrafficProfile().getTrafficProfileChoice() instanceof ServiceClassNameChoice) {
727                 final ServiceClassName scn =
728                     ((ServiceClassNameChoice)newGate.getTrafficProfile()
729                      .getTrafficProfileChoice())
730                     .getServiceClassNameProfile()
731                     .getServiceClassName();
732                 scnDirection = findScnOnCcap(scn, ccap);
733                 if (scnDirection == null) {
734                     final String msg =
735                         String.format("SCN %s not found on CCAP %s for %s", scn, ccap.getCcapId(), newGatePathStr);
736                     logger.error(msg);
737                     saveGateError(gateIID, newGatePathStr, msg);
738                     return;
739                 }
740                 ServiceClassNameProfileBuilder scnBuilder = new ServiceClassNameProfileBuilder();
741                 scnBuilder.setServiceClassName(scn);
742                 ServiceClassNameProfile scnProfile = scnBuilder.build();
743                 ServiceClassNameChoiceBuilder scncBuilder = new ServiceClassNameChoiceBuilder();
744                 scncBuilder.setServiceClassNameProfile(scnProfile);
745                 ServiceClassNameChoice scnChoice = scncBuilder.build();
746                 TrafficProfileBuilder trafficProfileBuilder = new TrafficProfileBuilder();
747                 trafficProfileBuilder.setTrafficProfileChoice(scnChoice);
748                 TrafficProfile trafficProfile = trafficProfileBuilder.build();
749                 gateBuilder.setTrafficProfile(trafficProfile);
750             }
751             else {
752                 gateBuilder.setTrafficProfile(newGate.getTrafficProfile());
753             }
754
755             //
756             // since we may be modifying the contents of the original request GateSpec
757             // to update flow direction (based on the ccap SCN configuration) we need to
758             // rebuild the requested gate spec and replace the existing one in the gate builder
759             //
760             final GateSpecBuilder gateSpecBuilder = new GateSpecBuilder();
761             gateSpecBuilder.setDirection(scnDirection);
762             gateSpecBuilder.setDscpTosMask(newGate.getGateSpec().getDscpTosMask());
763             gateSpecBuilder.setDscpTosOverwrite(newGate.getGateSpec().getDscpTosOverwrite());
764             gateSpecBuilder.setSessionClassId(newGate.getGateSpec().getSessionClassId());
765             gateSpecBuilder.setInactivityTimer(newGate.getGateSpec().getInactivityTimer());
766             final GateSpec gateSpec = gateSpecBuilder.build();
767             gateBuilder.setGateSpec(gateSpec);
768
769             //
770             // build the gate to be requested
771             //
772             gateBuilder.setTimestamp(getNowTimeStamp());
773
774             final Gate requestGate = gateBuilder.build();
775
776             //
777             // send gate request to Ccap
778             //
779             PCMMService.GateSendStatus status =
780                     pcmmService.sendGateSet(newGatePathStr, subscriberAddr, requestGate);
781             if (status.didSucceed()) {
782                 gateMap.put(newGatePathStr, requestGate);
783                 gateCcapMap.put(newGatePathStr, ccap.getCcapId());
784
785                 //
786                 // inquire as to the status, and implementation info of the requested gate
787                 //
788                 PCMMService.GateSendStatus infoStatus = pcmmService.sendGateInfo(newGatePathStr);
789
790                 if (infoStatus.didSucceed()) {
791                     //
792                     // update builder with info for operational storage
793                     //
794                     gateBuilder.setCopsGateState(
795                             infoStatus.getCopsGateState() + "/" + infoStatus.getCopsGateStateReason())
796                             .setCopsGateTimeInfo(infoStatus.getCopsGateTimeInfo())
797                             .setCopsGateUsageInfo(infoStatus.getCopsGateUsageInfo())
798                             .setCopsGateId(status.getCopsGateId());
799                 } else {
800                     List<String> errors = new ArrayList<>(2);
801
802                     // Keep GateSetErrors
803                     if (gateBuilder.getError() != null) {
804                         errors.addAll(gateBuilder.getError());
805                     }
806
807                     errors.add(infoStatus.getMessage());
808                     gateBuilder.setError(errors);
809                 }
810             }
811             else {
812                 gateBuilder.setError(Collections.singletonList(status.getMessage()));
813             }
814
815             Gate operationalGate = gateBuilder.build();
816             mdsalUtils.put(LogicalDatastoreType.OPERATIONAL, gateIID, operationalGate);
817         }
818
819         private void saveGateError(@Nonnull final InstanceIdentifier<Gate> gateIID, @Nonnull final String gatePathStr,
820                                    @Nonnull final String error) {
821             checkNotNull(gateIID);
822             checkNotNull(error);
823
824             final GateBuilder gateBuilder = new GateBuilder();
825             gateBuilder.setGateId(InstanceIdentifier.keyOf(gateIID).getGateId())
826                     .setGatePath(gatePathStr)
827                     .setCopsGateId("")
828                     .setCopsGateState("N/A");
829
830             gateBuilder.setError(Collections.singletonList(error));
831
832             Gate operationalGate = gateBuilder.build();
833
834             mdsalUtils.put(LogicalDatastoreType.OPERATIONAL, gateIID, operationalGate);
835         }
836
837         @Override
838         protected void handleUpdatedData(final DataTreeModification<Gate> change) {
839             InstanceIdentifier<Gate> gateIID = change.getRootPath().getRootIdentifier();
840
841             // If this notification is coming from our modification ignore it.
842             if (updateQueue.contains(gateIID)) {
843                 updateQueue.remove(gateIID);
844                 return;
845             }
846
847             final Gate updatedGate = change.getRootNode().getDataAfter();
848
849             // restores the original data
850             updateQueue.add(gateIID);
851             mdsalUtils.put(LogicalDatastoreType.CONFIGURATION, gateIID, updatedGate);
852         }
853
854         @Override
855         protected void handleRemovedData(final DataTreeModification<Gate> change) {
856             InstanceIdentifier<Gate> removedGateIID = change.getRootPath().getRootIdentifier();
857             final Gate newGate = change.getRootNode().getDataBefore();
858
859             mdsalUtils.delete(LogicalDatastoreType.OPERATIONAL, removedGateIID);
860
861             executor.execute(new SubscriberCleaner(removedGateIID));
862
863             final String gatePathStr = makeGatePathString(removedGateIID);
864
865             if (gateMap.containsKey(gatePathStr)) {
866                 final Gate thisGate = gateMap.remove(gatePathStr);
867                 final String gateId = thisGate.getGateId();
868                 final String ccapId = gateCcapMap.remove(gatePathStr);
869                 final Ccap thisCcap = ccapMap.get(ccapId);
870                 final PCMMService service = pcmmServiceMap.get(thisCcap.getCcapId());
871                 if (service != null) {
872                     service.sendGateDelete(gatePathStr);
873                     logger.info("onDataChanged(): removed QoS gate {} for {}/{}/{}: ", gateId, ccapId, gatePathStr,thisGate);
874                 } else {
875                     logger.warn("Unable to send to locate PCMMService to send gate delete message with CCAP - "
876                             + thisCcap);
877                 }
878             }
879
880         }
881
882         @Override
883         protected void handleInvalidData(final DataTreeModification<Gate> change, ValidationException validationException){
884             // bad data write errors to operational datastore
885             saveErrors(change, validationException);
886         }
887
888         private String makeGatePathString(InstanceIdentifier<Gate> iid) {
889             final InstanceIdentifier<App> appIID = iid.firstIdentifierOf(App.class);
890             final AppKey appKey = InstanceIdentifier.keyOf(appIID);
891
892             final InstanceIdentifier<Subscriber> subscriberIID = iid.firstIdentifierOf(Subscriber.class);
893             final SubscriberKey subscriberKey = InstanceIdentifier.keyOf(subscriberIID);
894
895             final GateKey gateKey = InstanceIdentifier.keyOf(iid);
896
897             return appKey.getAppId() + "/" + subscriberKey.getSubscriberId() + "/" + gateKey.getGateId();
898         }
899     }
900
901     @Override
902     public Future<RpcResult<CcapSetConnectionOutput>> ccapSetConnection(CcapSetConnectionInput input) {
903         // TODO refactor this method into smaller parts
904
905         InstanceIdentifier<Ccap> ccapIid = (InstanceIdentifier<Ccap>) input.getCcapId();
906         List<String> outputError = new ArrayList<>();
907         String rpcResponse = null;
908         Boolean inputIsConnected = input.getConnection().isConnected();
909         Boolean effectiveIsConnected = null;
910         String ccapId = input.getCcapId().firstIdentifierOf(Ccap.class).firstKeyOf(Ccap.class).getCcapId();
911         PCMMService pcmmService = pcmmServiceMap.get(ccapId);
912
913         if (!inputIsConnected) {
914             // set connected false
915             if (pcmmService.getPcmmPdpSocket()) {
916                 outputError.add(ccapId + ": CCAP COPS socket is already closed");
917                 effectiveIsConnected = false;
918             } else {
919                 //if (!pcmmService.getPcmmCcapClientIsConnected()) {
920                 outputError.add(ccapId + ": CCAP client is disconnected with error: "
921                         + pcmmService.getPcmmCcapClientConnectErrMsg());
922                 //}
923                 pcmmService.ccapClient.disconnect();
924                 effectiveIsConnected = false;
925             }
926         } else {
927             // set connected true
928             if (!pcmmService.getPcmmPdpSocket() && pcmmService.getPcmmCcapClientIsConnected()) {
929                 outputError.add(ccapId + ": CCAP COPS socket is already open");
930                 outputError.add(ccapId + ": CCAP client is connected");
931                 effectiveIsConnected = true;
932             } else {
933                 if (pcmmService.getPcmmCcapClientIsConnected()) {
934                     pcmmService.ccapClient.disconnect();
935                 }
936                 pcmmService.ccapClient.connect();
937                 if (pcmmService.getPcmmCcapClientIsConnected()) {
938                     effectiveIsConnected = true;
939                     outputError.add(ccapId + ": CCAP client is connected");
940                 } else {
941                     effectiveIsConnected = false;
942                     outputError.add(ccapId + ": CCAP client is disconnected with error: "
943                             + pcmmService.getPcmmCcapClientConnectErrMsg());
944                 }
945             }
946         }
947
948         DateAndTime connectionDateAndTime = getNowTimeStamp();
949         org.opendaylight.yang.gen.v1.urn.packetcable.rev170224.ccap.set.connection.output.ccap.ConnectionBuilder
950                 connectionRpcOutput =
951                 new org.opendaylight.yang.gen.v1.urn.packetcable.rev170224.ccap.set.connection.output.ccap.ConnectionBuilder()
952                         .setConnected(effectiveIsConnected)
953                         .setError(outputError)
954                         .setTimestamp(connectionDateAndTime);
955
956         org.opendaylight.yang.gen.v1.urn.packetcable.rev170224.ccap.set.connection.output.CcapBuilder ccapRpcOutput =
957                 new org.opendaylight.yang.gen.v1.urn.packetcable.rev170224.ccap.set.connection.output.CcapBuilder().setCcapId(
958                         ccapId).setConnection(connectionRpcOutput.build());
959
960
961         ConnectionBuilder connectionOps = new ConnectionBuilder().setConnected(effectiveIsConnected)
962                 .setError(outputError)
963                 .setTimestamp(connectionDateAndTime);
964
965         CcapBuilder responseCcapBuilder = new CcapBuilder().setCcapId(ccapId).setConnection(connectionOps.build());
966
967
968         mdsalUtils.put(LogicalDatastoreType.OPERATIONAL, ccapIid, responseCcapBuilder.build());
969
970
971         DateAndTime rpcDateAndTime = getNowTimeStamp();
972         rpcResponse = ccapId + ": CCAP set complete";
973         CcapSetConnectionOutputBuilder outputBuilder =
974                 new CcapSetConnectionOutputBuilder().setCcap(ccapRpcOutput.build())
975                         .setResponse(rpcResponse)
976                         .setTimestamp(rpcDateAndTime);
977
978         return Futures.immediateFuture(RpcResultBuilder.success(outputBuilder.build()).build());
979     }
980
981
982
983     @Override
984     public Future<RpcResult<CcapPollConnectionOutput>> ccapPollConnection(CcapPollConnectionInput input) {
985         // TODO refactor this method into smaller parts
986
987         InstanceIdentifier<Ccap> ccapIid = (InstanceIdentifier<Ccap>) input.getCcapId();
988         List<String> outputError = new ArrayList<>();
989
990         String ccapId = input.getCcapId().firstIdentifierOf(Ccap.class).firstKeyOf(Ccap.class).getCcapId();
991         PCMMService pcmmService = pcmmServiceMap.get(ccapId);
992         Boolean effectiveIsConnected = true;
993         String response = null;
994         org.opendaylight.yang.gen.v1.urn.packetcable.rev170224.ccap.poll.connection.output.ccap.ConnectionBuilder
995                 connectionRpcOutput =
996                 new org.opendaylight.yang.gen.v1.urn.packetcable.rev170224.ccap.poll.connection.output.ccap.ConnectionBuilder();
997
998         if (pcmmService != null) {
999             if (pcmmService.getPcmmPdpSocket()) {
1000                 outputError.add(ccapId + ": CCAP Cops socket is closed");
1001                 if (!pcmmService.getPcmmCcapClientIsConnected()) {
1002                     outputError.add(ccapId + ": CCAP client is disconnected with error: "
1003                             + pcmmService.getPcmmCcapClientConnectErrMsg());
1004                 }
1005                 effectiveIsConnected = false;
1006             } else {
1007                 //outputError.add(String.format(ccapId+": CCAP Cops socket is open"));
1008                 if (!pcmmService.getPcmmCcapClientIsConnected()) {
1009                     outputError.add(ccapId + ": CCAP client is disconnected with error: "
1010                             + pcmmService.getPcmmCcapClientConnectErrMsg());
1011                     effectiveIsConnected = false;
1012                 } else {
1013                     outputError.add(ccapId + ": CCAP client is connected");
1014                 }
1015             }
1016             DateAndTime connectionDateAndTime = getNowTimeStamp();
1017
1018
1019             ConnectionBuilder connectionOps = new ConnectionBuilder().setConnected(effectiveIsConnected)
1020                     .setError(outputError)
1021                     .setTimestamp(connectionDateAndTime);
1022
1023             CcapBuilder responseCcapBuilder = new CcapBuilder().setCcapId(ccapId).setConnection(connectionOps.build());
1024
1025             connectionRpcOutput =
1026                     new org.opendaylight.yang.gen.v1.urn.packetcable.rev170224.ccap.poll.connection.output.ccap.ConnectionBuilder()
1027                             .setConnected(effectiveIsConnected)
1028                             .setError(outputError)
1029                             .setTimestamp(connectionDateAndTime);
1030
1031             mdsalUtils.put(LogicalDatastoreType.OPERATIONAL, ccapIid, responseCcapBuilder.build());
1032             response = ccapId + ": CCAP poll complete";
1033         } else {
1034             //pcmmService is null, do not poll
1035             response = ccapId + ": CCAP connection null; no poll performed";
1036         }
1037
1038         DateAndTime rpcDateAndTime = getNowTimeStamp();
1039
1040         org.opendaylight.yang.gen.v1.urn.packetcable.rev170224.ccap.poll.connection.output.CcapBuilder ccapRpcOutput =
1041                 new org.opendaylight.yang.gen.v1.urn.packetcable.rev170224.ccap.poll.connection.output.CcapBuilder().setCcapId(
1042                         ccapId).setConnection(connectionRpcOutput.build());
1043
1044         CcapPollConnectionOutputBuilder outputBuilder =
1045                 new CcapPollConnectionOutputBuilder().setCcap(ccapRpcOutput.build())
1046                         .setResponse(response)
1047                         .setTimestamp(rpcDateAndTime);
1048
1049         return Futures.immediateFuture(RpcResultBuilder.success(outputBuilder.build()).build());
1050     }
1051
1052
1053
1054     private App readAppFromOperationalDatastore(InstanceIdentifier<App> appIid) {
1055         Optional<App> optionalApp = mdsalUtils.read(LogicalDatastoreType.OPERATIONAL, appIid);
1056         AppBuilder thisAppBuilder = new AppBuilder(optionalApp.get());
1057         App thisApp = thisAppBuilder.build();
1058         logger.info("readAppFromConfigDatastore() retrived App: " + thisApp.getAppId());
1059         return thisApp;
1060     }
1061
1062     private Gate readGateFromOperationalDatastore(InstanceIdentifier<Gate> gateIid) {
1063         Optional<Gate> optionalGate = mdsalUtils.read(LogicalDatastoreType.OPERATIONAL, gateIid);
1064         if (optionalGate.isPresent()) {
1065             GateBuilder gateBuilder = new GateBuilder(optionalGate.get());
1066             Gate thisGate = gateBuilder.build();
1067             return thisGate;
1068         } else {
1069             return null;
1070         }
1071     }
1072
1073     private Subscriber readSubscriberFromOperationalDatastore(InstanceIdentifier<Subscriber> subscriberIid) {
1074         Optional<Subscriber> optionalSubscriber = mdsalUtils.read(LogicalDatastoreType.OPERATIONAL, subscriberIid);
1075         if (optionalSubscriber.isPresent()) {
1076             SubscriberBuilder subscriberBuilder = new SubscriberBuilder(optionalSubscriber.get());
1077             Subscriber thisSubscriber = subscriberBuilder.build();
1078             return thisSubscriber;
1079         } else {
1080             return null;
1081         }
1082     }
1083
1084
1085
1086     @Override
1087     public Future<RpcResult<QosSetGateOutput>> qosSetGate(QosSetGateInput input) {
1088         logger.debug("RPC call to qosSetGate()");
1089
1090         String inputAppIid = input.getAppId();
1091         String inputSubscriberId = input.getSubscriberId();
1092         org.opendaylight.yang.gen.v1.urn.packetcable.rev170224.qos.set.gate.input.Gates gates = input.getGates();
1093         List<org.opendaylight.yang.gen.v1.urn.packetcable.rev170224.qos.set.gate.input.gates.Gate> gate = gates.getGate();
1094         QosSetGateOutputBuilder outputBuilder = new QosSetGateOutputBuilder();
1095
1096         String inputGateId = gate.get(0).getGateId();
1097         Boolean retryOption = false;
1098         InstanceIdentifier<Gate> gateIID = qosIID.builder()
1099             .child(Apps.class)
1100             .child(App.class, new AppKey(inputAppIid))
1101             .child(Subscribers.class)
1102             .child(Subscriber.class, new SubscriberKey(inputSubscriberId))
1103             .child(Gates.class)
1104             .child(Gate.class, new GateKey(inputGateId))
1105             .build();
1106
1107         Gate newGate = readGateFromOperationalDatastore(gateIID);
1108         final String newGatePathStr = "/" + inputAppIid + "/" + inputSubscriberId + "/" + inputGateId;
1109
1110         final InetAddress subscriberAddr = getInetAddress(inputSubscriberId);
1111         if (subscriberAddr == null) {
1112             final String msg = String.format("SubscriberId must be a valid ipaddress: %s",
1113                                              inputSubscriberId);
1114             logger.error(msg);
1115             SetFailureBuilder fb = new SetFailureBuilder();
1116             final FailureType ft = FailureType.Unsent;
1117             fb.setFailure(ft);
1118             fb.setMessage(msg);
1119             final SetFailure f = fb.build();
1120             outputBuilder.setSetResponseType(f);
1121             return Futures.immediateFuture(RpcResultBuilder.success(outputBuilder.build()).build());
1122         }
1123
1124         final Ccap ccap = findCcapForSubscriberId(subscriberAddr);
1125         if (ccap == null) {
1126             final String msg =
1127                 String.format("qosSetGate(): Error finding CCAP for %s", newGatePathStr);
1128             logger.error(msg);
1129             SetFailureBuilder fb = new SetFailureBuilder();
1130             final FailureType ft = FailureType.Unsent;
1131             fb.setFailure(ft);
1132             fb.setMessage(msg);
1133             final SetFailure f = fb.build();
1134             outputBuilder.setSetResponseType(f);
1135             return Futures.immediateFuture(RpcResultBuilder.success(outputBuilder.build()).build());
1136         }
1137
1138         logger.debug("Mapped {} to {}", inputSubscriberId, ccap.getCcapId());
1139
1140         final PCMMService pcmmService = pcmmServiceMap.get(ccap.getCcapId());
1141         if (pcmmService == null) {
1142             final String msg =
1143             String.format("Unable to locate PCMM Service for CCAP: %s ; with subscriber: %s", ccap, inputSubscriberId);
1144             logger.error(msg);
1145             SetFailureBuilder fb = new SetFailureBuilder();
1146             final FailureType ft = FailureType.Unsent;
1147             fb.setFailure(ft);
1148             fb.setMessage(msg);
1149             final SetFailure f = fb.build();
1150             outputBuilder.setSetResponseType(f);
1151             return Futures.immediateFuture(RpcResultBuilder.success(outputBuilder.build()).build());
1152         }
1153
1154         final GateBuilder gateBuilder = new GateBuilder();
1155         gateBuilder.setGateId(inputGateId)
1156             .setGatePath(newGatePathStr)
1157             .setCcapId(ccap.getCcapId())
1158             .setCopsGateId(gate.get(0).getCopsGateId())
1159             .setTimestamp(getNowTimeStamp())
1160             .setTimestamp(getNowTimeStamp())
1161             .setGateSpec(gate.get(0).getGateSpec())
1162             .setTrafficProfile(gate.get(0).getTrafficProfile())
1163             .setClassifiers(gate.get(0).getClassifiers());
1164
1165         newGate = gateBuilder.build();
1166
1167         if (gate.get(0).getCopsGateId() != null) {
1168             retryOption = true;
1169         }
1170
1171         PCMMService.GateSendStatus status = null;
1172         synchronized (pcmmService) {
1173             logger.info("Sending gate: Path {} inputSubscriberId {} cops-gate-id {}",
1174                         newGatePathStr, inputSubscriberId, gate.get(0).getCopsGateId());
1175
1176             status = pcmmService.sendGateSet(newGatePathStr, subscriberAddr, newGate);
1177         }
1178
1179         if (status.didSucceed()) {
1180
1181             gateMap.put(newGatePathStr, newGate);
1182             gateCcapMap.put(newGatePathStr, ccap.getCcapId());
1183             Long copsGateId = 0L;
1184             SetSuccessfulBuilder sb = new SetSuccessfulBuilder();
1185
1186             if (status.getCopsGateId() != null) {
1187                 logger.debug("newGate.getCopsGateId() = {} ", status.getCopsGateId());
1188                 copsGateId = Long.decode(status.getCopsGateId());
1189                 sb.setCopsGateId(copsGateId);
1190                 if (status.getCopsGateId() != null) {
1191                     gateBuilder.setCopsGateId(status.getCopsGateId());
1192                 }
1193                 if (status.getCopsGateState() != null) {
1194                     gateBuilder.setCopsGateState(status.getCopsGateState());
1195                 }
1196                 if (status.getCopsGateTimeInfo() != null) {
1197                     gateBuilder.setCopsGateTimeInfo(status.getCopsGateTimeInfo());
1198                 }
1199                 if (status.getCopsGateUsageInfo() != null) {
1200                     gateBuilder.setCopsGateUsageInfo(status.getCopsGateUsageInfo());
1201                 }
1202             }
1203
1204             mdsalUtils.put(LogicalDatastoreType.OPERATIONAL, gateIID, gateBuilder.build());
1205
1206             final SetSuccessful s = sb.build();
1207             outputBuilder.setSetResponseType(s);
1208             return Futures.immediateFuture(RpcResultBuilder.success(outputBuilder.build()).build());
1209         }
1210         else {
1211             if (retryOption == true) {
1212                 // Try one more time with blank Cops Gate Id in case the gate has timed out unexpectedly
1213                 logger.info("qosSetGate error msg: {} reason: {}", status.getMessage(), status.getCopsGateStateReason());
1214                 final GateBuilder retryGateBuilder = new GateBuilder();
1215                 retryGateBuilder.setGateId(inputGateId)
1216                     .setGatePath(newGatePathStr)
1217                     .setCcapId(ccap.getCcapId())
1218                     .setTimestamp(getNowTimeStamp())
1219                     .setTimestamp(getNowTimeStamp())
1220                     .setGateSpec(gate.get(0).getGateSpec())
1221                     .setTrafficProfile(gate.get(0).getTrafficProfile())
1222                     .setClassifiers(gate.get(0).getClassifiers());
1223
1224                 newGate = retryGateBuilder.build();
1225
1226                 synchronized (pcmmService) {
1227                     logger.info("Sending gate: Path {} inputSubscriberId {} with cops-gate-id undefined",
1228                                 newGatePathStr);
1229
1230                     status = pcmmService.sendGateSet(newGatePathStr, subscriberAddr, newGate);
1231                 }
1232
1233                 if (status.didSucceed()) {
1234
1235                     gateMap.put(newGatePathStr, newGate);
1236                     gateCcapMap.put(newGatePathStr, ccap.getCcapId());
1237                     Long copsGateId = 0L;
1238                     SetSuccessfulBuilder sb = new SetSuccessfulBuilder();
1239
1240                     if (status.getCopsGateId() != null) {
1241                         logger.debug("newGate.getCopsGateId() = {} ", status.getCopsGateId());
1242                         copsGateId = Long.decode(status.getCopsGateId());
1243                         sb.setCopsGateId(copsGateId);
1244                         if (status.getCopsGateId() != null) {
1245                             gateBuilder.setCopsGateId(status.getCopsGateId());
1246                         }
1247                         if (status.getCopsGateState() != null) {
1248                             gateBuilder.setCopsGateState(status.getCopsGateState());
1249                         }
1250                         if (status.getCopsGateTimeInfo() != null) {
1251                             gateBuilder.setCopsGateTimeInfo(status.getCopsGateTimeInfo());
1252                         }
1253                         if (status.getCopsGateUsageInfo() != null) {
1254                             gateBuilder.setCopsGateUsageInfo(status.getCopsGateUsageInfo());
1255                         }
1256                     }
1257
1258                     mdsalUtils.put(LogicalDatastoreType.OPERATIONAL, gateIID, gateBuilder.build());
1259
1260                     final SetSuccessful s = sb.build();
1261                     outputBuilder.setSetResponseType(s);
1262                     return Futures.immediateFuture(RpcResultBuilder.success(outputBuilder.build()).build());
1263                 }
1264             }
1265             SetFailureBuilder fb = new SetFailureBuilder();
1266             final FailureType ft = FailureType.Failed;
1267             fb.setFailure(ft);
1268             fb.setMessage(status.getMessage());
1269             final SetFailure f = fb.build();
1270             outputBuilder.setSetResponseType(f);
1271             logger.error("qosSetGate error msg: {} reason: {}", status.getMessage(), status.getCopsGateStateReason());
1272             return Futures.immediateFuture(RpcResultBuilder.success(outputBuilder.build()).build());
1273         }
1274
1275     }
1276
1277     @Override
1278     public Future<RpcResult<QosDeleteGateOutput>> qosDeleteGate(QosDeleteGateInput input) {
1279         logger.debug("RPC call to qosDeleteGate()");
1280
1281
1282         String inputAppIid = input.getAppId();
1283         String inputSubscriberId = input.getSubscriberId();
1284         String inputGateId = input.getGateId();
1285         String strGateId = null;
1286
1287         InstanceIdentifier<Gate> gateIID = qosIID.builder()
1288             .child(Apps.class)
1289             .child(App.class, new AppKey(inputAppIid))
1290             .child(Subscribers.class)
1291             .child(Subscriber.class, new SubscriberKey(inputSubscriberId))
1292             .child(Gates.class)
1293             .child(Gate.class, new GateKey(inputGateId))
1294             .build();
1295
1296         Gate newGate = readGateFromOperationalDatastore(gateIID);
1297         QosDeleteGateOutputBuilder outputBuilder = new QosDeleteGateOutputBuilder();
1298         final String newGatePathStr = "/" + inputAppIid + "/" + inputSubscriberId + "/" + inputGateId;
1299
1300         if (newGate != null) {
1301             strGateId = newGate.getCopsGateId();
1302             if (strGateId == null || strGateId.length() == 0 || strGateId.equals("null")){
1303                 final String msg =
1304                     String.format("qosDeleteGate(): Unknown CopsGateId %s", newGatePathStr);
1305                 logger.error(msg);
1306                 DeleteFailureBuilder fb = new DeleteFailureBuilder();
1307                 final FailureType ft = FailureType.Unsent;
1308                 fb.setFailure(ft);
1309                 fb.setMessage(msg);
1310                 final DeleteFailure f = fb.build();
1311                 outputBuilder.setDeleteResponseType(f);
1312                 return Futures.immediateFuture(RpcResultBuilder.success(outputBuilder.build()).build());
1313             }
1314             else {
1315                 logger.debug("PacketcableProvider: gateId = {} ", strGateId);
1316             }
1317         }
1318         else {
1319             final String msg =
1320                 String.format("qosDeleteGate(): Error deleting gate %s", newGatePathStr);
1321             logger.error(msg);
1322             DeleteFailureBuilder fb = new DeleteFailureBuilder();
1323             final FailureType ft = FailureType.Unsent;
1324             fb.setFailure(ft);
1325             fb.setMessage(msg);
1326             final DeleteFailure f = fb.build();
1327             outputBuilder.setDeleteResponseType(f);
1328             return Futures.immediateFuture(RpcResultBuilder.success(outputBuilder.build()).build());
1329         }
1330
1331         final InetAddress subscriberAddr = getInetAddress(inputSubscriberId);
1332         if (subscriberAddr == null) {
1333             final String msg = String.format("SubscriberId must be a valid ipaddress: %s",
1334                                              inputSubscriberId);
1335             logger.error(msg);
1336             DeleteFailureBuilder fb = new DeleteFailureBuilder();
1337             final FailureType ft = FailureType.Unsent;
1338             fb.setFailure(ft);
1339             fb.setMessage(msg);
1340             final DeleteFailure f = fb.build();
1341             outputBuilder.setDeleteResponseType(f);
1342             return Futures.immediateFuture(RpcResultBuilder.success(outputBuilder.build()).build());
1343         }
1344
1345         final Ccap ccap = findCcapForSubscriberId(subscriberAddr);
1346         if (ccap == null) {
1347             final String msg = String.format("Unable to find Ccap for subscriber %s:",
1348                                              inputSubscriberId);
1349             logger.error(msg);
1350             DeleteFailureBuilder fb = new DeleteFailureBuilder();
1351             final FailureType ft = FailureType.Unsent;
1352             fb.setFailure(ft);
1353             fb.setMessage(msg);
1354             final DeleteFailure f = fb.build();
1355             outputBuilder.setDeleteResponseType(f);
1356             return Futures.immediateFuture(RpcResultBuilder.success(outputBuilder.build()).build());
1357         }
1358
1359         logger.debug("Mapped {} to {}", inputSubscriberId, ccap.getCcapId());
1360
1361         final PCMMService pcmmService = pcmmServiceMap.get(ccap.getCcapId());
1362         if (pcmmService == null) {
1363             final String msg =
1364             String.format("Unable to locate PCMM Service for CCAP: %s ; with subscriber: %s", ccap, inputSubscriberId);
1365             logger.error(msg);
1366             DeleteFailureBuilder fb = new DeleteFailureBuilder();
1367             final FailureType ft = FailureType.Unsent;
1368             fb.setFailure(ft);
1369             fb.setMessage(msg);
1370             final DeleteFailure f = fb.build();
1371             outputBuilder.setDeleteResponseType(f);
1372             return Futures.immediateFuture(RpcResultBuilder.success(outputBuilder.build()).build());
1373         }
1374
1375         Boolean status = false;
1376         synchronized (pcmmService) {
1377             status = pcmmService.sendGateDelete(newGatePathStr);
1378         }
1379
1380         if (status == true) {
1381             Long copsGateId = 0L;
1382             copsGateId = Long.decode(strGateId);
1383
1384             logger.info("qosDeleteGate(): Successfully deleted gate {}", newGatePathStr);
1385             mdsalUtils.delete(LogicalDatastoreType.OPERATIONAL, gateIID);
1386             DeleteSuccessfulBuilder sb = new DeleteSuccessfulBuilder();
1387             sb.setCopsGateId(copsGateId);
1388             final DeleteSuccessful s = sb.build();
1389             outputBuilder.setDeleteResponseType(s);
1390             return Futures.immediateFuture(RpcResultBuilder.success(outputBuilder.build()).build());
1391         }
1392         else {
1393             final String msg = String.format("qosDeleteGate(): Error deleting gate %s", newGatePathStr);
1394             logger.error(msg);
1395             DeleteFailureBuilder fb = new DeleteFailureBuilder();
1396             final FailureType ft = FailureType.Failed;
1397             fb.setFailure(ft);
1398             fb.setMessage(msg);
1399             final DeleteFailure f = fb.build();
1400             outputBuilder.setDeleteResponseType(f);
1401             return Futures.immediateFuture(RpcResultBuilder.success(outputBuilder.build()).build());
1402         }
1403     }
1404
1405     @Override
1406     public Future<RpcResult<QosGateInfoOutput>> qosGateInfo(QosGateInfoInput input) {
1407         logger.debug("RPC call to qosGateInfo()");
1408
1409         String inputAppIid = input.getAppId();
1410         String inputSubscriberId = input.getSubscriberId();
1411         String inputGateId = input.getGateId();
1412         QosGateInfoOutputBuilder outputBuilder = new QosGateInfoOutputBuilder();
1413         InstanceIdentifier<Gate> gateIID = qosIID.builder()
1414             .child(Apps.class)
1415             .child(App.class, new AppKey(inputAppIid))
1416             .child(Subscribers.class)
1417             .child(Subscriber.class, new SubscriberKey(inputSubscriberId))
1418             .child(Gates.class)
1419             .child(Gate.class, new GateKey(inputGateId))
1420             .build();
1421
1422         Gate infoGate = readGateFromOperationalDatastore(gateIID);
1423         final String newGatePathStr = "/" + inputAppIid + "/" + inputSubscriberId + "/" + inputGateId;
1424
1425         final InetAddress subscriberAddr = getInetAddress(inputSubscriberId);
1426         if (subscriberAddr == null) {
1427             final String msg = String.format("SubscriberId must be a valid ipaddress: %s",
1428                                              inputSubscriberId);
1429             logger.error(msg);
1430             InfoFailureBuilder fb = new InfoFailureBuilder();
1431             final FailureType ft = FailureType.Unsent;
1432             fb.setFailure(ft);
1433             fb.setMessage(msg);
1434             final InfoFailure f = fb.build();
1435             outputBuilder.setInfoResponseType(f);
1436             return Futures.immediateFuture(RpcResultBuilder.success(outputBuilder.build()).build());
1437         }
1438
1439         final Ccap ccap = findCcapForSubscriberId(subscriberAddr);
1440         if (ccap == null) {
1441             final String msg = String.format("Unable to find Ccap for subscriber %s:",
1442                                              inputSubscriberId);
1443             logger.error(msg);
1444             InfoFailureBuilder fb = new InfoFailureBuilder();
1445             final FailureType ft = FailureType.Unsent;
1446             fb.setFailure(ft);
1447             fb.setMessage(msg);
1448             final InfoFailure f = fb.build();
1449             outputBuilder.setInfoResponseType(f);
1450             return Futures.immediateFuture(RpcResultBuilder.success(outputBuilder.build()).build());
1451         }
1452
1453         logger.debug("Mapped {} to {}", inputSubscriberId, ccap.getCcapId());
1454
1455         final PCMMService pcmmService = pcmmServiceMap.get(ccap.getCcapId());
1456         if (pcmmService == null) {
1457             final String msg =
1458                 String.format("Unable to locate PCMM Service for CCAP: %s ; with subscriber: %s",
1459                               ccap, inputSubscriberId);
1460             logger.error(msg);
1461             InfoFailureBuilder fb = new InfoFailureBuilder();
1462             final FailureType ft = FailureType.Unsent;
1463             fb.setFailure(ft);
1464             fb.setMessage(msg);
1465             final InfoFailure f = fb.build();
1466             outputBuilder.setInfoResponseType(f);
1467             return Futures.immediateFuture(RpcResultBuilder.success(outputBuilder.build()).build());
1468         }
1469
1470         PCMMService.GateSendStatus status = null;
1471
1472         synchronized (pcmmService) {
1473             status = pcmmService.sendGateInfo(newGatePathStr);
1474         }
1475
1476         if (status.didSucceed()) {
1477             DateAndTime gateDateAndTime = getNowTimeStamp();
1478             List<String> gateOutputError = Collections.emptyList();
1479             gateOutputError = Collections.singletonList(status.getMessage());
1480             GateBuilder gateBuilder = new GateBuilder();
1481
1482             gateBuilder.setGateId(inputGateId)
1483                 .setGatePath(newGatePathStr)
1484                 .setCcapId(ccap.getCcapId())
1485                 .setCopsGateState(status.getCopsGateState() + "/" + status.getCopsGateStateReason())
1486                 .setCopsGateTimeInfo(status.getCopsGateTimeInfo())
1487                 .setCopsGateUsageInfo(status.getCopsGateUsageInfo())
1488                 .setCopsGateId(status.getCopsGateId())
1489                 .setError(gateOutputError)
1490                 .setTimestamp(gateDateAndTime);
1491
1492             infoGate = gateBuilder.build();
1493
1494             mdsalUtils.put(LogicalDatastoreType.OPERATIONAL, gateIID, infoGate);
1495
1496             org.opendaylight.yang.gen.v1.urn.packetcable.rev170224.qos.gate.info.response.info.response.type.info.successful.gates.GateBuilder responseGateBuilder
1497                 = new org.opendaylight.yang.gen.v1.urn.packetcable.rev170224.qos.gate.info.response.info.response.type.info.successful.gates.GateBuilder();
1498             responseGateBuilder.fieldsFrom(infoGate);
1499             responseGateBuilder.setGateId(inputGateId);
1500             responseGateBuilder.setGatePath(newGatePathStr);
1501             org.opendaylight.yang.gen.v1.urn.packetcable.rev170224.qos.gate.info.response.info.response.type.info.successful.gates.Gate responseGate =
1502                 responseGateBuilder.build();
1503             List<org.opendaylight.yang.gen.v1.urn.packetcable.rev170224.qos.gate.info.response.info.response.type.info.successful.gates.Gate> responseGateList =
1504                 new ArrayList<>();
1505             responseGateList.add(responseGate);
1506             org.opendaylight.yang.gen.v1.urn.packetcable.rev170224.qos.gate.info.response.info.response.type.info.successful.GatesBuilder responseGatesBuilder =
1507                 new org.opendaylight.yang.gen.v1.urn.packetcable.rev170224.qos.gate.info.response.info.response.type.info.successful.GatesBuilder();
1508             responseGatesBuilder.setGate(responseGateList);
1509             org.opendaylight.yang.gen.v1.urn.packetcable.rev170224.qos.gate.info.response.info.response.type.info.successful.Gates responseGates =
1510                 responseGatesBuilder.build();
1511
1512             InfoSuccessfulBuilder sb = new InfoSuccessfulBuilder();
1513             sb.setGates(responseGates);
1514             final InfoSuccessful s = sb.build();
1515             outputBuilder.setInfoResponseType(s);
1516             return Futures.immediateFuture(RpcResultBuilder.success(outputBuilder.build()).build());
1517         }
1518         else {
1519             final String msg =
1520                 String.format("qosGateInfo(): error msg: %s reason: %s", status.getMessage(), status.getCopsGateStateReason());
1521             logger.error(msg);
1522             InfoFailureBuilder fb = new InfoFailureBuilder();
1523             final FailureType ft = FailureType.Failed;
1524             fb.setFailure(ft);
1525             fb.setMessage(msg);
1526             final InfoFailure f = fb.build();
1527             outputBuilder.setInfoResponseType(f);
1528             return Futures.immediateFuture(RpcResultBuilder.success(outputBuilder.build()).build());
1529         }
1530     }
1531
1532     @Override
1533     public Future<RpcResult<QosPollGatesOutput>> qosPollGates(QosPollGatesInput input) {
1534         // TODO refactor this method into smaller parts
1535
1536         InstanceIdentifier<App> appIid = (InstanceIdentifier<App>) input.getAppId();
1537         //logger.info("qospollgates appIid : "+appIid.toString());
1538         App app = readAppFromOperationalDatastore(appIid);
1539         //logger.info("qospollgates app : "+app.toString());
1540         AppKey appKey = InstanceIdentifier.keyOf(appIid);
1541         String inputSubscriberId = input.getSubscriberId();
1542         String inputGateId = input.getGateId();
1543         List<String> gateOutputError = Collections.emptyList();
1544         String subscriberId = null;
1545         String gateId = null;
1546         String ccapId = null;
1547         String gatePathStr = null;
1548         String opsCopsGateId = null;
1549         Gate opsGate = null;
1550
1551         String rpcResponse = null;
1552
1553         org.opendaylight.yang.gen.v1.urn.packetcable.rev170224.qos.poll.gates.output.GateBuilder gateOutputBuilder =
1554                 new org.opendaylight.yang.gen.v1.urn.packetcable.rev170224.qos.poll.gates.output.GateBuilder();
1555
1556         GateBuilder gateBuilder = new GateBuilder();
1557
1558         if (inputSubscriberId != null) {
1559             if (inputGateId != null) {
1560                 //Subscriber Id and Gate Id provided, only one gate to be poolled
1561
1562                 //generate the gateiid
1563                 InstanceIdentifier<Gate> gateIid = appIid.builder()
1564                         .child(Subscribers.class)
1565                         .child(Subscriber.class, new SubscriberKey(inputSubscriberId))
1566                         .child(Gates.class)
1567                         .child(Gate.class, new GateKey(inputGateId))
1568                         .build();
1569
1570
1571                 opsGate = readGateFromOperationalDatastore(gateIid);
1572
1573                 //does the gate exists in the Operational DS?
1574                 if (opsGate == null) {
1575                     gatePathStr = appKey.getAppId() + "/" + inputSubscriberId + "/" + inputGateId;
1576                     rpcResponse = gatePathStr + ": gate does not exist in the system; gate poll not performed";
1577                 } else {
1578                     opsCopsGateId = opsGate.getCopsGateId();
1579                     gatePathStr = opsGate.getGatePath();
1580
1581                     if (!Objects.equals(opsCopsGateId, "") && !Objects.equals(opsCopsGateId, null)) {
1582                         ccapId = findCcapForSubscriberId(getInetAddress(inputSubscriberId)).getCcapId();
1583                         PCMMService pcmmService = pcmmServiceMap.get(ccapId);
1584                         //is the CCAP socket open?
1585                         if (!pcmmService.getPcmmPdpSocket() && pcmmService.getPcmmCcapClientIsConnected()) {
1586                             PCMMService.GateSendStatus status = pcmmService.sendGateInfo(gatePathStr);
1587                             DateAndTime gateDateAndTime = getNowTimeStamp();
1588                             //logger.info("qospollgates Gate Status : GateID/"+status.getCopsGateId());
1589                             //logger.info("qospollgates Gate Status : Message/"+status.getMessage());
1590                             //logger.info("qospollgates Gate Status : DidSucceed/"+status.didSucceed());
1591                             gateOutputError = Collections.singletonList(status.getMessage());
1592
1593                             gateOutputBuilder.setGatePath(gatePathStr)
1594                                     .setCcapId(ccapId)
1595                                     .setCopsGateState(status.getCopsGateState() + "/" + status.getCopsGateStateReason())
1596                                     .setCopsGateTimeInfo(status.getCopsGateTimeInfo())
1597                                     .setCopsGateUsageInfo(status.getCopsGateUsageInfo())
1598                                     .setCopsGateId(status.getCopsGateId())
1599                                     .setError(gateOutputError)
1600                                     .setTimestamp(gateDateAndTime);
1601
1602                             gateBuilder.setGateId(inputGateId)
1603                                     .setGatePath(gatePathStr)
1604                                     .setCcapId(ccapId)
1605                                     .setCopsGateState(status.getCopsGateState() + "/" + status.getCopsGateStateReason())
1606                                     .setCopsGateTimeInfo(status.getCopsGateTimeInfo())
1607                                     .setCopsGateUsageInfo(status.getCopsGateUsageInfo())
1608                                     .setCopsGateId(status.getCopsGateId())
1609                                     .setError(gateOutputError)
1610                                     .setTimestamp(gateDateAndTime);
1611
1612                             mdsalUtils.put(LogicalDatastoreType.OPERATIONAL, gateIid, gateBuilder.build());
1613                             rpcResponse = gatePathStr + ": gate poll complete";
1614                         } else {
1615                             rpcResponse =
1616                                     ccapId + ": CCAP socket is down or client disconnected; gate poll not performed";
1617                         }
1618                     } else {
1619                         rpcResponse = gatePathStr + ": gate not active; gate poll not performed";
1620                     }
1621                 }
1622             } else {
1623                 //inputGateId is null; pool all gates for the subscriber if the sub exists
1624
1625                 //generate active subIid
1626                 InstanceIdentifier<Subscriber> subIid = appIid.builder()
1627                         .child(Subscribers.class)
1628                         .child(Subscriber.class, new SubscriberKey(inputSubscriberId))
1629                         .build();
1630                 //does the subscriber provided exists in the Operational Datastore?
1631                 Subscriber sub = readSubscriberFromOperationalDatastore(subIid);
1632                 if (sub != null) {
1633                     //If Subscriber exsits poll all gates for the subscriber
1634                     subscriberId = sub.getSubscriberId();
1635                     List<Gate> gateList = sub.getGates().getGate();
1636                     for (Gate gate : gateList) {
1637                         //generate active gateIid
1638                         gateId = gate.getGateId();
1639                         InstanceIdentifier<Gate> gateIid =
1640                                 subIid.builder().child(Gates.class).child(Gate.class, new GateKey(gateId)).build();
1641
1642                         opsGate = readGateFromOperationalDatastore(gateIid);
1643                         opsCopsGateId = opsGate.getCopsGateId();
1644                         //generate active gatePathStr
1645                         gatePathStr = appKey.getAppId() + "/" + subscriberId + "/" + gateId;
1646
1647                         if (!Objects.equals(opsCopsGateId, "") && !Objects.equals(opsCopsGateId, null)) {
1648                             ccapId = findCcapForSubscriberId(getInetAddress(subscriberId)).getCcapId();
1649                             PCMMService pcmmService = pcmmServiceMap.get(ccapId);
1650                             //is the CCAP socket open?
1651                             if (!pcmmService.getPcmmPdpSocket() && pcmmService.getPcmmCcapClientIsConnected()) {
1652                                 PCMMService.GateSendStatus status = pcmmService.sendGateInfo(gatePathStr);
1653                                 DateAndTime gateDateAndTime = getNowTimeStamp();
1654
1655                                 gateBuilder.setGateId(gateId)
1656                                         .setGatePath(gatePathStr)
1657                                         .setCcapId(ccapId)
1658                                         .setCopsGateState(
1659                                                 status.getCopsGateState() + "/" + status.getCopsGateStateReason())
1660                                         .setCopsGateTimeInfo(status.getCopsGateTimeInfo())
1661                                         .setCopsGateUsageInfo(status.getCopsGateUsageInfo())
1662                                         .setCopsGateId(status.getCopsGateId())
1663                                         .setError(gateOutputError)
1664                                         .setTimestamp(gateDateAndTime);
1665
1666                                 mdsalUtils.put(LogicalDatastoreType.OPERATIONAL, gateIid, gateBuilder.build());
1667                             } else {
1668                                 logger.info(
1669                                         "qospollgates: {}: CCAP Cops socket is down or client disconnected; gate poll not performed",
1670                                         ccapId);
1671                             }
1672                         } else {
1673                             //TODO define what happens if a gate is not active.. is nothing ok?
1674                             logger.info("qospollgates: {}: gate not active; gate poll not performed", gatePathStr);
1675                         }
1676                     } //for
1677                     rpcResponse = inputSubscriberId + "/: subscriber subtree poll in progress";
1678                 } else {
1679                     rpcResponse =
1680                             inputSubscriberId + "/: subscriber is not defined in the system, gate poll not performed";
1681                 }
1682             }
1683         } //inputSubId if
1684         else {
1685             // inputSubId is null
1686             if (inputGateId != null) {
1687                 gatePathStr = appKey.getAppId() + "/" + inputSubscriberId + "/" + inputGateId;
1688                 rpcResponse = gatePathStr + ": Subscriber ID not provided; gate poll not performed";
1689             } else {
1690                 //poll all gates for the appId
1691                 PollAllGatesForApp pollAllGatesForApp = new PollAllGatesForApp(appIid,app);
1692                 Thread t = new Thread(pollAllGatesForApp);
1693                 t.start();
1694                 rpcResponse = appKey.getAppId() + "/: gate subtree poll in progress";
1695             }
1696         }
1697
1698         DateAndTime rpcDateAndTime = getNowTimeStamp();
1699
1700         QosPollGatesOutputBuilder outputBuilder = new QosPollGatesOutputBuilder().setTimestamp(rpcDateAndTime)
1701                 .setResponse(rpcResponse)
1702                 .setGate(gateOutputBuilder.build());
1703         return Futures.immediateFuture(RpcResultBuilder.success(outputBuilder.build()).build());
1704     }
1705     private class PollAllGatesForApp implements Runnable {
1706
1707         private final InstanceIdentifier <App> appIid;
1708         private final App app;
1709
1710         private PollAllGatesForApp (InstanceIdentifier <App> appIid, App app) {
1711             this.app = app;
1712             this.appIid = appIid;
1713         }
1714
1715         @Override
1716         public void run() {
1717
1718             org.opendaylight.yang.gen.v1.urn.packetcable.rev170224.qos.poll.gates.output.GateBuilder gateOutputBuilder =
1719                     new org.opendaylight.yang.gen.v1.urn.packetcable.rev170224.qos.poll.gates.output.GateBuilder();
1720
1721             GateBuilder gateBuilder = new GateBuilder();
1722
1723             //generate appKey
1724             AppKey appKey = InstanceIdentifier.keyOf(appIid);
1725
1726             Subscribers subs = app.getSubscribers();
1727             logger.info("qospollgates subscribers: " + subs.toString());
1728
1729             List<Subscriber> subList = subs.getSubscriber();
1730             logger.info("qospollgates subList: " + subList.toString());
1731
1732             for (Subscriber sub : subList) {
1733                 //generate active subIid
1734                 String subscriberId = sub.getSubscriberId();
1735                 InstanceIdentifier<Subscriber> subIid = appIid.builder()
1736                         .child(Subscribers.class)
1737                         .child(Subscriber.class, new SubscriberKey(subscriberId))
1738                         .build();
1739
1740                 List<Gate> gateList = sub.getGates().getGate();
1741
1742                 for (Gate gate : gateList) {
1743                     //logger.info("qospollgates active gate: "+gate);
1744
1745                     //generate active gateIid
1746                     String gateId = gate.getGateId();
1747                     InstanceIdentifier<Gate> gateIid =
1748                             subIid.builder().child(Gates.class).child(Gate.class, new GateKey(gateId)).build();
1749
1750
1751                     Gate opsGate = readGateFromOperationalDatastore(gateIid);
1752                     String opsCopsGateId = opsGate.getCopsGateId();
1753                     //generate active gatePathStr
1754                     String gatePathStr = appKey.getAppId() + "/" + subscriberId + "/" + gateId;
1755
1756                     if (!Objects.equals(opsCopsGateId, "") && !Objects.equals(opsCopsGateId, null)) {
1757                         String ccapId = findCcapForSubscriberId(getInetAddress(subscriberId)).getCcapId();
1758                         PCMMService pcmmService = pcmmServiceMap.get(ccapId);
1759                         //is the CCAP socket open?
1760                         if (!pcmmService.getPcmmPdpSocket() && pcmmService.getPcmmCcapClientIsConnected()) {
1761                             PCMMService.GateSendStatus status = pcmmService.sendGateInfo(gatePathStr);
1762                             DateAndTime gateDateAndTime = getNowTimeStamp();
1763                             List<String> gateOutputError = Collections.singletonList(status.getMessage());
1764
1765
1766                             gateBuilder.setGateId(gateId)
1767                                     .setGatePath(gatePathStr)
1768                                     .setCcapId(ccapId)
1769                                     .setCopsGateState(
1770                                             status.getCopsGateState() + "/" + status.getCopsGateStateReason())
1771                                     .setCopsGateTimeInfo(status.getCopsGateTimeInfo())
1772                                     .setCopsGateUsageInfo(status.getCopsGateUsageInfo())
1773                                     .setCopsGateId(status.getCopsGateId())
1774                                     .setError(gateOutputError)
1775                                     .setTimestamp(gateDateAndTime);
1776
1777                             mdsalUtils.put(LogicalDatastoreType.OPERATIONAL, gateIid, gateBuilder.build());
1778                         } else {
1779                             logger.info(
1780                                     "qospollgates: {}: CCAP socket is down or client disconnected; gate poll not performed",
1781                                     ccapId);
1782                         }
1783                     } else {
1784                         //TODO define what happens if a gate is not active.. is nothing ok
1785                         logger.info("qospollgates: {}: gate not active; gate poll not performed", gatePathStr);
1786                     }
1787                 }
1788             }
1789         }
1790     }
1791
1792
1793     private DateAndTime getNowTimeStamp() {
1794         DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSXXX");
1795         return new DateAndTime(dateFormat.format(new Date()));
1796     }
1797 }