Merge "modified group"
[controller.git] / opendaylight / md-sal / forwardingrules-manager / src / main / java / org / opendaylight / controller / forwardingrulesmanager / consumer / impl / GroupConsumerImpl.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.group.config.rev131024.Groups;
31 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.config.rev131024.groups.Group;
32 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.config.rev131024.groups.GroupKey;
33 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.service.rev130918.AddGroupInputBuilder;
34 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.service.rev130918.GroupAdded;
35 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.service.rev130918.GroupRemoved;
36 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.service.rev130918.GroupUpdated;
37 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.service.rev130918.RemoveGroupInputBuilder;
38 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.service.rev130918.SalGroupListener;
39 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.service.rev130918.SalGroupService;
40 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.service.rev130918.UpdateGroupInputBuilder;
41 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.service.rev130918.group.update.OriginalGroupBuilder;
42 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.service.rev130918.group.update.UpdatedGroupBuilder;
43 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.GroupId;
44 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.GroupTypes;
45 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.group.Buckets;
46 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.group.buckets.Bucket;
47 import org.opendaylight.yangtools.concepts.Registration;
48 import org.opendaylight.yangtools.yang.binding.DataObject;
49 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
50 import org.opendaylight.yangtools.yang.binding.NotificationListener;
51 import org.opendaylight.yangtools.yang.common.RpcError;
52 import org.opendaylight.yangtools.yang.common.RpcResult;
53 import org.slf4j.Logger;
54 import org.slf4j.LoggerFactory;
55
56 @SuppressWarnings("unused")
57 public class GroupConsumerImpl {
58
59     protected static final Logger logger = LoggerFactory.getLogger(GroupConsumerImpl.class);
60     private final GroupEventListener groupEventListener = new GroupEventListener();
61     private Registration<NotificationListener> groupListener;
62     private SalGroupService groupService;
63     private GroupDataCommitHandler groupCommitHandler;
64
65     private IContainer container;
66
67     public GroupConsumerImpl() {
68
69         InstanceIdentifier<? extends DataObject> path = InstanceIdentifier.builder(Groups.class).toInstance();
70         groupService = FRMConsumerImpl.getProviderSession().getRpcService(SalGroupService.class);      
71
72         if (null == groupService) {
73             logger.error("Consumer SAL Group Service is down or NULL. FRM may not function as intended");
74             System.out.println("Consumer SAL Group Service is down or NULL.");
75             return;
76         }
77
78         // For switch events
79         groupListener = FRMConsumerImpl.getNotificationService().registerNotificationListener(groupEventListener);
80
81         if (null == groupListener) {
82             logger.error("Listener to listen on group data modifcation events");
83             System.out.println("Listener to listen on group data modifcation events.");
84             return;
85         }
86
87         groupCommitHandler = new GroupDataCommitHandler();
88         FRMConsumerImpl.getDataProviderService().registerCommitHandler(path, groupCommitHandler);
89     }  
90
91     public Status validateGroup(Group group) {        
92         String groupName;
93         Iterator<Bucket> bucketIterator;
94         boolean returnResult;
95         Buckets groupBuckets;
96
97         if (null != group) {   
98             groupName = group.getGroupName();
99             if (!FRMUtil.isNameValid(groupName)) {
100                 logger.error("Group Name is invalid %s" + groupName);
101                 return new Status(StatusCode.BADREQUEST, "Group Name is invalid");
102             }
103             
104             if (!(group.getGroupType().getIntValue() >= GroupTypes.GroupAll.getIntValue() && group.getGroupType()
105                     .getIntValue() <= GroupTypes.GroupFf.getIntValue())) {
106                 logger.error("Invalid Group type %d" + group.getGroupType().getIntValue());
107                 return new Status(StatusCode.BADREQUEST, "Invalid Group type");
108             }
109
110             groupBuckets = group.getBuckets();
111
112             if (null != groupBuckets && null != groupBuckets.getBucket()) {
113                 bucketIterator = groupBuckets.getBucket().iterator();
114
115                 while (bucketIterator.hasNext()) {
116                     if (!(FRMUtil.validateActions(bucketIterator.next().getAction()))) {
117                         logger.error("Error in action bucket");
118                         return new Status(StatusCode.BADREQUEST, "Invalid Group bucket contents");
119                     }
120                 }
121             }
122         }
123
124         return new Status(StatusCode.SUCCESS);
125     }
126
127     /**
128      * Update Group entries to the southbound plugin/inventory and our internal
129      * database
130      *
131      * @param path
132      * @param dataObject
133      */
134     private void updateGroup(InstanceIdentifier<?> path, 
135         Group originalGroupDataObject, Group updatedGroupDataObject) {
136         
137         GroupKey groupKey = updatedGroupDataObject.getKey();
138        // Node nodeInstanceID = path.firstIdentifierOf("Node");
139         UpdatedGroupBuilder updateGroupBuilder = null;
140         Status groupOperationStatus = validateGroup(updatedGroupDataObject);
141
142         if (!groupOperationStatus.isSuccess()) {
143             logger.error("Group data object validation failed %s" + updatedGroupDataObject.getGroupName());
144             return;
145         }
146         
147         UpdateGroupInputBuilder groupInputBuilder = new UpdateGroupInputBuilder();
148         groupInputBuilder.setNode(updatedGroupDataObject.getNode());
149         updateGroupBuilder = new UpdatedGroupBuilder(updatedGroupDataObject);
150         updateGroupBuilder.setGroupId(new GroupId(updatedGroupDataObject.getId()));        
151         groupInputBuilder.setUpdatedGroup(updateGroupBuilder.build());       
152         OriginalGroupBuilder originalGroupBuilder = new OriginalGroupBuilder(originalGroupDataObject);
153         groupInputBuilder.setOriginalGroup(originalGroupBuilder.build());
154         groupService.updateGroup(groupInputBuilder.build());
155         return;
156     }
157
158     /**
159      * Adds Group to the southbound plugin and our internal database
160      *
161      * @param path
162      * @param dataObject
163      */
164     private void addGroup(InstanceIdentifier<?> path, Group groupAddDataObject) {
165         GroupKey groupKey = groupAddDataObject.getKey();
166         Status groupOperationStatus = validateGroup(groupAddDataObject);
167
168         if (!groupOperationStatus.isSuccess()) {
169             logger.error("Group data object validation failed %s" + groupAddDataObject.getGroupName());
170             return;
171         }
172         
173         AddGroupInputBuilder groupData = new AddGroupInputBuilder();
174         groupData.setBuckets(groupAddDataObject.getBuckets());
175         groupData.setContainerName(groupAddDataObject.getContainerName());
176         groupData.setGroupId(new GroupId(groupAddDataObject.getId()));
177         groupData.setGroupType(groupAddDataObject.getGroupType());
178         groupData.setNode(groupAddDataObject.getNode());    
179         groupService.addGroup(groupData.build());
180         return;
181     }
182
183     /**
184      * Remove Group to the southbound plugin and our internal database
185      *
186      * @param path
187      * @param dataObject
188      */
189     private void removeGroup(InstanceIdentifier<?> path, Group groupRemoveDataObject) {
190         GroupKey groupKey = groupRemoveDataObject.getKey();
191         Status groupOperationStatus = validateGroup(groupRemoveDataObject);
192
193         if (!groupOperationStatus.isSuccess()) {
194             logger.error("Group data object validation failed %s" + groupRemoveDataObject.getGroupName());
195             return;
196         }
197        
198         RemoveGroupInputBuilder groupData = new RemoveGroupInputBuilder();
199         groupData.setBuckets(groupRemoveDataObject.getBuckets());
200         groupData.setContainerName(groupRemoveDataObject.getContainerName());
201         groupData.setGroupId(new GroupId(groupRemoveDataObject.getId()));
202         groupData.setGroupType(groupRemoveDataObject.getGroupType());
203         groupData.setNode(groupRemoveDataObject.getNode());    
204         groupService.removeGroup(groupData.build());  
205         return;
206     }
207     
208     private RpcResult<Void> commitToPlugin(InternalTransaction transaction) {
209         DataModification<InstanceIdentifier<?>, DataObject> modification = transaction.modification;         
210         //get created entries      
211         Set<Entry<InstanceIdentifier<? extends DataObject>, DataObject>> createdEntries = 
212                                         modification.getCreatedConfigurationData().entrySet();
213         
214         //get updated entries
215         Set<Entry<InstanceIdentifier<? extends DataObject>, DataObject>> updatedEntries = 
216                     new HashSet<Entry<InstanceIdentifier<? extends DataObject>, DataObject>>(); 
217         
218         updatedEntries.addAll(modification.getUpdatedConfigurationData().entrySet());
219         updatedEntries.removeAll(createdEntries);
220
221         //get removed entries
222         Set<InstanceIdentifier<? extends DataObject>> removeEntriesInstanceIdentifiers = 
223                                                     modification.getRemovedConfigurationData();
224         
225         for (Entry<InstanceIdentifier<? extends DataObject >, DataObject> entry : createdEntries) { 
226             if(entry.getValue() instanceof Group) {   
227                 addGroup(entry.getKey(), (Group)entry.getValue());   
228             }   
229         } 
230         
231         for (Entry<InstanceIdentifier<?>, DataObject> entry : updatedEntries) { 
232             if(entry.getValue() instanceof Group) {   
233                 Group originalGroup = (Group) modification.getOriginalConfigurationData().get(entry.getKey());    
234                 Group updatedGroup = (Group) entry.getValue(); 
235                 updateGroup(entry.getKey(), originalGroup, updatedGroup);   
236             }   
237         }   
238
239         for (InstanceIdentifier<?> instanceId : removeEntriesInstanceIdentifiers ) {    
240             DataObject removeValue = modification.getOriginalConfigurationData().get(instanceId);   
241             if(removeValue instanceof Group) {   
242                 removeGroup(instanceId, (Group)removeValue); 
243             }   
244         }
245
246         return Rpcs.getRpcResult(true, null, Collections.<RpcError>emptySet());
247     }
248
249     private final class GroupDataCommitHandler implements DataCommitHandler<InstanceIdentifier<?>, DataObject> {
250
251         @Override
252         public DataCommitTransaction<InstanceIdentifier<?>, DataObject> requestCommit(
253                 DataModification<InstanceIdentifier<?>, DataObject> modification) {            
254             InternalTransaction transaction = new InternalTransaction(modification);
255             transaction.prepareUpdate();
256             return transaction;
257         }
258     }
259
260     private final class InternalTransaction implements DataCommitTransaction<InstanceIdentifier<?>, DataObject> {      
261
262         private final DataModification<InstanceIdentifier<?>, DataObject> modification;
263         
264         public InternalTransaction(DataModification<InstanceIdentifier<?>, DataObject> modification) {   
265             this.modification = modification;
266         }
267         
268         /**
269          * We create a plan which flows will be added, which will be updated and
270          * which will be removed based on our internal state.
271          *
272          */
273         void prepareUpdate() {
274                 
275         }
276         
277         /**
278          * We are OK to go with execution of plan
279          *
280          */
281         @Override
282         public RpcResult<Void> finish() throws IllegalStateException {
283
284             RpcResult<Void> rpcStatus = commitToPlugin(this);            
285             return rpcStatus;
286         }
287
288         /**
289          *
290          * We should rollback our preparation
291          *
292          */
293         @Override
294         public RpcResult<Void> rollback() throws IllegalStateException { 
295             
296             ///needs to be implemented as per gerrit 3314
297             return Rpcs.getRpcResult(true, null, Collections.<RpcError>emptySet());
298         }
299
300         @Override
301         public DataModification<InstanceIdentifier<?>, DataObject> getModification() {            
302             return modification;
303         }
304
305     }
306
307     final class GroupEventListener implements SalGroupListener {
308
309         List<GroupAdded> addedGroups = new ArrayList<>();
310         List<GroupRemoved> removedGroups = new ArrayList<>();
311         List<GroupUpdated> updatedGroups = new ArrayList<>();
312
313         @Override
314         public void onGroupAdded(GroupAdded notification) {
315             addedGroups.add(notification);
316         }
317
318         @Override
319         public void onGroupRemoved(GroupRemoved notification) {
320             // TODO Auto-generated method stub
321
322         }
323
324         @Override
325         public void onGroupUpdated(GroupUpdated notification) {
326             // TODO Auto-generated method stub
327
328         }
329     }
330  }