Merge "Fixed typo in group service. Modified Group and Meter flow Impl"
[controller.git] / opendaylight / md-sal / forwardingrules-manager / src / main / java / org / opendaylight / controller / forwardingrulesmanager / consumer / impl / MeterConsumerImpl.java
1 package org.opendaylight.controller.forwardingrulesmanager.consumer.impl;
2
3 import java.util.ArrayList;
4 import java.util.Collection;
5 import java.util.Collections;
6 import java.util.EnumSet;
7 import java.util.HashMap;
8 import java.util.HashSet;
9 import java.util.Iterator;
10 import java.util.List;
11 import java.util.Map;
12 import java.util.Map.Entry;
13 import java.util.Set;
14 import java.util.concurrent.ConcurrentHashMap;
15 import java.util.concurrent.ConcurrentMap;
16
17 import org.opendaylight.controller.clustering.services.CacheConfigException;
18 import org.opendaylight.controller.clustering.services.CacheExistException;
19 import org.opendaylight.controller.clustering.services.IClusterContainerServices;
20 import org.opendaylight.controller.clustering.services.IClusterServices;
21 import org.opendaylight.controller.md.sal.common.api.data.DataCommitHandler;
22 import org.opendaylight.controller.md.sal.common.api.data.DataCommitHandler.DataCommitTransaction;
23 import org.opendaylight.controller.md.sal.common.api.data.DataModification;
24 import org.opendaylight.controller.sal.common.util.Rpcs;
25 import org.opendaylight.controller.sal.core.IContainer;
26 import org.opendaylight.controller.sal.core.Node;
27 import org.opendaylight.controller.sal.utils.GlobalConstants;
28 import org.opendaylight.controller.sal.utils.Status;
29 import org.opendaylight.controller.sal.utils.StatusCode;
30 import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.config.rev131024.Meters;
31 import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.config.rev131024.meters.Meter;
32 import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.config.rev131024.meters.MeterKey;
33 import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.service.rev130918.AddMeterInputBuilder;
34 import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.service.rev130918.MeterAdded;
35 import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.service.rev130918.MeterRemoved;
36 import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.service.rev130918.MeterUpdated;
37 import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.service.rev130918.RemoveMeterInputBuilder;
38 import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.service.rev130918.SalMeterListener;
39 import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.service.rev130918.SalMeterService;
40 import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.service.rev130918.UpdateMeterInputBuilder;
41 import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.service.rev130918.meter.update.UpdatedMeterBuilder;
42 import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.types.rev130918.band.type.BandType;
43 import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.types.rev130918.band.type.band.type.Drop;
44 import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.types.rev130918.band.type.band.type.DscpRemark;
45 import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.types.rev130918.band.type.band.type.Experimenter;
46 import org.opendaylight.yangtools.concepts.Registration;
47 import org.opendaylight.yangtools.yang.binding.DataObject;
48 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
49 import org.opendaylight.yangtools.yang.binding.NotificationListener;
50 import org.opendaylight.yangtools.yang.common.RpcError;
51 import org.opendaylight.yangtools.yang.common.RpcResult;
52 import org.slf4j.Logger;
53 import org.slf4j.LoggerFactory;
54
55 public class MeterConsumerImpl implements IForwardingRulesManager {
56     protected static final Logger logger = LoggerFactory.getLogger(MeterConsumerImpl.class);
57     private final MeterEventListener meterEventListener = new MeterEventListener();
58     private Registration<NotificationListener> meterListener;
59     private SalMeterService meterService;
60     private MeterDataCommitHandler commitHandler;
61
62     private ConcurrentMap<MeterKey, Meter> originalSwMeterView;
63     @SuppressWarnings("unused")
64     private ConcurrentMap<MeterKey, Meter> installedSwMeterView;
65     @SuppressWarnings("unused")
66     private ConcurrentMap<Node, List<Meter>> nodeMeters;
67     @SuppressWarnings("unused")
68     private ConcurrentMap<MeterKey, Meter> inactiveMeters;
69     @SuppressWarnings("unused")
70     private IContainer container;
71
72     private IClusterContainerServices clusterMeterContainerService = null;
73     
74
75     public MeterConsumerImpl() {
76         InstanceIdentifier<? extends DataObject> path = InstanceIdentifier.builder(Meters.class).child(Meter.class)
77                 .toInstance();
78         meterService = FRMConsumerImpl.getProviderSession().getRpcService(SalMeterService.class);
79         clusterMeterContainerService = FRMConsumerImpl.getClusterContainerService();
80
81         container = FRMConsumerImpl.getContainer();
82
83         if (!(cacheStartup())) {
84             logger.error("Unable to allocate/retrieve meter cache");
85             System.out.println("Unable to allocate/retrieve meter cache");
86         }
87
88         if (null == meterService) {
89             logger.error("Consumer SAL Meter Service is down or NULL. FRM may not function as intended");
90             System.out.println("Consumer SAL Meter Service is down or NULL.");
91             return;
92         }
93
94         // For switch/plugin events
95         meterListener = FRMConsumerImpl.getNotificationService().registerNotificationListener(meterEventListener);
96
97         if (null == meterListener) {
98             logger.error("Listener to listen on meter data modifcation events");
99             System.out.println("Listener to listen on meter data modifcation events.");
100             return;
101         }
102
103         commitHandler = new MeterDataCommitHandler();
104         FRMConsumerImpl.getDataProviderService().registerCommitHandler(path, commitHandler);
105     }
106
107     private boolean allocateMeterCaches() {
108         if (this.clusterMeterContainerService == null) {
109             logger.warn("Meter: Un-initialized clusterMeterContainerService, can't create cache");
110             return false;
111         }
112
113         try {
114             clusterMeterContainerService.createCache("frm.originalSwMeterView",
115                     EnumSet.of(IClusterServices.cacheMode.TRANSACTIONAL));
116
117             clusterMeterContainerService.createCache("frm.installedSwMeterView",
118                     EnumSet.of(IClusterServices.cacheMode.TRANSACTIONAL));
119
120             clusterMeterContainerService.createCache("frm.inactiveMeters",
121                     EnumSet.of(IClusterServices.cacheMode.TRANSACTIONAL));
122
123             clusterMeterContainerService.createCache("frm.nodeMeters",
124                     EnumSet.of(IClusterServices.cacheMode.TRANSACTIONAL));
125
126             // TODO for cluster mode
127             /*
128              * clusterMeterContainerService.createCache(WORK_STATUS_CACHE,
129              * EnumSet.of(IClusterServices.cacheMode.NON_TRANSACTIONAL,
130              * IClusterServices.cacheMode.ASYNC));
131              *
132              * clusterMeterContainerService.createCache(WORK_ORDER_CACHE,
133              * EnumSet.of(IClusterServices.cacheMode.NON_TRANSACTIONAL,
134              * IClusterServices.cacheMode.ASYNC));
135              */
136
137         } catch (CacheConfigException cce) {
138             logger.error("Meter CacheConfigException");
139             return false;
140
141         } catch (CacheExistException cce) {
142             logger.error(" Meter CacheExistException");
143         }
144
145         return true;
146     }
147
148     private void nonClusterMeterObjectCreate() {
149         originalSwMeterView = new ConcurrentHashMap<MeterKey, Meter>();
150         installedSwMeterView = new ConcurrentHashMap<MeterKey, Meter>();
151         nodeMeters = new ConcurrentHashMap<Node, List<Meter>>();
152         inactiveMeters = new ConcurrentHashMap<MeterKey, Meter>();
153     }
154
155     @SuppressWarnings({ "unchecked" })
156     private boolean retrieveMeterCaches() {
157         ConcurrentMap<?, ?> map;
158
159         if (this.clusterMeterContainerService == null) {
160             logger.warn("Meter: un-initialized clusterMeterContainerService, can't retrieve cache");
161             nonClusterMeterObjectCreate();
162             return false;
163         }
164
165         map = clusterMeterContainerService.getCache("frm.originalSwMeterView");
166         if (map != null) {
167             originalSwMeterView = (ConcurrentMap<MeterKey, Meter>) map;
168         } else {
169             logger.error("Retrieval of cache(originalSwMeterView) failed");
170             return false;
171         }
172
173         map = clusterMeterContainerService.getCache("frm.installedSwMeterView");
174         if (map != null) {
175             installedSwMeterView = (ConcurrentMap<MeterKey, Meter>) map;
176         } else {
177             logger.error("Retrieval of cache(installedSwMeterView) failed");
178             return false;
179         }
180
181         map = clusterMeterContainerService.getCache("frm.inactiveMeters");
182         if (map != null) {
183             inactiveMeters = (ConcurrentMap<MeterKey, Meter>) map;
184         } else {
185             logger.error("Retrieval of cache(inactiveMeters) failed");
186             return false;
187         }
188
189         map = clusterMeterContainerService.getCache("frm.nodeMeters");
190         if (map != null) {
191             nodeMeters = (ConcurrentMap<Node, List<Meter>>) map;
192         } else {
193             logger.error("Retrieval of cache(nodeMeter) failed");
194             return false;
195         }
196
197         return true;
198     }
199
200     private boolean cacheStartup() {
201         if (allocateMeterCaches()) {
202             if (retrieveMeterCaches()) {
203                 return true;
204             }
205         }
206
207         return false;
208     }
209
210     /**
211      * Adds Meter to the southbound plugin and our internal database
212      *
213      * @param path
214      * @param dataObject
215      */
216     private Status addMeter(InstanceIdentifier<?> path, Meter meterAddDataObject) {
217         MeterKey meterKey = meterAddDataObject.getKey();
218
219         if (null != meterKey && validateMeter(meterAddDataObject, FRMUtil.operation.ADD).isSuccess()) {
220             if (meterAddDataObject.isInstall()) {
221                 AddMeterInputBuilder meterBuilder = new AddMeterInputBuilder();
222
223                 meterBuilder.setContainerName(meterAddDataObject.getContainerName());
224                 meterBuilder.setFlags(meterAddDataObject.getFlags());
225                 meterBuilder.setMeterBandHeaders(meterAddDataObject.getMeterBandHeaders());
226                 meterBuilder.setMeterId(meterAddDataObject.getMeterId());
227                 meterBuilder.setNode(meterAddDataObject.getNode());
228                // originalSwMeterView.put(meterKey, meterAddDataObject);
229                 meterService.addMeter(meterBuilder.build());
230             }
231
232            // originalSwMeterView.put(meterKey, meterAddDataObject);
233         } else {
234             return new Status(StatusCode.BADREQUEST, "Meter Key or attribute validation failed");
235         }
236
237         return new Status(StatusCode.SUCCESS);
238     }
239
240     /*
241      * Update Meter to the southbound plugin and our internal database
242      *
243      * @param path
244      *
245      * @param dataObject
246      */
247     private Status updateMeter(InstanceIdentifier<?> path, Meter meterUpdateDataObject) {
248         MeterKey meterKey = meterUpdateDataObject.getKey();
249         UpdatedMeterBuilder updateMeterBuilder = null;
250
251         if (null != meterKey && validateMeter(meterUpdateDataObject, FRMUtil.operation.UPDATE).isSuccess()) {
252
253            /* if (originalSwMeterView.containsKey(meterKey)) {
254                 originalSwMeterView.remove(meterKey);
255                 originalSwMeterView.put(meterKey, meterUpdateDataObject);
256             }*/
257
258             if (meterUpdateDataObject.isInstall()) {
259                 UpdateMeterInputBuilder updateMeterInputBuilder = new UpdateMeterInputBuilder();
260                 updateMeterBuilder = new UpdatedMeterBuilder();
261                 updateMeterBuilder.fieldsFrom(meterUpdateDataObject);
262                 updateMeterInputBuilder.setUpdatedMeter(updateMeterBuilder.build());
263
264               /*  if (installedSwMeterView.containsKey(meterKey)) {
265                     installedSwMeterView.remove(meterKey);
266                     installedSwMeterView.put(meterKey, meterUpdateDataObject);
267                 }*/
268
269                 meterService.updateMeter(updateMeterInputBuilder.build());
270             }
271
272         } else {
273             return new Status(StatusCode.BADREQUEST, "Meter Key or attribute validation failed");
274         }
275
276         return new Status(StatusCode.SUCCESS);
277     }
278
279     /*
280      * Remove Meter to the southbound plugin and our internal database
281      *
282      * @param path
283      *
284      * @param dataObject
285      */
286     private Status removeMeter(InstanceIdentifier<?> path, Meter meterRemoveDataObject) {
287         MeterKey meterKey = meterRemoveDataObject.getKey();
288
289         if (null != meterKey && validateMeter(meterRemoveDataObject, FRMUtil.operation.DELETE).isSuccess()) {
290             if (meterRemoveDataObject.isInstall()) {
291                 RemoveMeterInputBuilder meterBuilder = new RemoveMeterInputBuilder();
292                 meterBuilder.setContainerName(meterRemoveDataObject.getContainerName());
293                 meterBuilder.setNode(meterRemoveDataObject.getNode());
294                 meterBuilder.setFlags(meterRemoveDataObject.getFlags());
295                 meterBuilder.setMeterBandHeaders(meterRemoveDataObject.getMeterBandHeaders());
296                 meterBuilder.setMeterId(meterRemoveDataObject.getMeterId());
297                 meterBuilder.setNode(meterRemoveDataObject.getNode());
298                // originalSwMeterView.put(meterKey, meterAddDataObject);
299                 meterService.removeMeter(meterBuilder.build());
300             }
301
302            // originalSwMeterView.put(meterKey, meterAddDataObject);
303         } else {
304             return new Status(StatusCode.BADREQUEST, "Meter Key or attribute validation failed");
305         }
306
307         return new Status(StatusCode.SUCCESS);
308     }
309
310     public Status validateMeter(Meter meter, FRMUtil.operation operation) {
311         String containerName;
312         String meterName;
313         Status returnStatus = null;
314
315         if (null != meter) {
316             containerName = meter.getContainerName();
317
318             if (null == containerName) {
319                 containerName = GlobalConstants.DEFAULT.toString();
320             } else if (!FRMUtil.isNameValid(containerName)) {
321                 logger.error("Container Name is invalid %s" + containerName);
322                 returnStatus = new Status(StatusCode.BADREQUEST, "Container Name is invalid");
323                 return returnStatus;
324             }
325
326             meterName = meter.getMeterName();
327             if (!FRMUtil.isNameValid(meterName)) {
328                 logger.error("Meter Name is invalid %s" + meterName);
329                 returnStatus = new Status(StatusCode.BADREQUEST, "Meter Name is invalid");
330                 return returnStatus;
331             }
332
333          /*   returnResult = doesMeterEntryExists(meter.getKey(), meterName, containerName);
334
335             if (FRMUtil.operation.ADD == operation && returnResult) {
336                 logger.error("Record with same Meter Name exists");
337                 returnStatus = new Status(StatusCode.BADREQUEST, "Meter record exists");
338                 return returnStatus;
339             } else if (!returnResult) {
340                 logger.error("Group record does not exist");
341                 returnStatus = new Status(StatusCode.BADREQUEST, "Meter record does not exist");
342                 return returnStatus;
343             }*/
344
345             for (int i = 0; i < meter.getMeterBandHeaders().getMeterBandHeader().size(); i++) {
346                 if (!meter.getFlags().isMeterBurst()) {
347                     if (0 < meter.getMeterBandHeaders().getMeterBandHeader().get(i).getBurstSize()) {
348                         logger.error("Burst size should only be associated when Burst FLAG is set");
349                         returnStatus = new Status(StatusCode.BADREQUEST,
350                                 "Burst size should only be associated when Burst FLAG is set");
351                         break;
352                     }
353                 }
354             }
355
356             if (null != returnStatus && !returnStatus.isSuccess()) {
357                 return returnStatus;
358             } else {
359                 BandType setBandType = null;
360                 DscpRemark dscpRemark = null;
361                 for (int i = 0; i < meter.getMeterBandHeaders().getMeterBandHeader().size(); i++) {
362                     setBandType = meter.getMeterBandHeaders().getMeterBandHeader().get(i).getBandType();
363                     if (setBandType instanceof DscpRemark) {
364                         dscpRemark = (DscpRemark) setBandType;
365                         if (0 > dscpRemark.getRate()) {
366
367                         }
368                     } else if (setBandType instanceof Drop) {
369                         if (0 < dscpRemark.getPercLevel()) {
370                             logger.error("Number of drop Precedence level");
371                         }
372                     } else if (setBandType instanceof Experimenter) {
373
374                     }
375                 }
376             }
377         }
378         return new Status(StatusCode.SUCCESS);
379     }
380
381     /*private boolean doesMeterEntryExists(MeterKey key, String meterName, String containerName) {
382         if (!originalSwMeterView.containsKey(key)) {
383             return false;
384         }
385
386         for (Entry<MeterKey, Meter> entry : originalSwMeterView.entrySet()) {
387             if (entry.getValue().getMeterName().equals(meterName)) {
388                 if (entry.getValue().getContainerName().equals(containerName)) {
389                     return true;
390                 }
391             }
392         }
393         return false;
394     }*/
395
396     private final class InternalTransaction implements DataCommitTransaction<InstanceIdentifier<?>, DataObject> {
397
398         private final DataModification<InstanceIdentifier<?>, DataObject> modification;
399
400         @Override
401         public DataModification<InstanceIdentifier<?>, DataObject> getModification() {
402             return modification;
403         }
404
405         public InternalTransaction(DataModification<InstanceIdentifier<?>, DataObject> modification) {
406             this.modification = modification;
407         }
408
409         Map<InstanceIdentifier<?>, Meter> additions = new HashMap<>();
410         Map<InstanceIdentifier<?>, Meter> updates = new HashMap<>();
411         Set<InstanceIdentifier<?>> removals = new HashSet<>();
412
413         /**
414          * We create a plan which flows will be added, which will be updated and
415          * which will be removed based on our internal state.
416          *
417          */
418         void prepareUpdate() {
419             
420             Set<Entry<InstanceIdentifier<?>, DataObject>> addMeter = modification.getCreatedConfigurationData().entrySet();
421             for (Entry<InstanceIdentifier<?>, DataObject> entry : addMeter) {
422                 if (entry.getValue() instanceof Meter) {
423                     Meter meter = (Meter) entry.getValue();
424                     additions.put(entry.getKey(), meter);                    
425                 }
426
427             }
428             
429             Set<Entry<InstanceIdentifier<?>, DataObject>> updateMeter = modification.getUpdatedConfigurationData().entrySet();
430             for (Entry<InstanceIdentifier<?>, DataObject> entry : updateMeter) {
431                 if (entry.getValue() instanceof Meter) {
432                     Meter meter = (Meter) entry.getValue();
433                   ///will be fixed once getUpdatedConfigurationData returns only updated data not created data with it.
434                     if (!additions.containsKey(entry.getKey())) {
435                         updates.put(entry.getKey(), meter);       
436                     }
437                 }
438             }
439
440             removals = modification.getRemovedConfigurationData();
441         }
442
443         /**
444          * We are OK to go with execution of plan
445          *
446          */
447         @Override
448         public RpcResult<Void> finish() throws IllegalStateException {
449
450             RpcResult<Void> rpcStatus = commitToPlugin(this);
451             // We return true if internal transaction is successful.
452             // return Rpcs.getRpcResult(true, null, Collections.emptySet());
453             return rpcStatus;
454         }
455
456         /**
457          *
458          * We should rollback our preparation
459          *
460          */
461         @Override
462         public RpcResult<Void> rollback() throws IllegalStateException {
463             // NOOP - we did not modified any internal state during
464             // requestCommit phase
465             // return Rpcs.getRpcResult(true, null, Collections.emptySet());
466             return Rpcs.getRpcResult(true, null, Collections.<RpcError>emptySet());
467
468         }
469
470     }
471     
472     private RpcResult<Void> commitToPlugin(InternalTransaction transaction) {
473         for (Entry<InstanceIdentifier<?>, Meter> entry : transaction.additions.entrySet()) {
474
475             if (!addMeter(entry.getKey(), entry.getValue()).isSuccess()) {
476                 return Rpcs.getRpcResult(false, null, Collections.<RpcError>emptySet());
477             }
478         }
479         for (Entry<InstanceIdentifier<?>, Meter> entry : transaction.updates.entrySet()) {
480
481             if (!updateMeter(entry.getKey(), entry.getValue()).isSuccess()) {
482                 return Rpcs.getRpcResult(false, null, Collections.<RpcError>emptySet());
483             }
484         }
485
486         for (InstanceIdentifier<?> meterId : transaction.removals) {
487             DataObject removeValue = transaction.getModification().getOriginalConfigurationData().get(meterId); 
488                  
489                  if(removeValue instanceof Meter) {
490                      if(!removeMeter(meterId, (Meter)removeValue).isSuccess()) {
491                          return Rpcs.getRpcResult(false, null, Collections.<RpcError>emptySet());
492                          }
493                  }    
494         }
495
496         return Rpcs.getRpcResult(true, null, Collections.<RpcError>emptySet());
497     }
498
499     private final class MeterDataCommitHandler implements DataCommitHandler<InstanceIdentifier<?>, DataObject> {
500         @Override
501         public org.opendaylight.controller.md.sal.common.api.data.DataCommitHandler.DataCommitTransaction<InstanceIdentifier<?>, DataObject> requestCommit(
502                 DataModification<InstanceIdentifier<?>, DataObject> modification) {
503             // We should verify transaction
504             System.out.println("Coming in MeterDataCommitHandler");
505             InternalTransaction transaction = new InternalTransaction(modification);
506             transaction.prepareUpdate();
507             return transaction;
508         }
509     }
510
511     final class MeterEventListener implements SalMeterListener {
512
513         List<MeterAdded> addedMeter = new ArrayList<>();
514         List<MeterRemoved> removeMeter = new ArrayList<>();
515         List<MeterUpdated> updatedMeter = new ArrayList<>();
516
517         @Override
518         public void onMeterAdded(MeterAdded notification) {
519             // TODO Auto-generated method stub
520
521         }
522
523         @Override
524         public void onMeterRemoved(MeterRemoved notification) {
525             // TODO Auto-generated method stub
526
527         }
528
529         @Override
530         public void onMeterUpdated(MeterUpdated notification) {
531             // TODO Auto-generated method stub
532
533         }
534     }
535
536     @Override
537     public List<DataObject> get() {
538
539         List<DataObject> orderedList = new ArrayList<DataObject>();
540         Collection<Meter> meterList = originalSwMeterView.values();
541         for (Iterator<Meter> iterator = meterList.iterator(); iterator.hasNext();) {
542             orderedList.add(iterator.next());
543         }
544         return orderedList;
545     }
546
547     @Override
548     public DataObject getWithName(String name, Node n) {
549         if (this instanceof MeterConsumerImpl) {
550             Collection<Meter> meterList = originalSwMeterView.values();
551             for (Iterator<Meter> iterator = meterList.iterator(); iterator.hasNext();) {
552                 Meter meter = iterator.next();
553                 if (meter.getNode().equals(n) && meter.getMeterName().equals(name)) {
554
555                     return meter;
556                 }
557             }
558         }
559         return null;
560     }
561 }