Revert commit bedd505.
[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.flow.service.rev130819.UpdateFlowInputBuilder;
31 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.flow.update.OriginalFlowBuilder;
32 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.flow.update.UpdatedFlowBuilder;
33 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.service.rev130918.UpdateGroupInputBuilder;
34 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.service.rev130918.group.update.OriginalGroupBuilder;
35 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.service.rev130918.group.update.UpdatedGroupBuilder;
36 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.GroupId;
37 import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.config.rev131024.Meters;
38 import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.config.rev131024.meters.Meter;
39 import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.config.rev131024.meters.MeterKey;
40 import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.service.rev130918.AddMeterInputBuilder;
41 import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.service.rev130918.MeterAdded;
42 import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.service.rev130918.MeterRemoved;
43 import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.service.rev130918.MeterUpdated;
44 import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.service.rev130918.RemoveMeterInputBuilder;
45 import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.service.rev130918.SalMeterListener;
46 import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.service.rev130918.SalMeterService;
47 import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.service.rev130918.UpdateMeterInputBuilder;
48 import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.service.rev130918.meter.update.OriginalMeterBuilder;
49 import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.service.rev130918.meter.update.UpdatedMeterBuilder;
50 import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.types.rev130918.MeterId;
51 import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.types.rev130918.band.type.BandType;
52 import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.types.rev130918.band.type.band.type.Drop;
53 import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.types.rev130918.band.type.band.type.DscpRemark;
54 import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.types.rev130918.band.type.band.type.Experimenter;
55 import org.opendaylight.yangtools.concepts.Registration;
56 import org.opendaylight.yangtools.yang.binding.DataObject;
57 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
58 import org.opendaylight.yangtools.yang.binding.NotificationListener;
59 import org.opendaylight.yangtools.yang.common.RpcError;
60 import org.opendaylight.yangtools.yang.common.RpcResult;
61 import org.slf4j.Logger;
62 import org.slf4j.LoggerFactory;
63
64 public class MeterConsumerImpl {
65     protected static final Logger logger = LoggerFactory.getLogger(MeterConsumerImpl.class);
66     private final MeterEventListener meterEventListener = new MeterEventListener();
67     private Registration<NotificationListener> meterListener;
68     private SalMeterService meterService;
69     private MeterDataCommitHandler commitHandler;
70
71     public MeterConsumerImpl() {
72         InstanceIdentifier<? extends DataObject> path = InstanceIdentifier.builder(Meters.class).toInstance();
73         meterService = FRMConsumerImpl.getProviderSession().getRpcService(SalMeterService.class);
74         
75         if (null == meterService) {
76             logger.error("Consumer SAL Meter Service is down or NULL. FRM may not function as intended");
77             System.out.println("Consumer SAL Meter Service is down or NULL.");
78             return;
79         }
80
81         // For switch/plugin events
82         meterListener = FRMConsumerImpl.getNotificationService().registerNotificationListener(meterEventListener);
83
84         if (null == meterListener) {
85             logger.error("Listener to listen on meter data modifcation events");
86             System.out.println("Listener to listen on meter data modifcation events.");
87             return;
88         }
89
90         commitHandler = new MeterDataCommitHandler();
91         FRMConsumerImpl.getDataProviderService().registerCommitHandler(path, commitHandler);
92     }
93     
94     /**
95      * Adds Meter to the southbound plugin and our internal database
96      *
97      * @param path
98      * @param dataObject
99      */
100     private Status addMeter(InstanceIdentifier<?> path, Meter meterAddDataObject) {
101         MeterKey meterKey = meterAddDataObject.getKey();
102         
103         if (null != meterKey && validateMeter(meterAddDataObject).isSuccess()) {                 
104             AddMeterInputBuilder meterBuilder = new AddMeterInputBuilder();
105             meterBuilder.fieldsFrom(meterAddDataObject);            
106             meterBuilder.setMeterId(new MeterId(meterAddDataObject.getId()));
107             meterBuilder.setNode(meterAddDataObject.getNode());           
108             meterService.addMeter(meterBuilder.build());
109         } else {        
110             return new Status(StatusCode.BADREQUEST, "Meter Key or attribute validation failed");
111         }
112
113         return new Status(StatusCode.SUCCESS);
114     }
115
116     /*
117      * Update Meter to the southbound plugin and our internal database
118      *
119      * @param path
120      *
121      * @param dataObject
122      */
123     private Status updateMeter(InstanceIdentifier<?> path, 
124                 Meter updatedMeter, Meter originalMeter) {        
125         UpdatedMeterBuilder updateMeterBuilder = null;
126         
127         if (validateMeter(updatedMeter).isSuccess()) {                
128             UpdateMeterInputBuilder updateMeterInputBuilder = new UpdateMeterInputBuilder();
129             updateMeterInputBuilder.setNode(updatedMeter.getNode());
130             updateMeterBuilder = new UpdatedMeterBuilder();
131             updateMeterBuilder.fieldsFrom(updatedMeter);            
132             updateMeterBuilder.setMeterId(new MeterId(updatedMeter.getId()));            
133             updateMeterInputBuilder.setUpdatedMeter(updateMeterBuilder.build());
134             OriginalMeterBuilder originalMeterBuilder = new OriginalMeterBuilder(originalMeter);
135             updateMeterInputBuilder.setOriginalMeter(originalMeterBuilder.build());
136             meterService.updateMeter(updateMeterInputBuilder.build());
137         } else {
138             return new Status(StatusCode.BADREQUEST, "Meter Key or attribute validation failed");
139         }
140
141         return new Status(StatusCode.SUCCESS);
142     }
143
144     /*
145      * Remove Meter to the southbound plugin and our internal database
146      *
147      * @param path
148      *
149      * @param dataObject
150      */
151     private Status removeMeter(InstanceIdentifier<?> path, Meter meterRemoveDataObject) {
152         MeterKey meterKey = meterRemoveDataObject.getKey();
153
154         if (null != meterKey && validateMeter(meterRemoveDataObject).isSuccess()) {            
155             RemoveMeterInputBuilder meterBuilder = new RemoveMeterInputBuilder();
156             meterBuilder.fieldsFrom(meterRemoveDataObject);
157             meterBuilder.setNode(meterRemoveDataObject.getNode());            
158             meterBuilder.setMeterId(new MeterId(meterRemoveDataObject.getId()));           
159             meterService.removeMeter(meterBuilder.build());
160         } else {
161             return new Status(StatusCode.BADREQUEST, "Meter Key or attribute validation failed");
162         }
163
164         return new Status(StatusCode.SUCCESS);
165     }
166
167     public Status validateMeter(Meter meter) {        
168         String meterName;
169         Status returnStatus = null;
170
171         if (null != meter) {
172             meterName = meter.getMeterName();
173             if (!FRMUtil.isNameValid(meterName)) {
174                 logger.error("Meter Name is invalid %s" + meterName);
175                 returnStatus = new Status(StatusCode.BADREQUEST, "Meter Name is invalid");
176                 return returnStatus;
177             }
178
179             for (int i = 0; i < meter.getMeterBandHeaders().getMeterBandHeader().size(); i++) {
180                 if (null != meter.getFlags() && !meter.getFlags().isMeterBurst()) {
181                     if (0 < meter.getMeterBandHeaders().getMeterBandHeader().get(i).getBurstSize()) {
182                         logger.error("Burst size should only be associated when Burst FLAG is set");
183                         returnStatus = new Status(StatusCode.BADREQUEST,
184                                 "Burst size should only be associated when Burst FLAG is set");
185                         break;
186                     }
187                 }
188             }
189
190             if (null != returnStatus && !returnStatus.isSuccess()) {
191                 return returnStatus;
192             } else if (null != meter.getMeterBandHeaders()) {
193                 BandType setBandType = null;
194                 DscpRemark dscpRemark = null;
195                 for (int i = 0; i < meter.getMeterBandHeaders().getMeterBandHeader().size(); i++) {
196                     setBandType = meter.getMeterBandHeaders().getMeterBandHeader().get(i).getBandType();
197                     if (setBandType instanceof DscpRemark) {
198                         dscpRemark = (DscpRemark) setBandType;
199                         if (0 > dscpRemark.getRate()) {
200
201                         }
202                     } else if (setBandType instanceof Drop) {
203                         if (0 < dscpRemark.getPercLevel()) {
204                             logger.error("Number of drop Precedence level");
205                         }
206                     } else if (setBandType instanceof Experimenter) {
207
208                     }
209                 }
210             }
211         }
212         return new Status(StatusCode.SUCCESS);
213     }
214
215     private RpcResult<Void> commitToPlugin(InternalTransaction transaction) {
216         DataModification<InstanceIdentifier<?>, DataObject> modification = transaction.modification;         
217         //get created entries      
218         Set<Entry<InstanceIdentifier<? extends DataObject>, DataObject>> createdEntries = 
219                                         modification.getCreatedConfigurationData().entrySet();
220         
221         //get updated entries
222         Set<Entry<InstanceIdentifier<? extends DataObject>, DataObject>> updatedEntries = 
223                     new HashSet<Entry<InstanceIdentifier<? extends DataObject>, DataObject>>(); 
224         
225         updatedEntries.addAll(modification.getUpdatedConfigurationData().entrySet());
226         updatedEntries.removeAll(createdEntries);
227
228         //get removed entries
229         Set<InstanceIdentifier<? extends DataObject>> removeEntriesInstanceIdentifiers = 
230                                                     modification.getRemovedConfigurationData();
231         
232         for (Entry<InstanceIdentifier<? extends DataObject >, DataObject> entry : createdEntries) { 
233             if(entry.getValue() instanceof Meter) {   
234                 addMeter(entry.getKey(), (Meter)entry.getValue());   
235             }   
236         } 
237         
238         for (Entry<InstanceIdentifier<?>, DataObject> entry : updatedEntries) { 
239             if(entry.getValue() instanceof Meter) {   
240                 Meter originalMeter = (Meter) modification.getOriginalConfigurationData().get(entry.getKey());    
241                 Meter updatedMeter = (Meter) entry.getValue(); 
242                 updateMeter(entry.getKey(), originalMeter, updatedMeter);   
243             }   
244         }   
245
246         for (InstanceIdentifier<?> instanceId : removeEntriesInstanceIdentifiers ) {    
247             DataObject removeValue = modification.getOriginalConfigurationData().get(instanceId);   
248             if(removeValue instanceof Meter) {   
249                 removeMeter(instanceId, (Meter)removeValue); 
250             }   
251         }
252
253         return Rpcs.getRpcResult(true, null, Collections.<RpcError>emptySet());
254     }
255     
256     final class InternalTransaction implements DataCommitTransaction<InstanceIdentifier<?>, DataObject> {
257
258         private final DataModification<InstanceIdentifier<?>, DataObject> modification;
259
260         @Override
261         public DataModification<InstanceIdentifier<?>, DataObject> getModification() {
262             return modification;
263         }
264
265         public InternalTransaction(DataModification<InstanceIdentifier<?>, DataObject> modification) {
266             this.modification = modification;
267         }
268
269         /**
270          * We create a plan which flows will be added, which will be updated and
271          * which will be removed based on our internal state.
272          *
273          */
274         void prepareUpdate() {           
275             
276         }
277
278         /**
279          * We are OK to go with execution of plan
280          *
281          */
282         @Override
283         public RpcResult<Void> finish() throws IllegalStateException {
284
285             RpcResult<Void> rpcStatus = commitToPlugin(this);           
286             return rpcStatus;
287         }
288
289         /**
290          *
291          * We should rollback our preparation
292          *
293          */
294         @Override
295         public RpcResult<Void> rollback() throws IllegalStateException {            
296             return Rpcs.getRpcResult(true, null, Collections.<RpcError>emptySet());
297
298         }
299
300     }
301     
302     private final class MeterDataCommitHandler implements DataCommitHandler<InstanceIdentifier<?>, DataObject> {
303         @Override
304         public org.opendaylight.controller.md.sal.common.api.data.DataCommitHandler.DataCommitTransaction<InstanceIdentifier<?>, DataObject> requestCommit(
305                 DataModification<InstanceIdentifier<?>, DataObject> modification) {
306             // We should verify transaction
307             InternalTransaction transaction = new InternalTransaction(modification);
308             transaction.prepareUpdate();
309             return transaction;
310         }
311     }
312
313     final class MeterEventListener implements SalMeterListener {
314
315         List<MeterAdded> addedMeter = new ArrayList<>();
316         List<MeterRemoved> removeMeter = new ArrayList<>();
317         List<MeterUpdated> updatedMeter = new ArrayList<>();
318
319         @Override
320         public void onMeterAdded(MeterAdded notification) {
321             // TODO Auto-generated method stub
322
323         }
324
325         @Override
326         public void onMeterRemoved(MeterRemoved notification) {
327             // TODO Auto-generated method stub
328
329         }
330
331         @Override
332         public void onMeterUpdated(MeterUpdated notification) {
333             // TODO Auto-generated method stub
334
335         }
336     }   
337 }