1 package org.opendaylight.controller.forwardingrulesmanager.consumer.impl;
3 import java.util.ArrayList;
4 import java.util.Collection;
5 import java.util.EnumSet;
6 import java.util.HashMap;
7 import java.util.HashSet;
8 import java.util.Iterator;
11 import java.util.Map.Entry;
13 import java.util.concurrent.ConcurrentHashMap;
14 import java.util.concurrent.ConcurrentMap;
16 import org.opendaylight.controller.clustering.services.CacheConfigException;
17 import org.opendaylight.controller.clustering.services.CacheExistException;
18 import org.opendaylight.controller.clustering.services.IClusterContainerServices;
19 import org.opendaylight.controller.clustering.services.IClusterServices;
20 import org.opendaylight.controller.md.sal.common.api.data.DataCommitHandler;
21 import org.opendaylight.controller.md.sal.common.api.data.DataCommitHandler.DataCommitTransaction;
22 import org.opendaylight.controller.md.sal.common.api.data.DataModification;
23 import org.opendaylight.controller.sal.common.util.Rpcs;
24 import org.opendaylight.controller.sal.core.IContainer;
25 import org.opendaylight.controller.sal.core.Node;
26 import org.opendaylight.controller.sal.utils.GlobalConstants;
27 import org.opendaylight.controller.sal.utils.Status;
28 import org.opendaylight.controller.sal.utils.StatusCode;
29 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.config.rev131024.Groups;
30 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.config.rev131024.groups.Group;
31 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.config.rev131024.groups.GroupKey;
32 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.service.rev130918.AddGroupInputBuilder;
33 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.service.rev130918.GroupAdded;
34 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.service.rev130918.GroupRemoved;
35 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.service.rev130918.GroupUpdated;
36 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.service.rev130918.SalGroupListener;
37 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.service.rev130918.SalGroupService;
38 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.service.rev130918.UpdateGroupInputBuilder;
39 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.service.rev130918.group.update.UpdatedGroupBuilder;
40 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.GroupTypes.GroupType;
41 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.group.Buckets;
42 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.group.buckets.Bucket;
43 import org.opendaylight.yangtools.concepts.Registration;
44 import org.opendaylight.yangtools.yang.binding.DataObject;
45 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
46 import org.opendaylight.yangtools.yang.binding.NotificationListener;
47 import org.opendaylight.yangtools.yang.common.RpcResult;
48 import org.slf4j.Logger;
49 import org.slf4j.LoggerFactory;
51 @SuppressWarnings("unused")
52 public class GroupConsumerImpl implements IForwardingRulesManager {
54 protected static final Logger logger = LoggerFactory.getLogger(GroupConsumerImpl.class);
55 private final GroupEventListener groupEventListener = new GroupEventListener();
56 private Registration<NotificationListener> groupListener;
57 private SalGroupService groupService;
58 private GroupDataCommitHandler commitHandler;
60 private ConcurrentMap<GroupKey, Group> originalSwGroupView;
61 private ConcurrentMap<GroupKey, Group> installedSwGroupView;
63 private ConcurrentMap<Node, List<Group>> nodeGroups;
64 private ConcurrentMap<GroupKey, Group> inactiveGroups;
66 private IClusterContainerServices clusterGroupContainerService = null;
67 private IContainer container;
69 public GroupConsumerImpl() {
71 InstanceIdentifier<? extends DataObject> path = InstanceIdentifier.builder(Groups.class).child(Group.class)
73 groupService = FRMConsumerImpl.getProviderSession().getRpcService(SalGroupService.class);
75 clusterGroupContainerService = FRMConsumerImpl.getClusterContainerService();
76 container = FRMConsumerImpl.getContainer();
78 if (!(cacheStartup())) {
79 logger.error("Unanle to allocate/retrieve group cache");
80 System.out.println("Unable to allocate/retrieve group cache");
83 if (null == groupService) {
84 logger.error("Consumer SAL Group Service is down or NULL. FRM may not function as intended");
85 System.out.println("Consumer SAL Group Service is down or NULL.");
90 groupListener = FRMConsumerImpl.getNotificationService().registerNotificationListener(groupEventListener);
92 if (null == groupListener) {
93 logger.error("Listener to listen on group data modifcation events");
94 System.out.println("Listener to listen on group data modifcation events.");
98 commitHandler = new GroupDataCommitHandler();
99 FRMConsumerImpl.getDataProviderService().registerCommitHandler(path, commitHandler);
102 private boolean allocateGroupCaches() {
103 if (this.clusterGroupContainerService == null) {
104 logger.warn("Group: Un-initialized clusterGroupContainerService, can't create cache");
109 clusterGroupContainerService.createCache("frm.originalSwGroupView",
110 EnumSet.of(IClusterServices.cacheMode.TRANSACTIONAL));
112 clusterGroupContainerService.createCache("frm.installedSwGroupView",
113 EnumSet.of(IClusterServices.cacheMode.TRANSACTIONAL));
115 clusterGroupContainerService.createCache("frm.inactiveGroups",
116 EnumSet.of(IClusterServices.cacheMode.TRANSACTIONAL));
118 clusterGroupContainerService.createCache("frm.nodeGroups",
119 EnumSet.of(IClusterServices.cacheMode.TRANSACTIONAL));
121 // TODO for cluster mode
123 * clusterGroupContainerService.createCache(WORK_STATUS_CACHE,
124 * EnumSet.of(IClusterServices.cacheMode.NON_TRANSACTIONAL,
125 * IClusterServices.cacheMode.ASYNC));
127 * clusterGroupContainerService.createCache(WORK_ORDER_CACHE,
128 * EnumSet.of(IClusterServices.cacheMode.NON_TRANSACTIONAL,
129 * IClusterServices.cacheMode.ASYNC));
132 } catch (CacheConfigException cce) {
133 logger.error("Group CacheConfigException");
136 } catch (CacheExistException cce) {
137 logger.error(" Group CacheExistException");
143 private void nonClusterGroupObjectCreate() {
144 originalSwGroupView = new ConcurrentHashMap<GroupKey, Group>();
145 installedSwGroupView = new ConcurrentHashMap<GroupKey, Group>();
146 nodeGroups = new ConcurrentHashMap<Node, List<Group>>();
147 inactiveGroups = new ConcurrentHashMap<GroupKey, Group>();
150 @SuppressWarnings({ "unchecked" })
151 private boolean retrieveGroupCaches() {
152 ConcurrentMap<?, ?> map;
154 if (this.clusterGroupContainerService == null) {
155 logger.warn("Group: un-initialized clusterGroupContainerService, can't retrieve cache");
156 nonClusterGroupObjectCreate();
160 map = clusterGroupContainerService.getCache("frm.originalSwGroupView");
162 originalSwGroupView = (ConcurrentMap<GroupKey, Group>) map;
164 logger.error("Retrieval of cache(originalSwGroupView) failed");
168 map = clusterGroupContainerService.getCache("frm.installedSwGroupView");
170 installedSwGroupView = (ConcurrentMap<GroupKey, Group>) map;
172 logger.error("Retrieval of cache(installedSwGroupView) failed");
176 map = clusterGroupContainerService.getCache("frm.inactiveGroups");
178 inactiveGroups = (ConcurrentMap<GroupKey, Group>) map;
180 logger.error("Retrieval of cache(inactiveGroups) failed");
184 map = clusterGroupContainerService.getCache("frm.nodeGroups");
186 nodeGroups = (ConcurrentMap<Node, List<Group>>) map;
188 logger.error("Retrieval of cache(nodeGroup) failed");
195 private boolean cacheStartup() {
196 if (allocateGroupCaches()) {
197 if (retrieveGroupCaches()) {
205 public Status validateGroup(Group group, FRMUtil.operation operation) {
206 String containerName;
208 Iterator<Bucket> bucketIterator;
209 boolean returnResult;
210 Buckets groupBuckets;
213 containerName = group.getContainerName();
215 if (null == containerName) {
216 containerName = GlobalConstants.DEFAULT.toString();
217 } else if (!FRMUtil.isNameValid(containerName)) {
218 logger.error("Container Name is invalid %s" + containerName);
219 return new Status(StatusCode.BADREQUEST, "Container Name is invalid");
222 groupName = group.getGroupName();
223 if (!FRMUtil.isNameValid(groupName)) {
224 logger.error("Group Name is invalid %s" + groupName);
225 return new Status(StatusCode.BADREQUEST, "Group Name is invalid");
228 returnResult = doesGroupEntryExists(group.getKey(), groupName, containerName);
230 if (FRMUtil.operation.ADD == operation && returnResult) {
231 logger.error("Record with same Group Name exists");
232 return new Status(StatusCode.BADREQUEST, "Group record exists");
233 } else if (!returnResult) {
234 logger.error("Group record does not exist");
235 return new Status(StatusCode.BADREQUEST, "Group record does not exist");
238 if (!(group.getGroupType().getIntValue() >= GroupType.GroupAll.getIntValue() && group.getGroupType()
239 .getIntValue() <= GroupType.GroupFf.getIntValue())) {
240 logger.error("Invalid Group type %d" + group.getGroupType().getIntValue());
241 return new Status(StatusCode.BADREQUEST, "Invalid Group type");
244 groupBuckets = group.getBuckets();
246 if (null != groupBuckets && null != groupBuckets.getBucket()) {
247 bucketIterator = groupBuckets.getBucket().iterator();
249 while (bucketIterator.hasNext()) {
250 if (!(FRMUtil.validateActions(bucketIterator.next().getAction()))) {
251 logger.error("Error in action bucket");
252 return new Status(StatusCode.BADREQUEST, "Invalid Group bucket contents");
258 return new Status(StatusCode.SUCCESS);
262 private boolean doesGroupEntryExists(GroupKey key, String groupName, String containerName) {
263 if (!originalSwGroupView.containsKey(key)) {
267 for (ConcurrentMap.Entry<GroupKey, Group> entry : originalSwGroupView.entrySet()) {
268 if (entry.getValue().getGroupName().equals(groupName)) {
269 if (entry.getValue().getContainerName().equals(containerName)) {
278 * Update Group entries to the southbound plugin/inventory and our internal
284 private Status updateGroup(InstanceIdentifier<?> path, Group groupUpdateDataObject) {
285 GroupKey groupKey = groupUpdateDataObject.getKey();
286 UpdatedGroupBuilder updateGroupBuilder = null;
288 Status groupOperationStatus = validateGroup(groupUpdateDataObject, FRMUtil.operation.UPDATE);
290 if (!groupOperationStatus.isSuccess()) {
291 logger.error("Group data object validation failed %s" + groupUpdateDataObject.getGroupName());
292 return groupOperationStatus;
295 if (originalSwGroupView.containsKey(groupKey)) {
296 originalSwGroupView.remove(groupKey);
297 originalSwGroupView.put(groupKey, groupUpdateDataObject);
300 if (groupUpdateDataObject.isInstall()) {
301 UpdateGroupInputBuilder groupData = new UpdateGroupInputBuilder();
302 updateGroupBuilder = new UpdatedGroupBuilder();
303 updateGroupBuilder.fieldsFrom(groupUpdateDataObject);
304 groupData.setUpdatedGroup(updateGroupBuilder.build());
305 // TODO how to get original group and modified group.
307 if (installedSwGroupView.containsKey(groupKey)) {
308 installedSwGroupView.remove(groupKey);
309 installedSwGroupView.put(groupKey, groupUpdateDataObject);
312 groupService.updateGroup(groupData.build());
315 return groupOperationStatus;
319 * Adds Group to the southbound plugin and our internal database
324 private Status addGroup(InstanceIdentifier<?> path, Group groupAddDataObject) {
325 GroupKey groupKey = groupAddDataObject.getKey();
326 Status groupOperationStatus = validateGroup(groupAddDataObject, FRMUtil.operation.ADD);
328 if (!groupOperationStatus.isSuccess()) {
329 logger.error("Group data object validation failed %s" + groupAddDataObject.getGroupName());
330 return groupOperationStatus;
333 originalSwGroupView.put(groupKey, groupAddDataObject);
335 if (groupAddDataObject.isInstall()) {
336 AddGroupInputBuilder groupData = new AddGroupInputBuilder();
337 groupData.setBuckets(groupAddDataObject.getBuckets());
338 groupData.setContainerName(groupAddDataObject.getContainerName());
339 groupData.setGroupId(groupAddDataObject.getGroupId());
340 groupData.setGroupType(groupAddDataObject.getGroupType());
341 groupData.setNode(groupAddDataObject.getNode());
342 installedSwGroupView.put(groupKey, groupAddDataObject);
343 groupService.addGroup(groupData.build());
346 return groupOperationStatus;
349 private RpcResult<Void> commitToPlugin(internalTransaction transaction) {
350 for (Entry<InstanceIdentifier<?>, Group> entry : transaction.additions.entrySet()) {
352 if (!addGroup(entry.getKey(), entry.getValue()).isSuccess()) {
353 transaction.additions.remove(entry.getKey());
354 return Rpcs.getRpcResult(false, null, null);
358 for (Entry<InstanceIdentifier<?>, Group> entry : transaction.updates.entrySet()) {
360 if (!updateGroup(entry.getKey(), entry.getValue()).isSuccess()) {
361 transaction.updates.remove(entry.getKey());
362 return Rpcs.getRpcResult(false, null, null);
366 for (InstanceIdentifier<?> removal : transaction.removals) {
367 // removeFlow(removal);
370 return Rpcs.getRpcResult(true, null, null);
373 private final class GroupDataCommitHandler implements DataCommitHandler<InstanceIdentifier<?>, DataObject> {
375 @SuppressWarnings("unchecked")
377 public DataCommitTransaction<InstanceIdentifier<?>, DataObject> requestCommit(
378 DataModification<InstanceIdentifier<?>, DataObject> modification) {
379 // We should verify transaction
380 System.out.println("Coming in GroupDatacommitHandler");
381 internalTransaction transaction = new internalTransaction(modification);
382 transaction.prepareUpdate();
387 private final class internalTransaction implements DataCommitTransaction<InstanceIdentifier<?>, DataObject> {
389 private final DataModification<InstanceIdentifier<?>, DataObject> modification;
392 public DataModification<InstanceIdentifier<?>, DataObject> getModification() {
396 public internalTransaction(DataModification<InstanceIdentifier<?>, DataObject> modification) {
397 this.modification = modification;
400 Map<InstanceIdentifier<?>, Group> additions = new HashMap<>();
401 Map<InstanceIdentifier<?>, Group> updates = new HashMap<>();
402 Set<InstanceIdentifier<?>> removals = new HashSet<>();
405 * We create a plan which flows will be added, which will be updated and
406 * which will be removed based on our internal state.
409 void prepareUpdate() {
411 Set<Entry<InstanceIdentifier<?>, DataObject>> puts = modification.getUpdatedConfigurationData().entrySet();
412 for (Entry<InstanceIdentifier<?>, DataObject> entry : puts) {
413 if (entry.getValue() instanceof Group) {
414 Group group = (Group) entry.getValue();
415 preparePutEntry(entry.getKey(), group);
420 removals = modification.getRemovedConfigurationData();
423 private void preparePutEntry(InstanceIdentifier<?> key, Group group) {
425 Group original = originalSwGroupView.get(key);
426 if (original != null) {
427 // It is update for us
429 updates.put(key, group);
431 // It is addition for us
433 additions.put(key, group);
438 * We are OK to go with execution of plan
442 public RpcResult<Void> finish() throws IllegalStateException {
444 RpcResult<Void> rpcStatus = commitToPlugin(this);
445 // We return true if internal transaction is successful.
446 // return Rpcs.getRpcResult(true, null, Collections.emptySet());
452 * We should rollback our preparation
456 public RpcResult<Void> rollback() throws IllegalStateException {
457 // NOOP - we did not modified any internal state during
458 // requestCommit phase
459 // return Rpcs.getRpcResult(true, null, Collections.emptySet());
460 return Rpcs.getRpcResult(true, null, null);
466 final class GroupEventListener implements SalGroupListener {
468 List<GroupAdded> addedGroups = new ArrayList<>();
469 List<GroupRemoved> removedGroups = new ArrayList<>();
470 List<GroupUpdated> updatedGroups = new ArrayList<>();
473 public void onGroupAdded(GroupAdded notification) {
474 System.out.println("added Group..........................");
475 addedGroups.add(notification);
479 public void onGroupRemoved(GroupRemoved notification) {
480 // TODO Auto-generated method stub
485 public void onGroupUpdated(GroupUpdated notification) {
486 // TODO Auto-generated method stub
492 public List<DataObject> get() {
494 List<DataObject> orderedList = new ArrayList<DataObject>();
495 Collection<Group> groupList = originalSwGroupView.values();
496 for (Iterator<Group> iterator = groupList.iterator(); iterator.hasNext();) {
497 orderedList.add(iterator.next());
503 public DataObject getWithName(String name, Node n) {
505 if (this instanceof GroupConsumerImpl) {
506 Collection<Group> groupList = originalSwGroupView.values();
507 for (Iterator<Group> iterator = groupList.iterator(); iterator.hasNext();) {
508 Group group = iterator.next();
509 if (group.getNode().equals(n) && group.getGroupName().equals(name)) {