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