1adff5a3adf4e44f8941cd449f276f1c8747c90b
[openflowplugin.git] / openflowplugin-impl / src / main / java / org / opendaylight / openflowplugin / impl / role / OpenflowOwnershipListener.java
1 /**
2  * Copyright (c) 2015 Cisco Systems, Inc. and others.  All rights reserved.
3  *
4  * This program and the accompanying materials are made available under the
5  * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6  * and is available at http://www.eclipse.org/legal/epl-v10.html
7  */
8 package org.opendaylight.openflowplugin.impl.role;
9
10 import com.google.common.base.Optional;
11 import com.google.common.base.Preconditions;
12 import com.google.common.base.Verify;
13 import java.util.concurrent.ConcurrentHashMap;
14 import java.util.concurrent.ConcurrentMap;
15 import javax.annotation.CheckForNull;
16 import javax.annotation.Nonnull;
17 import org.opendaylight.controller.md.sal.common.api.clustering.Entity;
18 import org.opendaylight.controller.md.sal.common.api.clustering.EntityOwnershipChange;
19 import org.opendaylight.controller.md.sal.common.api.clustering.EntityOwnershipListener;
20 import org.opendaylight.controller.md.sal.common.api.clustering.EntityOwnershipListenerRegistration;
21 import org.opendaylight.controller.md.sal.common.api.clustering.EntityOwnershipService;
22 import org.opendaylight.controller.md.sal.common.api.clustering.EntityOwnershipState;
23 import org.opendaylight.openflowplugin.api.openflow.role.RoleChangeListener;
24 import org.opendaylight.openflowplugin.api.openflow.role.RoleManager;
25 import org.opendaylight.yang.gen.v1.urn.opendaylight.role.service.rev150727.OfpRole;
26 import org.slf4j.Logger;
27 import org.slf4j.LoggerFactory;
28
29 /**
30  * Class strictly separates {@link EntityOwnershipService} and OpenflowPlugin. So internal OpenflowPlugin
31  * implementation will stay without change for all {@link EntityOwnershipService} API changes.
32  *
33  * Created by kramesha on 9/14/15.
34  */
35 public class OpenflowOwnershipListener implements EntityOwnershipListener, AutoCloseable {
36
37     private static final Logger LOG = LoggerFactory.getLogger(OpenflowOwnershipListener.class);
38
39     public static boolean REMOVE_NODE_FROM_DS = true;
40
41     private final EntityOwnershipService entityOwnershipService;
42     private EntityOwnershipListenerRegistration entityOwnershipListenerRegistration;
43     private final ConcurrentMap<Entity, RoleChangeListener> roleChangeListenerMap = new ConcurrentHashMap<>();
44
45     /**
46      * Initialization method has to be call from {@link org.opendaylight.openflowplugin.api.openflow.role.RoleManager}
47      * @param entityOwnershipService
48      */
49     public OpenflowOwnershipListener(@Nonnull final EntityOwnershipService entityOwnershipService) {
50         LOG.debug("New instance of OpenflowOwnershipListener is created");
51         this.entityOwnershipService = Preconditions.checkNotNull(entityOwnershipService);
52     }
53
54     /**
55      * Initialization method is register {@link OpenflowOwnershipListener} as listener
56      * for EntityType = {@link RoleManager#ENTITY_TYPE}
57      */
58     public void init() {
59         LOG.debug("OpenflowOwnershipListener is registred as EntityOwnershipListener for {} type", RoleManager.ENTITY_TYPE);
60         entityOwnershipListenerRegistration = entityOwnershipService.registerListener(RoleManager.ENTITY_TYPE, this);
61     }
62
63     @Override
64     public void ownershipChanged(final EntityOwnershipChange ownershipChange) {
65         Preconditions.checkArgument(ownershipChange != null);
66         final RoleChangeListener roleChangeListener = roleChangeListenerMap.get(ownershipChange.getEntity());
67
68
69         if (roleChangeListener != null) {
70             LOG.debug("Found local entity:{}", ownershipChange.getEntity());
71
72             // if this was the master and entity does not have a master
73             if (ownershipChange.wasOwner() && !ownershipChange.isOwner() && !ownershipChange.hasOwner()) {
74                 // possible the last node to be disconnected from device.
75                 // eligible for the device to get deleted from inventory.
76                 LOG.debug("Initiate removal from operational. Possibly the last node to be disconnected for :{}. ", ownershipChange);
77                 roleChangeListener.onDeviceDisconnectedFromCluster();
78
79             } else {
80                 final OfpRole newRole = ownershipChange.isOwner() ? OfpRole.BECOMEMASTER : OfpRole.BECOMESLAVE;
81                 final OfpRole oldRole = ownershipChange.wasOwner() ? OfpRole.BECOMEMASTER : OfpRole.BECOMESLAVE;
82                 // send even if they are same. we do the check for duplicates in SalRoleService and maintain a lastKnownRole
83                 roleChangeListener.onRoleChanged(oldRole, newRole);
84             }
85         }
86     }
87
88     /**
89      * Candidate registration process doesn't send Event about actual {@link EntityOwnershipState} for
90      * Candidate. So we have to ask {@link EntityOwnershipService#getOwnershipState(Entity)} directly
91      * for every new instance. Call this method from RoleManager after candidateRegistration.
92      * @param roleChangeListener - new {@link RoleChangeListener} RoleContext
93      */
94     public void registerRoleChangeListener(@CheckForNull final RoleChangeListener roleChangeListener) {
95         LOG.debug("registerRoleChangeListener {}", roleChangeListener);
96         Preconditions.checkArgument(roleChangeListener != null);
97         Verify.verify(roleChangeListenerMap.putIfAbsent(roleChangeListener.getEntity(), roleChangeListener) == null);
98
99         final Entity entity = roleChangeListener.getEntity();
100
101         final Optional<EntityOwnershipState> entityOwnershipStateOptional = entityOwnershipService.getOwnershipState(entity);
102
103         if (entityOwnershipStateOptional != null && entityOwnershipStateOptional.isPresent()) {
104             final EntityOwnershipState entityOwnershipState = entityOwnershipStateOptional.get();
105             if (entityOwnershipState.hasOwner()) {
106                 LOG.debug("An owner exist for entity {}", entity);
107                 if (entityOwnershipState.isOwner()) {
108                     LOG.debug("Ownership is here for entity {} becoming master", entity);
109                     roleChangeListener.onRoleChanged(OfpRole.BECOMEMASTER, OfpRole.BECOMEMASTER);
110                 } else {
111                     LOG.debug("Ownership is NOT here for entity {} becoming alave", entity);
112                     roleChangeListener.onRoleChanged(OfpRole.BECOMESLAVE, OfpRole.BECOMESLAVE);
113                 }
114             }
115         }
116     }
117
118     /**
119      * Unregistration process has to remove {@link RoleChangeListener} from internal map, so
120      * we will not get anymore Events for this listener.
121      * @param roleChangeListener - RoleContext
122      */
123     public void unregisterRoleChangeListener(@CheckForNull final RoleChangeListener roleChangeListener) {
124         LOG.debug("unregisterroleChangeListener {}", roleChangeListener);
125         Preconditions.checkArgument(roleChangeListener != null);
126         roleChangeListenerMap.remove(roleChangeListener.getEntity(), roleChangeListener);
127     }
128
129     @Override
130     public void close() throws Exception {
131         if (entityOwnershipListenerRegistration != null) {
132             entityOwnershipListenerRegistration.close();
133         }
134     }
135 }