8fe9869d40c405d9d64dea03356a2b20f71983c0
[openflowplugin.git] / openflowplugin-impl / src / main / java / org / opendaylight / openflowplugin / impl / role / RoleContextImpl.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 javax.annotation.Nullable;
11 import java.util.concurrent.Future;
12
13 import com.google.common.annotations.VisibleForTesting;
14 import com.google.common.util.concurrent.FutureCallback;
15 import com.google.common.util.concurrent.Futures;
16 import com.google.common.util.concurrent.JdkFutureAdapters;
17 import com.google.common.util.concurrent.SettableFuture;
18 import org.opendaylight.controller.md.sal.common.api.clustering.CandidateAlreadyRegisteredException;
19 import org.opendaylight.controller.md.sal.common.api.clustering.Entity;
20 import org.opendaylight.controller.md.sal.common.api.clustering.EntityOwnershipCandidateRegistration;
21 import org.opendaylight.controller.md.sal.common.api.clustering.EntityOwnershipService;
22 import org.opendaylight.controller.sal.binding.api.RpcProviderRegistry;
23 import org.opendaylight.openflowplugin.api.openflow.connection.ConnectionContext;
24 import org.opendaylight.openflowplugin.api.openflow.device.DeviceContext;
25 import org.opendaylight.openflowplugin.api.openflow.device.RequestContext;
26 import org.opendaylight.openflowplugin.api.openflow.role.RoleContext;
27 import org.opendaylight.openflowplugin.api.openflow.role.RoleManager;
28 import org.opendaylight.openflowplugin.impl.rpc.AbstractRequestContext;
29 import org.opendaylight.openflowplugin.impl.services.SalRoleServiceImpl;
30 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeRef;
31 import org.opendaylight.yang.gen.v1.urn.opendaylight.role.service.rev150727.OfpRole;
32 import org.opendaylight.yang.gen.v1.urn.opendaylight.role.service.rev150727.SalRoleService;
33 import org.opendaylight.yang.gen.v1.urn.opendaylight.role.service.rev150727.SetRoleInput;
34 import org.opendaylight.yang.gen.v1.urn.opendaylight.role.service.rev150727.SetRoleInputBuilder;
35 import org.opendaylight.yang.gen.v1.urn.opendaylight.role.service.rev150727.SetRoleOutput;
36 import org.opendaylight.yangtools.yang.common.RpcResult;
37 import org.slf4j.Logger;
38 import org.slf4j.LoggerFactory;
39
40 /**
41  * Created by kramesha on 9/12/15.
42  */
43 public class RoleContextImpl implements RoleContext {
44     private static final Logger LOG = LoggerFactory.getLogger(RoleContextImpl.class);
45
46     private final EntityOwnershipService entityOwnershipService;
47     private EntityOwnershipCandidateRegistration entityOwnershipCandidateRegistration;
48     private final RpcProviderRegistry rpcProviderRegistry;
49     private final DeviceContext deviceContext;
50     private final Entity entity;
51     private final OpenflowOwnershipListener openflowOwnershipListener;
52     private SalRoleService salRoleService;
53     private FutureCallback<Boolean> roleChangeCallback;
54
55     private final SettableFuture<OfpRole> initRoleChangeFuture;
56
57     public RoleContextImpl(final DeviceContext deviceContext, final RpcProviderRegistry rpcProviderRegistry,
58                            final EntityOwnershipService entityOwnershipService, final OpenflowOwnershipListener openflowOwnershipListener) {
59         this.entityOwnershipService = entityOwnershipService;
60         this.rpcProviderRegistry = rpcProviderRegistry;
61         this.deviceContext = deviceContext;
62         entity = new Entity(RoleManager.ENTITY_TYPE, deviceContext.getPrimaryConnectionContext().getNodeId().getValue());
63
64         this.openflowOwnershipListener =  openflowOwnershipListener;
65         salRoleService = new SalRoleServiceImpl(this, deviceContext);
66
67         initRoleChangeFuture = SettableFuture.create();
68     }
69
70     @Override
71     public Future<OfpRole> initialization() throws CandidateAlreadyRegisteredException {
72         LOG.debug("Initialization requestOpenflowEntityOwnership for entity {}", entity);
73         openflowOwnershipListener.registerRoleChangeListener(this);
74         entityOwnershipCandidateRegistration = entityOwnershipService.registerCandidate(entity);
75         LOG.info("RoleContextImpl : Candidate registered with ownership service for device :{}", deviceContext
76                 .getPrimaryConnectionContext().getNodeId().getValue());
77         return initRoleChangeFuture;
78     }
79
80     /**
81      * @deprecated not used but we are able to add here extra call for get EntityOwnershipState from
82      *             OpenflowOwnershipListener instead call it directly from RoleManager (here could be
83      *             add call salRoleService.setRole(setRoleInput);
84      */
85     @Override
86     @Deprecated
87     public void facilitateRoleChange(final FutureCallback<Boolean> roleChangeCallback) {
88         this.roleChangeCallback = roleChangeCallback;
89         if (!isDeviceConnected()) {
90             throw new IllegalStateException(
91                     "Device is disconnected. Giving up on Role Change:" + deviceContext.getDeviceState().getNodeId());
92         }
93     }
94
95     /**
96      * @deprecated not used
97      */
98     @Deprecated
99     private void requestOpenflowEntityOwnership() {
100
101         LOG.debug("requestOpenflowEntityOwnership for entity {}", entity);
102         try {
103             entityOwnershipCandidateRegistration = entityOwnershipService.registerCandidate(entity);
104
105             // The role change listener must be registered after registering a candidate
106             openflowOwnershipListener.registerRoleChangeListener(this);
107             LOG.info("RoleContextImpl : Candidate registered with ownership service for device :{}", deviceContext.getPrimaryConnectionContext().getNodeId().getValue());
108         } catch (final CandidateAlreadyRegisteredException e) {
109             // we can log and move for this error, as listener is present and role changes will be served.
110             LOG.error("Candidate - Entity already registered with Openflow candidate ", entity, e );
111         }
112     }
113
114     @Override
115     public void onRoleChanged(final OfpRole oldRole, final OfpRole newRole) {
116         LOG.trace("onRoleChanged method call for Entity {}", entity);
117
118         if (!isDeviceConnected()) {
119             // this can happen as after the disconnect, we still get a last messsage from EntityOwnershipService.
120             LOG.info("Device {} is disconnected from this node. Hence not attempting a role change.",
121                     deviceContext.getPrimaryConnectionContext().getNodeId());
122             if (!initRoleChangeFuture.isDone()) {
123                 LOG.debug("RoleChange is not valid for initialization Entity {} anymore - Device is disconnected", entity);
124                 initRoleChangeFuture.cancel(true);
125             }
126             return;
127         }
128
129         if (!initRoleChangeFuture.isDone()) {
130             LOG.debug("Initialization Role for entity {} is chosed {}", entity, newRole);
131             initRoleChangeFuture.set(newRole);
132         }
133
134         LOG.debug("Role change received from ownership listener from {} to {} for device:{}", oldRole, newRole,
135                 deviceContext.getPrimaryConnectionContext().getNodeId());
136
137         final SetRoleInput setRoleInput = (new SetRoleInputBuilder())
138                 .setControllerRole(newRole)
139                 .setNode(new NodeRef(deviceContext.getDeviceState().getNodeInstanceIdentifier()))
140                 .build();
141
142         final Future<RpcResult<SetRoleOutput>> setRoleOutputFuture = salRoleService.setRole(setRoleInput);
143
144         Futures.addCallback(JdkFutureAdapters.listenInPoolThread(setRoleOutputFuture), new FutureCallback<RpcResult<SetRoleOutput>>() {
145             @Override
146             public void onSuccess(final RpcResult<SetRoleOutput> setRoleOutputRpcResult) {
147                 LOG.debug("Rolechange {} successful made on switch :{}", newRole,
148                         deviceContext.getPrimaryConnectionContext().getNodeId());
149                 deviceContext.getDeviceState().setRole(newRole);
150                 if (roleChangeCallback != null) {
151                     roleChangeCallback.onSuccess(true);
152                 }
153             }
154
155             @Override
156             public void onFailure(final Throwable throwable) {
157                 LOG.error("Error in setRole {} for device {} ", newRole,
158                         deviceContext.getPrimaryConnectionContext().getNodeId(), throwable);
159                 if (roleChangeCallback != null) {
160                     roleChangeCallback.onFailure(throwable);
161                 }
162             }
163         });
164     }
165
166     @Override
167     public void close() throws Exception {
168         if (entityOwnershipCandidateRegistration != null) {
169             LOG.debug("Closing EntityOwnershipCandidateRegistration for {}", entity);
170             entityOwnershipCandidateRegistration.close();
171         }
172     }
173
174     @Override
175     public void onDeviceContextClosed(final DeviceContext deviceContext) {
176         try {
177             LOG.debug("onDeviceContextClosed called");
178             this.close();
179         } catch (final Exception e) {
180             LOG.error("Exception in onDeviceContextClosed of RoleContext", e);
181         }
182     }
183
184     @Override
185     public Entity getEntity() {
186         return entity;
187     }
188
189     @Override
190     public void onDeviceDisconnectedFromCluster(final boolean removeNodeFromDS) {
191         LOG.debug("Called onDeviceDisconnectedFromCluster in DeviceContext for entity:{}", entity);
192         deviceContext.onDeviceDisconnectedFromCluster(removeNodeFromDS);
193     }
194
195     private boolean isDeviceConnected() {
196         return ConnectionContext.CONNECTION_STATE.WORKING.equals(
197                 deviceContext.getPrimaryConnectionContext().getConnectionState());
198     }
199
200     @Nullable
201     @Override
202     public <T> RequestContext<T> createRequestContext() {
203         final AbstractRequestContext<T> ret = new AbstractRequestContext<T>(deviceContext.getReservedXid()) {
204             @Override
205             public void close() {
206             }
207         };
208         return ret;
209     }
210
211     @VisibleForTesting
212     public void setSalRoleService(final SalRoleService salRoleService) {
213         this.salRoleService = salRoleService;
214     }
215 }