Merge "OPNFLWPLUG-963 : Updating ports delete reason from OFP:"
[openflowplugin.git] / openflowplugin-impl / src / main / java / org / opendaylight / openflowplugin / impl / services / sal / SalRoleServiceImpl.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.services.sal;
9
10 import com.google.common.base.Preconditions;
11 import com.google.common.util.concurrent.Futures;
12 import com.google.common.util.concurrent.JdkFutureAdapters;
13 import com.google.common.util.concurrent.ListenableFuture;
14 import com.google.common.util.concurrent.MoreExecutors;
15 import java.math.BigInteger;
16 import java.util.concurrent.Future;
17 import org.opendaylight.openflowplugin.api.openflow.connection.ConnectionContext.CONNECTION_STATE;
18 import org.opendaylight.openflowplugin.api.openflow.device.DeviceContext;
19 import org.opendaylight.openflowplugin.api.openflow.device.RequestContextStack;
20 import org.opendaylight.openflowplugin.api.openflow.device.Xid;
21 import org.opendaylight.openflowplugin.impl.services.AbstractSimpleService;
22 import org.opendaylight.openflowplugin.impl.services.RoleService;
23 import org.opendaylight.openflowplugin.impl.services.util.ServiceException;
24 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.OfHeader;
25 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.RoleRequestOutput;
26 import org.opendaylight.yang.gen.v1.urn.opendaylight.role.service.rev150727.OfpRole;
27 import org.opendaylight.yang.gen.v1.urn.opendaylight.role.service.rev150727.SalRoleService;
28 import org.opendaylight.yang.gen.v1.urn.opendaylight.role.service.rev150727.SetRoleInput;
29 import org.opendaylight.yang.gen.v1.urn.opendaylight.role.service.rev150727.SetRoleOutput;
30 import org.opendaylight.yangtools.yang.common.RpcResult;
31 import org.slf4j.Logger;
32 import org.slf4j.LoggerFactory;
33
34
35 public final class SalRoleServiceImpl extends AbstractSimpleService<SetRoleInput, SetRoleOutput>
36                                       implements SalRoleService  {
37
38     private static final Logger LOG = LoggerFactory.getLogger(SalRoleServiceImpl.class);
39     private static final BigInteger MAX_GENERATION_ID = new BigInteger("ffffffffffffffff", 16);
40
41     private final DeviceContext deviceContext;
42     private final RoleService roleService;
43
44     public SalRoleServiceImpl(final RequestContextStack requestContextStack, final DeviceContext deviceContext) {
45         super(requestContextStack, deviceContext, SetRoleOutput.class);
46         this.deviceContext = Preconditions.checkNotNull(deviceContext);
47         this.roleService =  new RoleService(requestContextStack, deviceContext, RoleRequestOutput.class);
48     }
49
50     @Override
51     protected OfHeader buildRequest(final Xid xid, final SetRoleInput input) throws ServiceException {
52         return null;
53     }
54
55     @Override
56     public Future<RpcResult<SetRoleOutput>> setRole(final SetRoleInput input) {
57         LOG.info("SetRole called with input:{}", input);
58
59         // Check current connection state
60         final CONNECTION_STATE state = deviceContext.getPrimaryConnectionContext().getConnectionState();
61         switch (state) {
62             case RIP:
63                 LOG.info("Device {} has been disconnected", input.getNode());
64                 return Futures.immediateFailedFuture(new Exception(String
65                         .format("Device connection doesn't exist anymore. Primary connection status : %s",
66                                 state)));
67             case WORKING:
68                 // We can proceed
69                 LOG.trace("Device {} has been working", input.getNode());
70                 break;
71             default:
72                 LOG.warn("Device {} is in state {}, role change is not allowed", input.getNode(), state);
73                 return Futures.immediateFailedFuture(new Exception(String
74                         .format("Unexpected device connection status : %s", state)));
75         }
76
77         LOG.info("Requesting state change to {}", input.getControllerRole());
78         return tryToChangeRole(input.getControllerRole());
79     }
80
81     private ListenableFuture<RpcResult<SetRoleOutput>> tryToChangeRole(final OfpRole role) {
82         LOG.info("RoleChangeTask called on device:{} OFPRole:{}", getDeviceInfo().getNodeId().getValue(), role);
83
84         final Future<BigInteger> generationFuture = roleService.getGenerationIdFromDevice(getVersion());
85
86         return Futures.transformAsync(JdkFutureAdapters.listenInPoolThread(generationFuture), generationId -> {
87             LOG.debug("RoleChangeTask, GenerationIdFromDevice from device {} is {}",
88                     getDeviceInfo().getNodeId().getValue(), generationId);
89             final BigInteger nextGenerationId = getNextGenerationId(generationId);
90             LOG.debug("nextGenerationId received from device:{} is {}",
91                     getDeviceInfo().getNodeId().getValue(), nextGenerationId);
92             final Future<RpcResult<SetRoleOutput>> submitRoleFuture =
93                     roleService.submitRoleChange(role, getVersion(), nextGenerationId);
94             return JdkFutureAdapters.listenInPoolThread(submitRoleFuture);
95         }, MoreExecutors.directExecutor());
96     }
97
98     private static BigInteger getNextGenerationId(final BigInteger generationId) {
99         if (generationId.compareTo(MAX_GENERATION_ID) < 0) {
100             return generationId.add(BigInteger.ONE);
101         } else {
102             return BigInteger.ZERO;
103         }
104     }
105 }