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