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