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