Lower fast-path locking in RpcContext
[openflowplugin.git] / openflowplugin-impl / src / main / java / org / opendaylight / openflowplugin / impl / rpc / RpcContextImpl.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.rpc;
9
10 import com.google.common.util.concurrent.SettableFuture;
11 import java.util.ArrayList;
12 import java.util.Collection;
13 import javax.annotation.concurrent.GuardedBy;
14 import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.RoutedRpcRegistration;
15 import org.opendaylight.controller.sal.binding.api.RpcProviderRegistry;
16 import org.opendaylight.openflowplugin.api.openflow.connection.ConnectionContext;
17 import org.opendaylight.openflowplugin.api.openflow.device.RequestContext;
18 import org.opendaylight.openflowplugin.api.openflow.rpc.RpcContext;
19 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeContext;
20 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node;
21 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey;
22 import org.opendaylight.yangtools.yang.binding.KeyedInstanceIdentifier;
23 import org.opendaylight.yangtools.yang.binding.RpcService;
24 import org.opendaylight.yangtools.yang.common.RpcError;
25 import org.opendaylight.yangtools.yang.common.RpcResult;
26 import org.opendaylight.yangtools.yang.common.RpcResultBuilder;
27 import org.slf4j.Logger;
28
29 public class RpcContextImpl implements RpcContext {
30     private static final Logger LOG = org.slf4j.LoggerFactory.getLogger(RpcContextImpl.class);
31     final RpcProviderRegistry rpcProviderRegistry;
32
33     // TODO: add private Sal salBroker
34     private final KeyedInstanceIdentifier<Node, NodeKey> nodeInstanceIdentifier;
35     private final Collection<RoutedRpcRegistration<?>> rpcRegistrations = new ArrayList<>();
36
37     @GuardedBy("requestsList")
38     private final Collection<RequestContext<?>> requestsList = new ArrayList<RequestContext<?>>();
39
40     private int maxRequestsPerDevice;
41
42     public RpcContextImpl(final RpcProviderRegistry rpcProviderRegistry, final KeyedInstanceIdentifier<Node, NodeKey> nodeInstanceIdentifier) {
43         this.rpcProviderRegistry = rpcProviderRegistry;
44         this.nodeInstanceIdentifier = nodeInstanceIdentifier;
45     }
46
47     /**
48      * @see org.opendaylight.openflowplugin.api.openflow.rpc.RpcContext#registerRpcServiceImplementation(java.lang.Class,
49      * org.opendaylight.yangtools.yang.binding.RpcService)
50      */
51     @Override
52     public <S extends RpcService> void registerRpcServiceImplementation(final Class<S> serviceClass,
53                                                                         final S serviceInstance) {
54         final RoutedRpcRegistration<S> routedRpcReg = rpcProviderRegistry.addRoutedRpcImplementation(serviceClass, serviceInstance);
55         routedRpcReg.registerPath(NodeContext.class, nodeInstanceIdentifier);
56         rpcRegistrations.add(routedRpcReg);
57         LOG.debug("Registration of service {} for device {}.",serviceClass, nodeInstanceIdentifier);
58     }
59
60     @Override
61     public <T> SettableFuture<RpcResult<T>> storeOrFail(final RequestContext<T> requestContext) {
62         final SettableFuture<RpcResult<T>> rpcResultFuture = requestContext.getFuture();
63
64         final boolean success;
65         // FIXME: use a fixed-size collection, with lockless reserve/set queue
66         synchronized (requestsList) {
67             if (requestsList.size() < maxRequestsPerDevice) {
68                 requestsList.add(requestContext);
69                 success = true;
70             } else {
71                 success = false;
72             }
73         }
74
75         if (!success) {
76             final RpcResult<T> rpcResult = RpcResultBuilder.<T>failed()
77                     .withError(RpcError.ErrorType.APPLICATION, "", "Device's request queue is full.").build();
78             rpcResultFuture.set(rpcResult);
79         }
80
81         return rpcResultFuture;
82     }
83
84     /**
85      * Unregisters all services.
86      *
87      * @see java.lang.AutoCloseable#close()
88      */
89     @Override
90     public void close() throws Exception {
91         for (final RoutedRpcRegistration<?> rpcRegistration : rpcRegistrations) {
92             rpcRegistration.unregisterPath(NodeContext.class, nodeInstanceIdentifier);
93             rpcRegistration.close();
94         }
95     }
96
97     /**
98      * @see org.opendaylight.openflowplugin.api.openflow.rpc.RpcContext#setRequestContextQuota(int)
99      */
100     @Override
101     public void setRequestContextQuota(final int maxRequestsPerDevice) {
102         this.maxRequestsPerDevice = maxRequestsPerDevice;
103     }
104
105     @Override
106     public <T> void forgetRequestContext(final RequestContext<T> requestContext) {
107         synchronized (requestsList) {
108             requestsList.remove(requestContext);
109             LOG.trace("Removed request context with xid {}. Context request in list {}.",
110                 requestContext.getXid().getValue(), requestsList.size());
111         }
112     }
113
114     @Override
115     public <T> RequestContext<T> createRequestContext() {
116         return new RequestContextImpl<T>(this);
117     }
118
119     @Override
120     public void onDeviceDisconnected(final ConnectionContext connectionContext) {
121         for (RoutedRpcRegistration<?> registration : rpcRegistrations) {
122             registration.close();
123         }
124
125         synchronized (requestsList) {
126             requestsList.clear();
127         }
128     }
129 }