f4064f22ceeeda56740468d11451da999d6a1a5d
[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 updatedGroupDataObject, Group originalGroupDataObject) {
136         UpdatedGroupBuilder updateGroupBuilder = null;
137         Status groupOperationStatus = validateGroup(updatedGroupDataObject);
138         
139         if (!groupOperationStatus.isSuccess()) {
140             logger.error("Group data object validation failed %s" + updatedGroupDataObject.getGroupName());
141             return;
142         }
143         
144         UpdateGroupInputBuilder groupInputBuilder = new UpdateGroupInputBuilder();        
145         updateGroupBuilder = new UpdatedGroupBuilder(updatedGroupDataObject);        
146         updateGroupBuilder.setGroupId(new GroupId(updatedGroupDataObject.getId())); 
147         groupInputBuilder.setNode(updatedGroupDataObject.getNode());
148         groupInputBuilder.setUpdatedGroup(updateGroupBuilder.build());       
149         OriginalGroupBuilder originalGroupBuilder = new OriginalGroupBuilder(originalGroupDataObject);
150         groupInputBuilder.setOriginalGroup(originalGroupBuilder.build());     
151         groupService.updateGroup(groupInputBuilder.build());
152         return;
153     }
154
155     /**
156      * Adds Group to the southbound plugin and our internal database
157      *
158      * @param path
159      * @param dataObject
160      */
161     private void addGroup(InstanceIdentifier<?> path, Group groupAddDataObject) {
162         GroupKey groupKey = groupAddDataObject.getKey();
163         Status groupOperationStatus = validateGroup(groupAddDataObject);
164
165         if (!groupOperationStatus.isSuccess()) {
166             logger.error("Group data object validation failed %s" + groupAddDataObject.getGroupName());
167             return;
168         }
169         
170         AddGroupInputBuilder groupData = new AddGroupInputBuilder();
171         groupData.fieldsFrom(groupAddDataObject);       
172         groupData.setGroupId(new GroupId(groupAddDataObject.getId()));     
173         groupData.setNode(groupAddDataObject.getNode());    
174         groupService.addGroup(groupData.build());
175         return;
176     }
177
178     /**
179      * Remove Group to the southbound plugin and our internal database
180      *
181      * @param path
182      * @param dataObject
183      */
184     private void removeGroup(InstanceIdentifier<?> path, Group groupRemoveDataObject) {
185         GroupKey groupKey = groupRemoveDataObject.getKey();
186         Status groupOperationStatus = validateGroup(groupRemoveDataObject);
187
188         if (!groupOperationStatus.isSuccess()) {
189             logger.error("Group data object validation failed %s" + groupRemoveDataObject.getGroupName());
190             return;
191         }
192        
193         RemoveGroupInputBuilder groupData = new RemoveGroupInputBuilder();
194         groupData.fieldsFrom(groupRemoveDataObject);
195         groupData.setGroupId(new GroupId(groupRemoveDataObject.getId()));    
196         groupData.setNode(groupRemoveDataObject.getNode());
197         groupService.removeGroup(groupData.build());  
198         return;
199     }
200     
201     private RpcResult<Void> commitToPlugin(InternalTransaction transaction) {
202         DataModification<InstanceIdentifier<?>, DataObject> modification = transaction.modification;         
203         //get created entries      
204         Set<Entry<InstanceIdentifier<? extends DataObject>, DataObject>> createdEntries = 
205                                         modification.getCreatedConfigurationData().entrySet();
206         
207         //get updated entries
208         Set<Entry<InstanceIdentifier<? extends DataObject>, DataObject>> updatedEntries = 
209                     new HashSet<Entry<InstanceIdentifier<? extends DataObject>, DataObject>>(); 
210         
211         updatedEntries.addAll(modification.getUpdatedConfigurationData().entrySet());
212         updatedEntries.removeAll(createdEntries);
213
214         //get removed entries
215         Set<InstanceIdentifier<? extends DataObject>> removeEntriesInstanceIdentifiers = 
216                                                     modification.getRemovedConfigurationData();
217         
218         for (Entry<InstanceIdentifier<? extends DataObject >, DataObject> entry : createdEntries) { 
219             if(entry.getValue() instanceof Group) {   
220                 addGroup(entry.getKey(), (Group)entry.getValue());   
221             }   
222         } 
223         
224         for (Entry<InstanceIdentifier<?>, DataObject> entry : updatedEntries) { 
225             if(entry.getValue() instanceof Group) {   
226                 Group originalGroup = (Group) modification.getOriginalConfigurationData().get(entry.getKey());    
227                 Group updatedGroup = (Group) entry.getValue(); 
228                 updateGroup(entry.getKey(), originalGroup, updatedGroup);   
229             }   
230         }   
231
232         for (InstanceIdentifier<?> instanceId : removeEntriesInstanceIdentifiers ) {    
233             DataObject removeValue = modification.getOriginalConfigurationData().get(instanceId);   
234             if(removeValue instanceof Group) {   
235                 removeGroup(instanceId, (Group)removeValue); 
236             }   
237         }
238
239         return Rpcs.getRpcResult(true, null, Collections.<RpcError>emptySet());
240     }
241
242     private final class GroupDataCommitHandler implements DataCommitHandler<InstanceIdentifier<?>, DataObject> {
243
244         @Override
245         public DataCommitTransaction<InstanceIdentifier<?>, DataObject> requestCommit(
246                 DataModification<InstanceIdentifier<?>, DataObject> modification) {            
247             InternalTransaction transaction = new InternalTransaction(modification);
248             transaction.prepareUpdate();
249             return transaction;
250         }
251     }
252
253     private final class InternalTransaction implements DataCommitTransaction<InstanceIdentifier<?>, DataObject> {      
254
255         private final DataModification<InstanceIdentifier<?>, DataObject> modification;
256         
257         public InternalTransaction(DataModification<InstanceIdentifier<?>, DataObject> modification) {   
258             this.modification = modification;
259         }
260         
261         /**
262          * We create a plan which flows will be added, which will be updated and
263          * which will be removed based on our internal state.
264          *
265          */
266         void prepareUpdate() {
267                 
268         }
269         
270         /**
271          * We are OK to go with execution of plan
272          *
273          */
274         @Override
275         public RpcResult<Void> finish() throws IllegalStateException {
276
277             RpcResult<Void> rpcStatus = commitToPlugin(this);            
278             return rpcStatus;
279         }
280
281         /**
282          *
283          * We should rollback our preparation
284          *
285          */
286         @Override
287         public RpcResult<Void> rollback() throws IllegalStateException { 
288             
289             ///needs to be implemented as per gerrit 3314
290             return Rpcs.getRpcResult(true, null, Collections.<RpcError>emptySet());
291         }
292
293         @Override
294         public DataModification<InstanceIdentifier<?>, DataObject> getModification() {            
295             return modification;
296         }
297
298     }
299
300     final class GroupEventListener implements SalGroupListener {
301
302         List<GroupAdded> addedGroups = new ArrayList<>();
303         List<GroupRemoved> removedGroups = new ArrayList<>();
304         List<GroupUpdated> updatedGroups = new ArrayList<>();
305
306         @Override
307         public void onGroupAdded(GroupAdded notification) {
308             addedGroups.add(notification);
309         }
310
311         @Override
312         public void onGroupRemoved(GroupRemoved notification) {
313             // TODO Auto-generated method stub
314
315         }
316
317         @Override
318         public void onGroupUpdated(GroupUpdated notification) {
319             // TODO Auto-generated method stub
320
321         }
322     }
323  }