Added GateInfo to Op Ds and RPCs to support gate update requests
[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.Maps;
15 import com.google.common.collect.Sets;
16 import com.google.common.util.concurrent.CheckedFuture;
17 import com.google.common.util.concurrent.Futures;
18
19 import java.net.InetAddress;
20 import java.net.UnknownHostException;
21 import java.text.DateFormat;
22 import java.text.SimpleDateFormat;
23 import java.util.ArrayList;
24 import java.util.Collections;
25 import java.util.Date;
26 import java.util.List;
27 import java.util.Map;
28 import java.util.Objects;
29 import java.util.Set;
30 import java.util.concurrent.ConcurrentHashMap;
31 import java.util.concurrent.ExecutionException;
32 import java.util.concurrent.Executor;
33 import java.util.concurrent.Executors;
34 import java.util.concurrent.Future;
35
36 import javax.annotation.Nonnull;
37 import javax.annotation.concurrent.ThreadSafe;
38
39 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
40 import org.opendaylight.controller.md.sal.binding.api.DataChangeListener;
41 import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
42 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
43 import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException;
44 import org.opendaylight.controller.packetcable.provider.validation.DataValidator;
45 import org.opendaylight.controller.packetcable.provider.validation.ValidationException;
46 import org.opendaylight.controller.packetcable.provider.validation.Validator;
47 import org.opendaylight.controller.packetcable.provider.validation.impl.CcapsValidatorProviderFactory;
48 import org.opendaylight.controller.packetcable.provider.validation.impl.QosValidatorProviderFactory;
49 import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.ProviderContext;
50 import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.RoutedRpcRegistration;
51 import org.opendaylight.controller.sal.binding.api.BindingAwareProvider;
52 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.IpPrefix;
53 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Ipv4Prefix;
54 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev100924.DateAndTime;
55 import org.opendaylight.yang.gen.v1.urn.packetcable.rev151101.AppContext;
56 import org.opendaylight.yang.gen.v1.urn.packetcable.rev151101.CcapContext;
57 import org.opendaylight.yang.gen.v1.urn.packetcable.rev151101.CcapPollConnectionInput;
58 import org.opendaylight.yang.gen.v1.urn.packetcable.rev151101.CcapPollConnectionOutput;
59 import org.opendaylight.yang.gen.v1.urn.packetcable.rev151101.CcapPollConnectionOutputBuilder;
60 import org.opendaylight.yang.gen.v1.urn.packetcable.rev151101.CcapSetConnectionInput;
61 import org.opendaylight.yang.gen.v1.urn.packetcable.rev151101.CcapSetConnectionOutput;
62 import org.opendaylight.yang.gen.v1.urn.packetcable.rev151101.CcapSetConnectionOutputBuilder;
63 import org.opendaylight.yang.gen.v1.urn.packetcable.rev151101.Ccaps;
64 import org.opendaylight.yang.gen.v1.urn.packetcable.rev151101.PacketcableService;
65 import org.opendaylight.yang.gen.v1.urn.packetcable.rev151101.Qos;
66 import org.opendaylight.yang.gen.v1.urn.packetcable.rev151101.QosPollGatesInput;
67 import org.opendaylight.yang.gen.v1.urn.packetcable.rev151101.QosPollGatesOutput;
68 import org.opendaylight.yang.gen.v1.urn.packetcable.rev151101.QosPollGatesOutputBuilder;
69 import org.opendaylight.yang.gen.v1.urn.packetcable.rev151101.ServiceClassName;
70 import org.opendaylight.yang.gen.v1.urn.packetcable.rev151101.ServiceFlowDirection;
71 import org.opendaylight.yang.gen.v1.urn.packetcable.rev151101.ccap.attributes.ConnectionBuilder;
72 import org.opendaylight.yang.gen.v1.urn.packetcable.rev151101.ccaps.Ccap;
73 import org.opendaylight.yang.gen.v1.urn.packetcable.rev151101.ccaps.CcapBuilder;
74 import org.opendaylight.yang.gen.v1.urn.packetcable.rev151101.pcmm.qos.gates.Apps;
75 import org.opendaylight.yang.gen.v1.urn.packetcable.rev151101.pcmm.qos.gates.apps.App;
76 import org.opendaylight.yang.gen.v1.urn.packetcable.rev151101.pcmm.qos.gates.apps.AppBuilder;
77 import org.opendaylight.yang.gen.v1.urn.packetcable.rev151101.pcmm.qos.gates.apps.AppKey;
78 import org.opendaylight.yang.gen.v1.urn.packetcable.rev151101.pcmm.qos.gates.apps.app.Subscribers;
79 import org.opendaylight.yang.gen.v1.urn.packetcable.rev151101.pcmm.qos.gates.apps.app.SubscribersBuilder;
80 import org.opendaylight.yang.gen.v1.urn.packetcable.rev151101.pcmm.qos.gates.apps.app.subscribers.Subscriber;
81 import org.opendaylight.yang.gen.v1.urn.packetcable.rev151101.pcmm.qos.gates.apps.app.subscribers.SubscriberBuilder;
82 import org.opendaylight.yang.gen.v1.urn.packetcable.rev151101.pcmm.qos.gates.apps.app.subscribers.SubscriberKey;
83 import org.opendaylight.yang.gen.v1.urn.packetcable.rev151101.pcmm.qos.gates.apps.app.subscribers.subscriber.Gates;
84 import org.opendaylight.yang.gen.v1.urn.packetcable.rev151101.pcmm.qos.gates.apps.app.subscribers.subscriber.GatesBuilder;
85 import org.opendaylight.yang.gen.v1.urn.packetcable.rev151101.pcmm.qos.gates.apps.app.subscribers.subscriber.gates.Gate;
86 import org.opendaylight.yang.gen.v1.urn.packetcable.rev151101.pcmm.qos.gates.apps.app.subscribers.subscriber.gates.GateBuilder;
87 import org.opendaylight.yang.gen.v1.urn.packetcable.rev151101.pcmm.qos.gates.apps.app.subscribers.subscriber.gates.GateKey;
88 import org.opendaylight.yangtools.concepts.ListenerRegistration;
89 import org.opendaylight.yangtools.yang.binding.DataObject;
90 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
91 import org.opendaylight.yangtools.yang.common.RpcResult;
92 import org.opendaylight.yangtools.yang.common.RpcResultBuilder;
93 import org.pcmm.rcd.IPCMMClient;
94 import org.slf4j.Logger;
95 import org.slf4j.LoggerFactory;
96
97 /**
98  * Called by ODL framework to start this bundle.
99  * <p>
100  * This class is responsible for processing messages received from ODL's restconf interface.
101  * TODO - Remove some of these state maps and move some of this into the PCMMService
102  * TODO Don't implement PacketcableService, move that into an inner class
103  */
104 @ThreadSafe
105 public class PacketcableProvider implements BindingAwareProvider, AutoCloseable, PacketcableService {
106
107     private static final Logger logger = LoggerFactory.getLogger(PacketcableProvider.class);
108
109     // keys to the /restconf/config/packetcable:ccaps and /restconf/config/packetcable:qos config datastore
110     private static final InstanceIdentifier<Ccaps> ccapsIID = InstanceIdentifier.builder(Ccaps.class).build();
111     private static final InstanceIdentifier<Qos> qosIID = InstanceIdentifier.builder(Qos.class).build();
112
113     // TODO - Revisit these maps and remove the ones no longer necessary
114     private final Map<String, Ccap> ccapMap = new ConcurrentHashMap<>();
115     private final Map<String, Gate> gateMap = new ConcurrentHashMap<>();
116     private final Map<String, String> gateCcapMap = new ConcurrentHashMap<>();
117     private final Map<Subnet, Ccap> subscriberSubnetsMap = new ConcurrentHashMap<>();
118     private final Map<ServiceClassName, List<Ccap>> downstreamScnMap = new ConcurrentHashMap<>();
119     private final Map<ServiceClassName, List<Ccap>> upstreamScnMap = new ConcurrentHashMap<>();
120
121     private final Executor executor = Executors.newSingleThreadExecutor();
122
123     /**
124      * Holds a PCMMService object for each CCAP being managed.
125      */
126     private final Map<String, PCMMService> pcmmServiceMap = new ConcurrentHashMap<>();
127
128     /**
129      * The ODL object used to broker messages throughout the framework
130      */
131     private DataBroker dataBroker;
132     private MdsalUtils mdsalUtils;
133
134     //Routed RPC Registration
135     private RoutedRpcRegistration<PacketcableService> rpcRegistration;
136
137     // Data change listeners/registrations
138     private final CcapsDataChangeListener ccapsDataChangeListener = new CcapsDataChangeListener();
139     private final QosDataChangeListener qosDataChangeListener = new QosDataChangeListener();
140
141     private ListenerRegistration<DataChangeListener> ccapsDataChangeListenerRegistration;
142     private ListenerRegistration<DataChangeListener> qosDataChangeListenerRegistration;
143
144     /**
145      * Constructor
146      */
147     public PacketcableProvider() {
148         logger.info("Starting provider");
149     }
150
151     @Override
152     public void onSessionInitiated(ProviderContext session) {
153         logger.info("Packetcable Session Initiated");
154         logger.info("logging levels: error={}, warn={}, info={}, debug={}, trace={}", logger.isErrorEnabled(),
155                 logger.isWarnEnabled(), logger.isInfoEnabled(), logger.isDebugEnabled(), logger.isTraceEnabled());
156
157         dataBroker = session.getSALService(DataBroker.class);
158
159         mdsalUtils = new MdsalUtils(dataBroker);
160
161         ccapsDataChangeListenerRegistration =
162                 dataBroker.registerDataChangeListener(LogicalDatastoreType.CONFIGURATION, ccapsIID.child(Ccap.class),
163                         ccapsDataChangeListener, DataBroker.DataChangeScope.SUBTREE);
164
165         qosDataChangeListenerRegistration = dataBroker.registerDataChangeListener(LogicalDatastoreType.CONFIGURATION,
166                 PacketcableProvider.qosIID.child(Apps.class).child(App.class), qosDataChangeListener,
167                 DataBroker.DataChangeScope.SUBTREE);
168
169         rpcRegistration = session.addRoutedRpcImplementation(PacketcableService.class, this);
170         logger.info("onSessionInitiated().rpcRgistration: {}", rpcRegistration);
171
172     }
173
174     /**
175      * Implemented from the AutoCloseable interface.
176      */
177     @Override
178     public void close() throws ExecutionException, InterruptedException {
179         if (ccapsDataChangeListenerRegistration != null) {
180             ccapsDataChangeListenerRegistration.close();
181         }
182
183         if (qosDataChangeListenerRegistration != null) {
184             qosDataChangeListenerRegistration.close();
185         }
186     }
187
188     private void updateCcapMaps(final Ccap ccap) {
189         // add ccap to the subscriberSubnets map
190         for (final IpPrefix ipPrefix : ccap.getSubscriberSubnets()) {
191             try {
192                 subscriberSubnetsMap.put(Subnet.createInstance(getIpPrefixStr(ipPrefix)), ccap);
193             } catch (UnknownHostException e) {
194                 logger.error("updateSubscriberSubnets: {}:{} FAILED: {}", ipPrefix, ccap, e.getMessage());
195             }
196         }
197         // ccap to upstream SCN map
198         for (final ServiceClassName scn : ccap.getUpstreamScns()) {
199             if (upstreamScnMap.containsKey(scn)) {
200                 upstreamScnMap.get(scn).add(ccap);
201             } else {
202                 final List<Ccap> ccapList = new ArrayList<>();
203                 ccapList.add(ccap);
204                 upstreamScnMap.put(scn, ccapList);
205             }
206         }
207         // ccap to downstream SCN map
208         for (final ServiceClassName scn : ccap.getDownstreamScns()) {
209             if (downstreamScnMap.containsKey(scn)) {
210                 downstreamScnMap.get(scn).add(ccap);
211             } else {
212                 final List<Ccap> ccapList = new ArrayList<>();
213                 ccapList.add(ccap);
214                 downstreamScnMap.put(scn, ccapList);
215             }
216         }
217     }
218
219     private String getIpPrefixStr(final IpPrefix ipPrefix) {
220         final Ipv4Prefix ipv4 = ipPrefix.getIpv4Prefix();
221         if (ipv4 != null) {
222             return ipv4.getValue();
223         } else {
224             return ipPrefix.getIpv6Prefix().getValue();
225         }
226     }
227
228     public InetAddress getInetAddress(final String subId) {
229         try {
230             return InetAddress.getByName(subId);
231         } catch (UnknownHostException e) {
232             logger.error("getInetAddress: {} FAILED: {}", subId, e.getMessage());
233             return null;
234         }
235     }
236
237     private Ccap findCcapForSubscriberId(final InetAddress inetAddr) {
238         // TODO replace this with a loading cache, https://github.com/google/guava/wiki/CachesExplained
239         Ccap matchedCcap = null;
240         int longestPrefixLen = -1;
241         for (final Map.Entry<Subnet, Ccap> entry : subscriberSubnetsMap.entrySet()) {
242             final Subnet subnet = entry.getKey();
243             if (subnet.isInNet(inetAddr)) {
244                 int prefixLen = subnet.getPrefixLen();
245                 if (prefixLen > longestPrefixLen) {
246                     matchedCcap = entry.getValue();
247                     longestPrefixLen = prefixLen;
248                 }
249             }
250         }
251         return matchedCcap;
252     }
253
254     private ServiceFlowDirection findScnOnCcap(final ServiceClassName scn, final Ccap ccap) {
255         checkNotNull(scn);
256         checkNotNull(ccap);
257
258         if (upstreamScnMap.containsKey(scn)) {
259             final List<Ccap> ccapList = upstreamScnMap.get(scn);
260             if (ccapList.contains(ccap)) {
261                 return ServiceFlowDirection.Us;
262             }
263         } else if (downstreamScnMap.containsKey(scn)) {
264             final List<Ccap> ccapList = downstreamScnMap.get(scn);
265             if (ccapList.contains(ccap)) {
266                 return ServiceFlowDirection.Ds;
267             }
268         }
269         return null;
270     }
271
272     private void removeCcapFromAllMaps(final Ccap ccap) {
273         // remove the ccap from all maps
274         // subscriberSubnets map
275         for (final Map.Entry<Subnet, Ccap> entry : subscriberSubnetsMap.entrySet()) {
276             if (entry.getValue() == ccap) {
277                 subscriberSubnetsMap.remove(entry.getKey());
278             }
279         }
280         // ccap to upstream SCN map
281         for (final Map.Entry<ServiceClassName, List<Ccap>> entry : upstreamScnMap.entrySet()) {
282             final List<Ccap> ccapList = entry.getValue();
283             ccapList.remove(ccap);
284             if (ccapList.isEmpty()) {
285                 upstreamScnMap.remove(entry.getKey());
286             }
287         }
288         // ccap to downstream SCN map
289         for (final Map.Entry<ServiceClassName, List<Ccap>> entry : downstreamScnMap.entrySet()) {
290             final List<Ccap> ccapList = entry.getValue();
291             ccapList.remove(ccap);
292             if (ccapList.isEmpty()) {
293                 downstreamScnMap.remove(entry.getKey());
294             }
295         }
296
297         final PCMMService service = pcmmServiceMap.remove(ccap.getCcapId());
298         if (service != null) {
299             service.disconect();
300         }
301     }
302
303     // ValidationException does not need to be thrown again
304     @SuppressWarnings("ThrowableResultOfMethodCallIgnored")
305     private <T extends DataObject> void saveErrors(@Nonnull Map<InstanceIdentifier<T>, ValidationException> errorMap,
306             @Nonnull Map<InstanceIdentifier<T>, T> dataMap) {
307
308         final WriteTransaction writeTransaction = dataBroker.newWriteOnlyTransaction();
309
310
311         for (InstanceIdentifier<T> iid : errorMap.keySet()) {
312
313             final ValidationException exception = errorMap.get(iid);
314             final T badData = dataMap.get(iid);
315
316             if (!badData.getImplementedInterface().isAssignableFrom(iid.getTargetType())) {
317                 // InstanceIdentifier<T> does not have the same type as the DataObject
318                 logger.error("Bad InstanceIdentifier to DataObject mapping, {} : {}", iid, badData);
319                 continue;
320             }
321
322             if (badData instanceof Ccap) {
323                 final Ccap ccap = (Ccap) badData;
324
325                 final Ccap opperationalCcap =
326                         new CcapBuilder().setCcapId(ccap.getCcapId()).setError(exception.getErrorMessages()).build();
327
328
329                 // type match between iid and badData is done at start of loop
330                 @SuppressWarnings("unchecked") final InstanceIdentifier<Ccap> ccapIID = (InstanceIdentifier<Ccap>) iid;
331                 writeTransaction.put(LogicalDatastoreType.OPERATIONAL, ccapIID, opperationalCcap);
332             } else if (badData instanceof Gate) {
333                 final Gate gate = (Gate) badData;
334
335                 final Gate operationalGate =
336                         new GateBuilder().setGateId(gate.getGateId()).setError(exception.getErrorMessages()).build();
337
338                 final Gates operationalGates =
339                         new GatesBuilder().setGate(Collections.singletonList(operationalGate)).build();
340
341                 final SubscriberKey subscriberKey = InstanceIdentifier.keyOf(iid.firstIdentifierOf(Subscriber.class));
342                 final Subscriber operationalSubscriber =
343                         new SubscriberBuilder().setSubscriberId(subscriberKey.getSubscriberId())
344                                 .setGates(operationalGates)
345                                 .build();
346
347                 final Subscribers operationalSubscribers =
348                         new SubscribersBuilder().setSubscriber(Collections.singletonList(operationalSubscriber))
349                                 .build();
350
351                 final InstanceIdentifier<App> appIID = iid.firstIdentifierOf(App.class);
352                 final AppKey appKey = InstanceIdentifier.keyOf(appIID);
353                 final App operationalApp =
354                         new AppBuilder().setAppId(appKey.getAppId()).setSubscribers(operationalSubscribers).build();
355
356
357                 writeTransaction.put(LogicalDatastoreType.OPERATIONAL, appIID, operationalApp);
358             } else {
359                 // If you get here a developer forgot to add a type above
360                 logger.error("Unexpected type requested for error saving: {}", badData);
361                 throw new IllegalStateException("Unsupported type for error saving");
362             }
363
364         }
365
366
367         CheckedFuture<Void, TransactionCommitFailedException> future = writeTransaction.submit();
368
369         try {
370             future.checkedGet();
371         } catch (TransactionCommitFailedException e) {
372             logger.error("Failed to write errors to operational datastore", e);
373         }
374     }
375
376     /**
377      * Removes Ccaps if all Ccap instances are removed
378      */
379     private class CcapsCleaner extends AbstractCleaner<Ccaps> {
380
381         public CcapsCleaner(final InstanceIdentifier<?> removedIID) {
382             super(removedIID, Ccaps.class, LogicalDatastoreType.OPERATIONAL);
383         }
384
385         @Override
386         protected boolean shouldClean(final Ccaps ccaps) {
387             return ccaps.getCcap().isEmpty();
388         }
389     }
390
391
392     /**
393      * Removes Subscriber if all Gate instances are removed
394      */
395     private class SubscriberCleaner extends AbstractCleaner<Subscriber> {
396
397         public SubscriberCleaner(InstanceIdentifier<Gate> removedGateIID) {
398             super(removedGateIID, Subscriber.class, LogicalDatastoreType.OPERATIONAL);
399         }
400
401         @Override
402         protected boolean shouldClean(final Subscriber subscriber) {
403             return subscriber.getGates().getGate().isEmpty();
404         }
405
406         @Override
407         protected void postRemove(InstanceIdentifier<Subscriber> subscriberIID) {
408             executor.execute(new AppCleaner(subscriberIID));
409         }
410     }
411
412
413     /**
414      * Removes App if all Subscribers are removed.
415      */
416     private class AppCleaner extends AbstractCleaner<App> {
417
418         public AppCleaner(InstanceIdentifier<Subscriber> removedSubscriberIID) {
419             super(removedSubscriberIID, App.class, LogicalDatastoreType.OPERATIONAL);
420         }
421
422         @Override
423         boolean shouldClean(final App app) {
424             return app.getSubscribers().getSubscriber().isEmpty();
425         }
426
427         @Override
428         void postRemove(final InstanceIdentifier<App> appIID) {
429             //unregister app rpc path
430             logger.info("Un-Registering App Routed RPC Path...");
431             rpcRegistration.unregisterPath(AppContext.class, appIID);
432             executor.execute(new AppsCleaner(appIID));
433         }
434     }
435
436
437     /**
438      * Removes Apps if all App instances are removed.
439      */
440     private class AppsCleaner extends AbstractCleaner<Apps> {
441
442         public AppsCleaner(InstanceIdentifier<App> removedAppIID) {
443             super(removedAppIID, Apps.class, LogicalDatastoreType.OPERATIONAL);
444         }
445
446         @Override
447         protected boolean shouldClean(final Apps apps) {
448             return apps.getApp().isEmpty();
449         }
450     }
451
452
453     /**
454      * Helper class to do the heavy lifting in removing object. Lets subclasses decide with
455      * {@link #shouldClean(DataObject)}. <br>
456      * <p>
457      * Subclasses can react after an instance is removed by overriding {@link #postRemove(InstanceIdentifier)}
458      *
459      * @param <T>
460      *         The type that will be removed
461      */
462     private abstract class AbstractCleaner<T extends DataObject> implements Runnable {
463         final InstanceIdentifier<?> removedIID;
464         final Class<T> tClass;
465         final LogicalDatastoreType datastoreType;
466
467         public AbstractCleaner(InstanceIdentifier<?> removedIID, Class<T> tClass, LogicalDatastoreType datastoreType) {
468             this.removedIID = checkNotNull(removedIID);
469             this.tClass = checkNotNull(tClass);
470             this.datastoreType = checkNotNull(datastoreType);
471         }
472
473         @Override
474         public void run() {
475             InstanceIdentifier<T> tIID = removedIID.firstIdentifierOf(tClass);
476             if (tIID != null) {
477                 Optional<T> optional = mdsalUtils.read(datastoreType, tIID);
478                 if (optional.isPresent()) {
479
480                     if (shouldClean(optional.get())) {
481                         if (mdsalUtils.delete(datastoreType, tIID)) {
482                             postRemove(tIID);
483                         } else {
484                             removeFailed(tIID);
485                         }
486                     }
487
488                 }
489             } else {
490                 logger.error("Expected to find InstanceIdentifier<{}> but was not found: {}", tClass.getSimpleName(),
491                         removedIID);
492             }
493         }
494
495         /**
496          * If returns true the object will be removed from the datastore
497          *
498          * @param object
499          *         The object that might be removed.
500          * @return true if it should be removed.
501          */
502         abstract boolean shouldClean(final T object);
503
504         /**
505          * Called after an instance is removed.
506          *
507          * @param tIID
508          *         the InstanceIdentifier of the removed object
509          */
510         void postRemove(InstanceIdentifier<T> tIID) {
511
512         }
513
514         void removeFailed(InstanceIdentifier<T> tIID) {
515             logger.error("Failed to remove {}", tIID);
516         }
517     }
518
519
520     /**
521      * Listener for the packetcable:ccaps tree
522      */
523     private class CcapsDataChangeListener extends AbstractDataChangeListener<Ccap> {
524
525         private final DataValidator ccapsDataValidator = new DataValidator(new CcapsValidatorProviderFactory().build());
526
527         private final Set<InstanceIdentifier<Ccap>> updateQueue = Sets.newConcurrentHashSet();
528
529         public CcapsDataChangeListener() {
530             super(Ccap.class);
531         }
532
533         @Override
534         protected void handleCreatedData(final Map<InstanceIdentifier<Ccap>, Ccap> createdCcaps) {
535             if (createdCcaps.isEmpty()) {
536                 return;
537             }
538
539             final Map<InstanceIdentifier<Ccap>, ValidationException> errorMap =
540                     ccapsDataValidator.validateOneType(createdCcaps, Validator.Extent.NODE_AND_SUBTREE);
541
542             // validate all new objects an update operational datastore
543             if (!errorMap.isEmpty()) {
544                 // bad data write errors to operational datastore
545                 saveErrors(errorMap, createdCcaps);
546             }
547
548             if (createdCcaps.size() > errorMap.size()) {
549                 final Map<InstanceIdentifier<Ccap>, Ccap> goodData =
550                         Maps.newHashMapWithExpectedSize(createdCcaps.size() - errorMap.size());
551                 for (InstanceIdentifier<Ccap> iid : createdCcaps.keySet()) {
552                     if (!errorMap.containsKey(iid)) {
553                         goodData.put(iid, createdCcaps.get(iid));
554                     }
555                 }
556                 addNewCcaps(goodData);
557             }
558         }
559
560         private void addNewCcaps(final Map<InstanceIdentifier<Ccap>, Ccap> goodData) {
561             for (InstanceIdentifier<Ccap> iid : goodData.keySet()) {
562                 final Ccap ccap = goodData.get(iid);
563
564                 // add service
565                 if (pcmmServiceMap.containsKey(ccap.getCcapId())) {
566                     logger.error("Already monitoring CCAP - " + ccap);
567                     continue;
568                 }
569                 final PCMMService pcmmService = new PCMMService(IPCMMClient.CLIENT_TYPE, ccap);
570                 // TODO - may want to use the AMID but for the client type but probably not???
571 /*
572                             final PCMMService pcmmService = new PCMMService(
573                                     thisCcap.getAmId().getAmType().shortValue(), thisCcap);
574 */
575                 ConnectionBuilder connectionBuilder = new ConnectionBuilder();
576                 String message = pcmmService.addCcap();
577                 if (message.contains("200 OK")) {
578                     pcmmServiceMap.put(ccap.getCcapId(), pcmmService);
579                     ccapMap.put(ccap.getCcapId(), ccap);
580                     updateCcapMaps(ccap);
581                     logger.info("Created CCAP: {}/{} : {}", iid, ccap, message);
582                     logger.info("Created CCAP: {} : {}", iid, message);
583
584                     connectionBuilder.setConnected(true).setError(Collections.<String>emptyList());
585                 } else {
586                     logger.error("Create CCAP Failed: {} : {}", iid, message);
587
588                     connectionBuilder.setConnected(false).setError(Collections.singletonList(message));
589                 }
590
591                 //register rpc
592                 logger.info("Registering CCAP Routed RPC Path...");
593                 rpcRegistration.registerPath(CcapContext.class, iid);
594
595                 Optional<Ccap> optionalCcap = mdsalUtils.read(LogicalDatastoreType.OPERATIONAL, iid);
596
597                 final CcapBuilder responseCcapBuilder;
598                 if (optionalCcap.isPresent()) {
599                     responseCcapBuilder = new CcapBuilder(optionalCcap.get());
600                 } else {
601                     responseCcapBuilder = new CcapBuilder();
602                     responseCcapBuilder.setCcapId(ccap.getCcapId());
603                 }
604
605                 responseCcapBuilder.setConnection(connectionBuilder.build());
606
607                 mdsalUtils.put(LogicalDatastoreType.OPERATIONAL, iid, responseCcapBuilder.build());
608             }
609
610         }
611
612         @Override
613         protected void handleUpdatedData(final Map<InstanceIdentifier<Ccap>, Ccap> updatedCcaps,
614                 final Map<InstanceIdentifier<Ccap>, Ccap> originalCcaps) {
615
616             // TODO actually support updates
617
618             // update operation not allowed -- restore the original config object and complain
619             for (final Map.Entry<InstanceIdentifier<Ccap>, Ccap> entry : updatedCcaps.entrySet()) {
620                 if (!originalCcaps.containsKey(entry.getKey())) {
621                     logger.error("No original data found for supposedly updated data: {}", entry.getValue());
622                     continue;
623                 }
624
625                 // If this notification is coming from our modification ignore it.
626                 if (updateQueue.contains(entry.getKey())) {
627                     updateQueue.remove(entry.getKey());
628                     continue;
629                 }
630
631                 final Ccap originalCcap = originalCcaps.get(entry.getKey());
632                 //final Ccap updatedCcap = entry.getValue();
633
634                 //register rpc
635                 logger.info("Registering CCAP Routed RPC Path...");
636                 rpcRegistration.registerPath(CcapContext.class, entry.getKey());
637
638                 // restore the original data
639                 updateQueue.add(entry.getKey());
640                 mdsalUtils.put(LogicalDatastoreType.CONFIGURATION, entry.getKey(), originalCcap);
641                 logger.error("CCAP update not permitted {}", entry.getKey());
642             }
643         }
644
645         @Override
646         protected void handleRemovedData(final Set<InstanceIdentifier<Ccap>> removedCcapPaths,
647                 final Map<InstanceIdentifier<Ccap>, Ccap> originalCcaps) {
648
649             for (InstanceIdentifier<Ccap> iid : removedCcapPaths) {
650                 final Ccap nukedCcap = originalCcaps.get(iid);
651                 removeCcapFromAllMaps(nukedCcap);
652
653                 //unregister ccap rpc path
654                 logger.info("Un-Registering CCAP Routed RPC Path...");
655                 rpcRegistration.unregisterPath(CcapContext.class, iid);
656
657                 mdsalUtils.delete(LogicalDatastoreType.OPERATIONAL, iid);
658
659                 // clean up ccaps level if it is now empty
660                 executor.execute(new CcapsCleaner(iid));
661             }
662
663         }
664     }
665
666
667     private class QosDataChangeListener extends AbstractDataChangeListener<Gate> {
668
669         private final DataValidator qosDataValidator = new DataValidator(new QosValidatorProviderFactory().build());
670         private final Set<InstanceIdentifier<Gate>> updateQueue = Sets.newConcurrentHashSet();
671
672         public QosDataChangeListener() {
673             super(Gate.class);
674         }
675
676         @Override
677         protected void handleCreatedData(final Map<InstanceIdentifier<Gate>, Gate> createdData) {
678
679             final Map<InstanceIdentifier<Gate>, ValidationException> errorMap =
680                     qosDataValidator.validateOneType(createdData, Validator.Extent.NODE_AND_SUBTREE);
681
682             // validate all new objects an update operational datastore
683             if (!errorMap.isEmpty()) {
684                 // bad data write errors to operational datastore
685                 saveErrors(errorMap, createdData);
686             }
687
688             if (createdData.size() > errorMap.size()) {
689                 final Map<InstanceIdentifier<Gate>, Gate> goodData =
690                         Maps.newHashMapWithExpectedSize(createdData.size() - errorMap.size());
691                 for (InstanceIdentifier<Gate> iid : createdData.keySet()) {
692                     if (!errorMap.containsKey(iid)) {
693                         goodData.put(iid, createdData.get(iid));
694                     }
695                 }
696                 addNewGates(goodData);
697             }
698
699         }
700
701         private void addNewGates(final Map<InstanceIdentifier<Gate>, Gate> createdGates) {
702
703             for (InstanceIdentifier<Gate> gateIID : createdGates.keySet()) {
704                 final Gate newGate = createdGates.get(gateIID);
705
706                 final String newGatePathStr = makeGatePathString(gateIID);
707
708                 // if a new app comes along add RPC registration
709                 final InstanceIdentifier<App> appIID = gateIID.firstIdentifierOf(App.class);
710                 // TBD verify if App ID exists first
711
712                 //register appID RPC path
713                 logger.info("Registering App Routed RPC Path...");
714                 rpcRegistration.registerPath(AppContext.class, appIID);
715
716                 final InstanceIdentifier<Subscriber> subscriberIID = gateIID.firstIdentifierOf(Subscriber.class);
717                 final SubscriberKey subscriberKey = InstanceIdentifier.keyOf(subscriberIID);
718                 final InetAddress subscriberAddr = getInetAddress(subscriberKey.getSubscriberId());
719                 if (subscriberAddr == null) {
720                     final String msg = String.format("subscriberId must be a valid ipaddress: %s",
721                             subscriberKey.getSubscriberId());
722                     logger.error(msg);
723                     saveGateError(gateIID, newGatePathStr, msg);
724                     continue;
725                 }
726
727                 final Ccap ccap = findCcapForSubscriberId(subscriberAddr);
728                 if (ccap == null) {
729                     final String msg = String.format("Unable to find Ccap for subscriber %s: @ %s",
730                             subscriberKey.getSubscriberId(), newGatePathStr);
731                     logger.error(msg);
732                     saveGateError(gateIID, newGatePathStr, msg);
733                     continue;
734                 }
735
736                 final ServiceClassName scn = newGate.getTrafficProfile().getServiceClassName();
737                 final ServiceFlowDirection scnDirection = findScnOnCcap(scn, ccap);
738                 if (scnDirection == null) {
739                     final String msg =
740                             String.format("SCN %s not found on CCAP %s for %s", scn, ccap.getCcapId(), newGatePathStr);
741                     logger.error(msg);
742                     saveGateError(gateIID, newGatePathStr, msg);
743                     continue;
744                 }
745
746                 final PCMMService pcmmService = pcmmServiceMap.get(ccap.getCcapId());
747                 if (pcmmService == null) {
748                     final String msg =
749                             String.format("Unable to locate PCMM Service for CCAP: %s ; with subscriber: %s", ccap,
750                                     subscriberKey.getSubscriberId());
751                     logger.error(msg);
752                     saveGateError(gateIID, newGatePathStr, msg);
753                     continue;
754                 }
755
756                 PCMMService.GateSendStatus status =
757                         pcmmService.sendGateSet(newGatePathStr, subscriberAddr, newGate, scnDirection);
758                 if (status.didSucceed()) {
759                     gateMap.put(newGatePathStr, newGate);
760                     gateCcapMap.put(newGatePathStr, ccap.getCcapId());
761                 }
762                 final GateBuilder gateBuilder = new GateBuilder();
763                 gateBuilder.setGateId(newGate.getGateId())
764                         .setGatePath(newGatePathStr)
765                         .setCcapId(ccap.getCcapId())
766                         .setCopsGateId(status.getCopsGateId())
767                         .setCopsGateState("")
768                         .setTimestamp(getNowTimeStamp())
769                         .setCopsGateTimeInfo("")
770                         .setCopsGateUsageInfo("")
771                         .setTimestamp(getNowTimeStamp());
772
773                 if (!status.didSucceed()) {
774                     gateBuilder.setError(Collections.singletonList(status.getMessage()));
775                 } else {
776                     PCMMService.GateSendStatus infoStatus = pcmmService.sendGateInfo(newGatePathStr);
777
778                     if (infoStatus.didSucceed()) {
779                         gateBuilder.setCopsGateState(
780                                 infoStatus.getCopsGateState() + "/" + infoStatus.getCopsGateStateReason())
781                                 .setCopsGateTimeInfo(infoStatus.getCopsGateTimeInfo())
782                                 .setCopsGateUsageInfo(infoStatus.getCopsGateUsageInfo());
783                     } else {
784                         List<String> errors = new ArrayList<>(2);
785
786                         // Keep GateSetErrors
787                         if (gateBuilder.getError() != null) {
788                             errors.addAll(gateBuilder.getError());
789                         }
790
791                         errors.add(infoStatus.getMessage());
792                         gateBuilder.setError(errors);
793                     }
794
795                 }
796
797                 Gate operationalGate = gateBuilder.build();
798
799                 mdsalUtils.put(LogicalDatastoreType.OPERATIONAL, gateIID, operationalGate);
800
801             }
802
803         }
804
805         private void saveGateError(@Nonnull final InstanceIdentifier<Gate> gateIID, @Nonnull final String gatePathStr,
806                 @Nonnull final String error) {
807             checkNotNull(gateIID);
808             checkNotNull(error);
809
810             final GateBuilder gateBuilder = new GateBuilder();
811             gateBuilder.setGateId(InstanceIdentifier.keyOf(gateIID).getGateId())
812                     .setGatePath(gatePathStr)
813                     .setCopsGateId("")
814                     .setCopsGateState("N/A");
815
816             gateBuilder.setError(Collections.singletonList(error));
817
818             Gate operationalGate = gateBuilder.build();
819
820             mdsalUtils.put(LogicalDatastoreType.OPERATIONAL, gateIID, operationalGate);
821         }
822
823         @Override
824         protected void handleUpdatedData(final Map<InstanceIdentifier<Gate>, Gate> updatedData,
825                 final Map<InstanceIdentifier<Gate>, Gate> originalData) {
826             // TODO actually support updates
827
828             // update operation not allowed -- restore the original config object and complain
829             for (final Map.Entry<InstanceIdentifier<Gate>, Gate> entry : updatedData.entrySet()) {
830                 if (!originalData.containsKey(entry.getKey())) {
831                     logger.error("No original data found for supposedly updated data: {}", entry.getValue());
832                     continue;
833                 }
834
835                 // If this notification is coming from our modification ignore it.
836                 if (updateQueue.contains(entry.getKey())) {
837                     updateQueue.remove(entry.getKey());
838                     continue;
839                 }
840
841                 final Gate originalGate = originalData.get(entry.getKey());
842
843                 // restores the original data
844                 updateQueue.add(entry.getKey());
845                 mdsalUtils.put(LogicalDatastoreType.CONFIGURATION, entry.getKey(), originalGate);
846                 logger.error("Update not permitted {}", entry.getKey());
847
848             }
849         }
850
851
852
853         @Override
854         protected void handleRemovedData(final Set<InstanceIdentifier<Gate>> removedPaths,
855                 final Map<InstanceIdentifier<Gate>, Gate> originalData) {
856
857             for (final InstanceIdentifier<Gate> removedGateIID : removedPaths) {
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,
874                                 thisGate);
875                     } else {
876                         logger.warn("Unable to send to locate PCMMService to send gate delete message with CCAP - "
877                                 + thisCcap);
878                     }
879                 }
880
881
882             }
883
884         }
885
886         private String makeGatePathString(InstanceIdentifier<Gate> iid) {
887             final InstanceIdentifier<App> appIID = iid.firstIdentifierOf(App.class);
888             final AppKey appKey = InstanceIdentifier.keyOf(appIID);
889
890             final InstanceIdentifier<Subscriber> subscriberIID = iid.firstIdentifierOf(Subscriber.class);
891             final SubscriberKey subscriberKey = InstanceIdentifier.keyOf(subscriberIID);
892
893             final GateKey gateKey = InstanceIdentifier.keyOf(iid);
894
895             return appKey.getAppId() + "/" + subscriberKey.getSubscriberId() + "/" + gateKey.getGateId();
896         }
897     }
898
899
900     @Override
901     public Future<RpcResult<CcapSetConnectionOutput>> ccapSetConnection(CcapSetConnectionInput input) {
902         // TODO refactor this method into smaller parts
903
904         InstanceIdentifier<Ccap> ccapIid = (InstanceIdentifier<Ccap>) input.getCcapId();
905         List<String> outputError = new ArrayList<String>();
906         String rpcResponse = null;
907         Boolean inputIsConnected = input.getConnection().isConnected();
908         Boolean effectiveIsConnected = null;
909         String ccapId = input.getCcapId().firstIdentifierOf(Ccap.class).firstKeyOf(Ccap.class).getCcapId();
910         PCMMService pcmmService = pcmmServiceMap.get(ccapId);
911
912         if (!inputIsConnected) {
913             // set connected false
914             if (pcmmService.getPcmmPdpSocket()) {
915                 outputError.add(ccapId + ": CCAP COPS socket is already closed");
916                 effectiveIsConnected = false;
917             } else {
918                 //if (!pcmmService.getPcmmCcapClientIsConnected()) {
919                 outputError.add(ccapId + ": CCAP client is disconnected with error: "
920                         + pcmmService.getPcmmCcapClientConnectErrMsg());
921                 //}
922                 pcmmService.ccapClient.disconnect();
923                 effectiveIsConnected = false;
924             }
925         } else {
926             // set connected true
927             if (!pcmmService.getPcmmPdpSocket() && pcmmService.getPcmmCcapClientIsConnected()) {
928                 outputError.add(ccapId + ": CCAP COPS socket is already open");
929                 outputError.add(ccapId + ": CCAP client is connected");
930                 effectiveIsConnected = true;
931             } else {
932                 if (pcmmService.getPcmmCcapClientIsConnected()) {
933                     pcmmService.ccapClient.disconnect();
934                 }
935                 pcmmService.ccapClient.connect();
936                 if (pcmmService.getPcmmCcapClientIsConnected()) {
937                     effectiveIsConnected = true;
938                     outputError.add(ccapId + ": CCAP client is connected");
939                 } else {
940                     effectiveIsConnected = false;
941                     outputError.add(ccapId + ": CCAP client is disconnected with error: "
942                             + pcmmService.getPcmmCcapClientConnectErrMsg());
943                 }
944             }
945         }
946
947         DateAndTime connectionDateAndTime = getNowTimeStamp();
948         org.opendaylight.yang.gen.v1.urn.packetcable.rev151101.ccap.set.connection.output.ccap.ConnectionBuilder
949                 connectionRpcOutput =
950                 new org.opendaylight.yang.gen.v1.urn.packetcable.rev151101.ccap.set.connection.output.ccap.ConnectionBuilder()
951                         .setConnected(effectiveIsConnected)
952                         .setError(outputError)
953                         .setTimestamp(connectionDateAndTime);
954
955         org.opendaylight.yang.gen.v1.urn.packetcable.rev151101.ccap.set.connection.output.CcapBuilder ccapRpcOutput =
956                 new org.opendaylight.yang.gen.v1.urn.packetcable.rev151101.ccap.set.connection.output.CcapBuilder().setCcapId(
957                         ccapId).setConnection(connectionRpcOutput.build());
958
959
960         ConnectionBuilder connectionOps = new ConnectionBuilder().setConnected(effectiveIsConnected)
961                 .setError(outputError)
962                 .setTimestamp(connectionDateAndTime);
963
964         CcapBuilder responseCcapBuilder = new CcapBuilder().setCcapId(ccapId).setConnection(connectionOps.build());
965
966
967         mdsalUtils.put(LogicalDatastoreType.OPERATIONAL, ccapIid, responseCcapBuilder.build());
968
969
970         DateAndTime rpcDateAndTime = getNowTimeStamp();
971         rpcResponse = ccapId + ": CCAP set complete";
972         CcapSetConnectionOutputBuilder outputBuilder =
973                 new CcapSetConnectionOutputBuilder().setCcap(ccapRpcOutput.build())
974                         .setResponse(rpcResponse)
975                         .setTimestamp(rpcDateAndTime);
976
977         return Futures.immediateFuture(RpcResultBuilder.success(outputBuilder.build()).build());
978     }
979
980
981
982     @Override
983     public Future<RpcResult<CcapPollConnectionOutput>> ccapPollConnection(CcapPollConnectionInput input) {
984         // TODO refactor this method into smaller parts
985
986         InstanceIdentifier<Ccap> ccapIid = (InstanceIdentifier<Ccap>) input.getCcapId();
987         List<String> outputError = new ArrayList<String>();
988
989         String ccapId = input.getCcapId().firstIdentifierOf(Ccap.class).firstKeyOf(Ccap.class).getCcapId();
990         PCMMService pcmmService = pcmmServiceMap.get(ccapId);
991         Boolean effectiveIsConnected = true;
992         String response = null;
993         org.opendaylight.yang.gen.v1.urn.packetcable.rev151101.ccap.poll.connection.output.ccap.ConnectionBuilder
994                 connectionRpcOutput =
995                 new org.opendaylight.yang.gen.v1.urn.packetcable.rev151101.ccap.poll.connection.output.ccap.ConnectionBuilder();
996
997         if (pcmmService != null) {
998             if (pcmmService.getPcmmPdpSocket()) {
999                 outputError.add(ccapId + ": CCAP Cops socket is closed");
1000                 if (!pcmmService.getPcmmCcapClientIsConnected()) {
1001                     outputError.add(ccapId + ": CCAP client is disconnected with error: "
1002                             + pcmmService.getPcmmCcapClientConnectErrMsg());
1003                 }
1004                 effectiveIsConnected = false;
1005             } else {
1006                 //outputError.add(String.format(ccapId+": CCAP Cops socket is open"));
1007                 if (!pcmmService.getPcmmCcapClientIsConnected()) {
1008                     outputError.add(ccapId + ": CCAP client is disconnected with error: "
1009                             + pcmmService.getPcmmCcapClientConnectErrMsg());
1010                     effectiveIsConnected = false;
1011                 } else {
1012                     outputError.add(ccapId + ": CCAP client is connected");
1013                 }
1014             }
1015             DateAndTime connectionDateAndTime = getNowTimeStamp();
1016
1017
1018             ConnectionBuilder connectionOps = new ConnectionBuilder().setConnected(effectiveIsConnected)
1019                     .setError(outputError)
1020                     .setTimestamp(connectionDateAndTime);
1021
1022             CcapBuilder responseCcapBuilder = new CcapBuilder().setCcapId(ccapId).setConnection(connectionOps.build());
1023
1024             connectionRpcOutput =
1025                     new org.opendaylight.yang.gen.v1.urn.packetcable.rev151101.ccap.poll.connection.output.ccap.ConnectionBuilder()
1026                             .setConnected(effectiveIsConnected)
1027                             .setError(outputError)
1028                             .setTimestamp(connectionDateAndTime);
1029
1030             mdsalUtils.put(LogicalDatastoreType.OPERATIONAL, ccapIid, responseCcapBuilder.build());
1031             response = ccapId + ": CCAP poll complete";
1032         } else {
1033             //pcmmService is null, do not poll
1034             response = ccapId + ": CCAP connection null; no poll performed";
1035         }
1036
1037         DateAndTime rpcDateAndTime = getNowTimeStamp();
1038
1039         org.opendaylight.yang.gen.v1.urn.packetcable.rev151101.ccap.poll.connection.output.CcapBuilder ccapRpcOutput =
1040                 new org.opendaylight.yang.gen.v1.urn.packetcable.rev151101.ccap.poll.connection.output.CcapBuilder().setCcapId(
1041                         ccapId).setConnection(connectionRpcOutput.build());
1042
1043         CcapPollConnectionOutputBuilder outputBuilder =
1044                 new CcapPollConnectionOutputBuilder().setCcap(ccapRpcOutput.build())
1045                         .setResponse(response)
1046                         .setTimestamp(rpcDateAndTime);
1047
1048         return Futures.immediateFuture(RpcResultBuilder.success(outputBuilder.build()).build());
1049     }
1050
1051
1052
1053     private App readAppFromOperationalDatastore(InstanceIdentifier<App> appIid) {
1054         Optional<App> optionalApp = mdsalUtils.read(LogicalDatastoreType.OPERATIONAL, appIid);
1055         AppBuilder thisAppBuilder = new AppBuilder(optionalApp.get());
1056         App thisApp = thisAppBuilder.build();
1057         logger.info("readAppFromConfigDatastore() retrived App: " + thisApp.getAppId());
1058         return thisApp;
1059     }
1060
1061     private Gate readGateFromOperationalDatastore(InstanceIdentifier<Gate> gateIid) {
1062         Optional<Gate> optionalGate = mdsalUtils.read(LogicalDatastoreType.OPERATIONAL, gateIid);
1063         if (optionalGate.isPresent()) {
1064             GateBuilder gateBuilder = new GateBuilder(optionalGate.get());
1065             Gate thisGate = gateBuilder.build();
1066             return thisGate;
1067         } else {
1068             return null;
1069         }
1070     }
1071
1072     private Subscriber readSubscriberFromOperationalDatastore(InstanceIdentifier<Subscriber> subscriberIid) {
1073         Optional<Subscriber> optionalSubscriber = mdsalUtils.read(LogicalDatastoreType.OPERATIONAL, subscriberIid);
1074         if (optionalSubscriber.isPresent()) {
1075             SubscriberBuilder subscriberBuilder = new SubscriberBuilder(optionalSubscriber.get());
1076             Subscriber thisSubscriber = subscriberBuilder.build();
1077             return thisSubscriber;
1078         } else {
1079             return null;
1080         }
1081     }
1082
1083
1084
1085     @Override
1086     public Future<RpcResult<QosPollGatesOutput>> qosPollGates(QosPollGatesInput input) {
1087         // TODO refactor this method into smaller parts
1088
1089         InstanceIdentifier<App> appIid = (InstanceIdentifier<App>) input.getAppId();
1090         //logger.info("qospollgates appIid : "+appIid.toString());
1091         App app = readAppFromOperationalDatastore(appIid);
1092         //logger.info("qospollgates app : "+app.toString());
1093         AppKey appKey = InstanceIdentifier.keyOf(appIid);
1094         String inputSubscriberId = input.getSubscriberId();
1095         String inputGateId = input.getGateId();
1096         List<String> gateOutputError = Collections.emptyList();
1097         String subscriberId = null;
1098         String gateId = null;
1099         String ccapId = null;
1100         String gatePathStr = null;
1101         String opsCopsGateId = null;
1102         Gate opsGate = null;
1103
1104         String rpcResponse = null;
1105
1106         org.opendaylight.yang.gen.v1.urn.packetcable.rev151101.qos.poll.gates.output.GateBuilder gateOutputBuilder =
1107                 new org.opendaylight.yang.gen.v1.urn.packetcable.rev151101.qos.poll.gates.output.GateBuilder();
1108
1109         GateBuilder gateBuilder = new GateBuilder();
1110
1111         if (inputSubscriberId != null) {
1112             if (inputGateId != null) {
1113                 //Subscriber Id and Gate Id provided, only one gate to be poolled
1114
1115                 //generate the gateiid
1116                 InstanceIdentifier<Gate> gateIid = appIid.builder()
1117                         .child(Subscribers.class)
1118                         .child(Subscriber.class, new SubscriberKey(inputSubscriberId))
1119                         .child(Gates.class)
1120                         .child(Gate.class, new GateKey(inputGateId))
1121                         .build();
1122
1123
1124                 opsGate = readGateFromOperationalDatastore(gateIid);
1125
1126                 //does the gate exists in the Operational DS?
1127                 if (opsGate == null) {
1128                     gatePathStr = appKey.getAppId() + "/" + inputSubscriberId + "/" + inputGateId;
1129                     rpcResponse = gatePathStr + ": gate does not exist in the system; gate poll not performed";
1130                 } else {
1131                     opsCopsGateId = opsGate.getCopsGateId();
1132                     gatePathStr = opsGate.getGatePath();
1133
1134                     if ((!Objects.equals(opsCopsGateId, "")) && (!Objects.equals(opsCopsGateId, null))) {
1135                         ccapId = findCcapForSubscriberId(getInetAddress(inputSubscriberId)).getCcapId();
1136                         PCMMService pcmmService = pcmmServiceMap.get(ccapId);
1137                         //is the CCAP socket open?
1138                         if (!pcmmService.getPcmmPdpSocket() && pcmmService.getPcmmCcapClientIsConnected()) {
1139                             PCMMService.GateSendStatus status = pcmmService.sendGateInfo(gatePathStr);
1140                             DateAndTime gateDateAndTime = getNowTimeStamp();
1141                             //logger.info("qospollgates Gate Status : GateID/"+status.getCopsGateId());
1142                             //logger.info("qospollgates Gate Status : Message/"+status.getMessage());
1143                             //logger.info("qospollgates Gate Status : DidSucceed/"+status.didSucceed());
1144                             gateOutputError = Collections.singletonList(status.getMessage());
1145
1146                             gateOutputBuilder.setGatePath(gatePathStr)
1147                                     .setCcapId(ccapId)
1148                                     .setCopsGateState(status.getCopsGateState() + "/" + status.getCopsGateStateReason())
1149                                     .setCopsGateTimeInfo(status.getCopsGateTimeInfo())
1150                                     .setCopsGateUsageInfo(status.getCopsGateUsageInfo())
1151                                     .setCopsGateId(status.getCopsGateId())
1152                                     .setError(gateOutputError)
1153                                     .setTimestamp(gateDateAndTime);
1154
1155                             gateBuilder.setGateId(inputGateId)
1156                                     .setGatePath(gatePathStr)
1157                                     .setCcapId(ccapId)
1158                                     .setCopsGateState(status.getCopsGateState() + "/" + status.getCopsGateStateReason())
1159                                     .setCopsGateTimeInfo(status.getCopsGateTimeInfo())
1160                                     .setCopsGateUsageInfo(status.getCopsGateUsageInfo())
1161                                     .setCopsGateId(status.getCopsGateId())
1162                                     .setError(gateOutputError)
1163                                     .setTimestamp(gateDateAndTime);
1164
1165                             mdsalUtils.put(LogicalDatastoreType.OPERATIONAL, gateIid, gateBuilder.build());
1166                             rpcResponse = gatePathStr + ": gate poll complete";
1167                         } else {
1168                             rpcResponse =
1169                                     ccapId + ": CCAP socket is down or client disconnected; gate poll not performed";
1170                         }
1171                     } else {
1172                         rpcResponse = gatePathStr + ": gate not active; gate poll not performed";
1173                     }
1174                 }
1175             } else {
1176                 //inputGateId is null; pool all gates for the subscriber if the sub exists
1177
1178                 //generate active subIid
1179                 InstanceIdentifier<Subscriber> subIid = appIid.builder()
1180                         .child(Subscribers.class)
1181                         .child(Subscriber.class, new SubscriberKey(inputSubscriberId))
1182                         .build();
1183                 //does the subscriber provided exists in the Operational Datastore?
1184                 Subscriber sub = readSubscriberFromOperationalDatastore(subIid);
1185                 if (sub != null) {
1186                     //If Subscriber exsits poll all gates for the subscriber
1187                     subscriberId = sub.getSubscriberId();
1188                     List<Gate> gateList = sub.getGates().getGate();
1189                     for (Gate gate : gateList) {
1190                         //generate active gateIid
1191                         gateId = gate.getGateId();
1192                         InstanceIdentifier<Gate> gateIid =
1193                                 subIid.builder().child(Gates.class).child(Gate.class, new GateKey(gateId)).build();
1194
1195                         opsGate = readGateFromOperationalDatastore(gateIid);
1196                         opsCopsGateId = opsGate.getCopsGateId();
1197                         //generate active gatePathStr
1198                         gatePathStr = appKey.getAppId() + "/" + subscriberId + "/" + gateId;
1199
1200                         if ((!Objects.equals(opsCopsGateId, "")) && (!Objects.equals(opsCopsGateId, null))) {
1201                             ccapId = findCcapForSubscriberId(getInetAddress(subscriberId)).getCcapId();
1202                             PCMMService pcmmService = pcmmServiceMap.get(ccapId);
1203                             //is the CCAP socket open?
1204                             if (!pcmmService.getPcmmPdpSocket() && pcmmService.getPcmmCcapClientIsConnected()) {
1205                                 PCMMService.GateSendStatus status = pcmmService.sendGateInfo(gatePathStr);
1206                                 DateAndTime gateDateAndTime = getNowTimeStamp();
1207
1208                                 gateBuilder.setGateId(gateId)
1209                                         .setGatePath(gatePathStr)
1210                                         .setCcapId(ccapId)
1211                                         .setCopsGateState(
1212                                                 status.getCopsGateState() + "/" + status.getCopsGateStateReason())
1213                                         .setCopsGateTimeInfo(status.getCopsGateTimeInfo())
1214                                         .setCopsGateUsageInfo(status.getCopsGateUsageInfo())
1215                                         .setCopsGateId(status.getCopsGateId())
1216                                         .setError(gateOutputError)
1217                                         .setTimestamp(gateDateAndTime);
1218
1219                                 mdsalUtils.put(LogicalDatastoreType.OPERATIONAL, gateIid, gateBuilder.build());
1220                             } else {
1221                                 logger.info(
1222                                         "qospollgates: {}: CCAP Cops socket is down or client disconnected; gate poll not performed",
1223                                         ccapId);
1224                             }
1225                         } else {
1226                             //TODO define what happens if a gate is not active.. is nothing ok?
1227                             logger.info("qospollgates: {}: gate not active; gate poll not performed", gatePathStr);
1228                         }
1229                     } //for
1230                     rpcResponse = inputSubscriberId + "/: subscriber subtree poll in progress";
1231                 } else {
1232                     rpcResponse =
1233                             inputSubscriberId + "/: subscriber is not defined in the system, gate poll not performed";
1234                 }
1235             }
1236         } //inputSubId if
1237         else {
1238             // inputSubId is null
1239             if (inputGateId != null) {
1240                 gatePathStr = appKey.getAppId() + "/" + inputSubscriberId + "/" + inputGateId;
1241                 rpcResponse = gatePathStr + ": Subscriber ID not provided; gate poll not performed";
1242             } else {
1243                 //poll all gates for the appId
1244
1245                 Subscribers subs = app.getSubscribers();
1246
1247                 logger.info("qospollgates subscribers: " + subs.toString());
1248
1249                 List<Subscriber> subList = subs.getSubscriber();
1250                 logger.info("qospollgates subList: " + subList.toString());
1251                 for (Subscriber sub : subList) {
1252
1253                     //generate active subIid
1254                     subscriberId = sub.getSubscriberId();
1255                     InstanceIdentifier<Subscriber> subIid = appIid.builder()
1256                             .child(Subscribers.class)
1257                             .child(Subscriber.class, new SubscriberKey(subscriberId))
1258                             .build();
1259
1260                     List<Gate> gateList = sub.getGates().getGate();
1261                     for (Gate gate : gateList) {
1262                         //logger.info("qospollgates active gate: "+gate);
1263
1264                         //generate active gateIid
1265                         gateId = gate.getGateId();
1266                         InstanceIdentifier<Gate> gateIid =
1267                                 subIid.builder().child(Gates.class).child(Gate.class, new GateKey(gateId)).build();
1268
1269                         opsGate = readGateFromOperationalDatastore(gateIid);
1270                         opsCopsGateId = opsGate.getCopsGateId();
1271                         //generate active gatePathStr
1272                         gatePathStr = appKey.getAppId() + "/" + subscriberId + "/" + gateId;
1273                         if ((!Objects.equals(opsCopsGateId, "")) && (!Objects.equals(opsCopsGateId, null))) {
1274                             ccapId = findCcapForSubscriberId(getInetAddress(subscriberId)).getCcapId();
1275                             PCMMService pcmmService = pcmmServiceMap.get(ccapId);
1276                             //is the CCAP socket open?
1277                             if (!pcmmService.getPcmmPdpSocket() && pcmmService.getPcmmCcapClientIsConnected()) {
1278                                 PCMMService.GateSendStatus status = pcmmService.sendGateInfo(gatePathStr);
1279                                 DateAndTime gateDateAndTime = getNowTimeStamp();
1280                                 gateOutputError = Collections.singletonList(status.getMessage());
1281
1282
1283                                 gateBuilder.setGateId(gateId)
1284                                         .setGatePath(gatePathStr)
1285                                         .setCcapId(ccapId)
1286                                         .setCopsGateState(
1287                                                 status.getCopsGateState() + "/" + status.getCopsGateStateReason())
1288                                         .setCopsGateTimeInfo(status.getCopsGateTimeInfo())
1289                                         .setCopsGateUsageInfo(status.getCopsGateUsageInfo())
1290                                         .setCopsGateId(status.getCopsGateId())
1291                                         .setError(gateOutputError)
1292                                         .setTimestamp(gateDateAndTime);
1293
1294                                 mdsalUtils.put(LogicalDatastoreType.OPERATIONAL, gateIid, gateBuilder.build());
1295                             } else {
1296                                 logger.info(
1297                                         "qospollgates: {}: CCAP socket is down or client disconnected; gate poll not performed",
1298                                         ccapId);
1299                             }
1300                         } else {
1301                             //TODO define what happens if a gate is not active.. is nothing ok
1302                             logger.info("qospollgates: {}: gate not active; gate poll not performed", gatePathStr);
1303                         }
1304                     }
1305                 }
1306                 rpcResponse = appKey.getAppId() + "/: gate subtree poll in progress";
1307             }
1308         }
1309
1310         DateAndTime rpcDateAndTime = getNowTimeStamp();
1311
1312         QosPollGatesOutputBuilder outputBuilder = new QosPollGatesOutputBuilder().setTimestamp(rpcDateAndTime)
1313                 .setResponse(rpcResponse)
1314                 .setGate(gateOutputBuilder.build());
1315         return Futures.immediateFuture(RpcResultBuilder.success(outputBuilder.build()).build());
1316     }
1317
1318     private DateAndTime getNowTimeStamp() {
1319         DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSXXX");
1320         return new DateAndTime(dateFormat.format(new Date()));
1321     }
1322 }