1 package org.opendaylight.controller.sal.binding.impl.connect.dom;
3 import static com.google.common.base.Preconditions.checkArgument;
4 import static com.google.common.base.Preconditions.checkState;
6 import com.google.common.base.Function;
7 import com.google.common.collect.FluentIterable;
8 import com.google.common.collect.ImmutableSet;
9 import com.google.common.util.concurrent.Futures;
10 import com.google.common.util.concurrent.ListenableFuture;
11 import java.lang.ref.WeakReference;
12 import java.lang.reflect.InvocationHandler;
13 import java.lang.reflect.Method;
14 import java.lang.reflect.Proxy;
15 import java.util.HashMap;
18 import java.util.WeakHashMap;
19 import java.util.concurrent.Callable;
20 import org.opendaylight.controller.sal.binding.api.RpcProviderRegistry;
21 import org.opendaylight.controller.sal.binding.api.rpc.RpcRouter;
22 import org.opendaylight.controller.sal.binding.impl.RpcProviderRegistryImpl;
23 import org.opendaylight.controller.sal.core.api.Broker;
24 import org.opendaylight.controller.sal.core.api.RpcImplementation;
25 import org.opendaylight.controller.sal.core.api.RpcProvisionRegistry;
26 import org.opendaylight.yangtools.concepts.CompositeObjectRegistration;
27 import org.opendaylight.yangtools.concepts.ObjectRegistration;
29 import org.opendaylight.yangtools.yang.binding.BaseIdentity;
30 import org.opendaylight.yangtools.yang.binding.DataObject;
31 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
32 import org.opendaylight.yangtools.yang.binding.RpcService;
33 import org.opendaylight.yangtools.yang.binding.util.BindingReflections;
34 import org.opendaylight.yangtools.yang.binding.util.ClassLoaderUtils;
35 import org.opendaylight.yangtools.yang.binding.BindingMapping;
36 import org.opendaylight.yangtools.yang.common.QName;
37 import org.opendaylight.yangtools.yang.common.RpcResult;
38 import org.opendaylight.yangtools.yang.data.api.CompositeNode;
39 import org.opendaylight.yangtools.yang.data.impl.codec.BindingIndependentMappingService;
40 import org.slf4j.Logger;
41 import org.slf4j.LoggerFactory;
43 class DomToBindingRpcForwarder implements RpcImplementation, InvocationHandler {
45 private final Logger LOG = LoggerFactory.getLogger(DomToBindingRpcForwarder.class);
47 private final Set<QName> supportedRpcs;
48 private final WeakReference<Class<? extends RpcService>> rpcServiceType;
49 private Set<org.opendaylight.controller.sal.core.api.Broker.RoutedRpcRegistration> registrations;
50 private final Map<QName, RpcInvocationStrategy> strategiesByQName = new HashMap<>();
51 private final WeakHashMap<Method, RpcInvocationStrategy> strategiesByMethod = new WeakHashMap<>();
52 private final RpcService proxy;
53 private ObjectRegistration<?> forwarderRegistration;
54 private boolean registrationInProgress = false;
56 private final RpcProvisionRegistry biRpcRegistry;
57 private final RpcProviderRegistry baRpcRegistry;
58 private final RpcProviderRegistryImpl baRpcRegistryImpl;
60 private final Function<InstanceIdentifier<?>, org.opendaylight.yangtools.yang.data.api.InstanceIdentifier> toDOMInstanceIdentifier;
62 private final static Method EQUALS_METHOD;
66 EQUALS_METHOD = Object.class.getMethod("equals", Object.class);
67 } catch (Exception e) {
68 throw new RuntimeException(e);
72 public DomToBindingRpcForwarder(final Class<? extends RpcService> service, final BindingIndependentMappingService mappingService,
73 final RpcProvisionRegistry biRpcRegistry, final RpcProviderRegistry baRpcRegistry) {
74 this.rpcServiceType = new WeakReference<Class<? extends RpcService>>(service);
75 this.supportedRpcs = mappingService.getRpcQNamesFor(service);
77 toDOMInstanceIdentifier = new Function<InstanceIdentifier<?>, org.opendaylight.yangtools.yang.data.api.InstanceIdentifier>() {
80 public org.opendaylight.yangtools.yang.data.api.InstanceIdentifier apply(final InstanceIdentifier<?> input) {
81 return mappingService.toDataDom(input);
85 this.biRpcRegistry = biRpcRegistry;
86 this.baRpcRegistry = baRpcRegistry;
87 baRpcRegistryImpl = (RpcProviderRegistryImpl) baRpcRegistry;
89 Class<?> cls = rpcServiceType.get();
90 ClassLoader clsLoader = cls.getClassLoader();
91 proxy =(RpcService) Proxy.newProxyInstance(clsLoader, new Class<?>[] { cls }, this);
92 createStrategies(mappingService);
96 * Constructor for Routed RPC Forwareder.
101 public DomToBindingRpcForwarder(final Class<? extends RpcService> service,
102 final Class<? extends BaseIdentity> context, final BindingIndependentMappingService mappingService,
103 final RpcProvisionRegistry biRpcRegistry, final RpcProviderRegistry baRpcRegistry) {
104 this(service, mappingService, biRpcRegistry, baRpcRegistry);
106 final ImmutableSet.Builder<Broker.RoutedRpcRegistration> registrationsBuilder = ImmutableSet.builder();
108 for (QName rpc : supportedRpcs) {
109 registrationsBuilder.add(biRpcRegistry.addRoutedRpcImplementation(rpc, this));
111 createDefaultDomForwarder();
112 } catch (Exception e) {
113 LOG.error("Could not forward Rpcs of type {}", service.getName(), e);
115 registrations = registrationsBuilder.build();
120 private void createStrategies(final BindingIndependentMappingService mappingService) {
122 for (QName rpc : supportedRpcs) {
123 RpcInvocationStrategy strategy = createInvocationStrategy(rpc, rpcServiceType.get(), mappingService);
124 strategiesByMethod.put(strategy.targetMethod, strategy);
125 strategiesByQName.put(rpc, strategy);
127 } catch (Exception e) {
128 LOG.error("Could not forward Rpcs of type {}", rpcServiceType.get(), e);
134 * Registers RPC Forwarder to DOM Broker,
135 * this means Binding Aware Broker has implementation of RPC
136 * which is registered to it.
138 * If RPC Forwarder was previously registered to DOM Broker
139 * or to Bidning Broker this method is noop to prevent
140 * creating forwarding loop.
143 public void registerToDOMBroker() {
144 if(!registrationInProgress && forwarderRegistration == null) {
145 registrationInProgress = true;
146 CompositeObjectRegistration.CompositeObjectRegistrationBuilder<DomToBindingRpcForwarder> builder = CompositeObjectRegistration.builderFor(this);
148 for (QName rpc : supportedRpcs) {
149 builder.add(biRpcRegistry.addRpcImplementation(rpc, this));
151 } catch (Exception e) {
152 LOG.error("Could not forward Rpcs of type {}", rpcServiceType.get(), e);
154 this.forwarderRegistration = builder.toInstance();
155 registrationInProgress = false;
160 public void registerPaths(final Class<? extends BaseIdentity> context,
161 final Class<? extends RpcService> service, final Set<InstanceIdentifier<?>> set) {
162 QName ctx = BindingReflections.findQName(context);
163 for (org.opendaylight.yangtools.yang.data.api.InstanceIdentifier path : FluentIterable.from(set).transform(
164 toDOMInstanceIdentifier)) {
165 for (org.opendaylight.controller.sal.core.api.Broker.RoutedRpcRegistration reg : registrations) {
166 reg.registerPath(ctx, path);
172 public Object invoke(final Object proxy, final Method method, final Object[] args) throws Throwable {
173 if (EQUALS_METHOD.equals(method)) {
176 RpcInvocationStrategy strategy = strategiesByMethod.get(method);
177 checkState(strategy != null);
178 checkArgument(args.length <= 2);
179 if (args.length == 1) {
180 checkArgument(args[0] instanceof DataObject);
181 return strategy.forwardToDomBroker((DataObject) args[0]);
183 return strategy.forwardToDomBroker(null);
186 public void removePaths(final Class<? extends BaseIdentity> context, final Class<? extends RpcService> service,
187 final Set<InstanceIdentifier<?>> set) {
188 QName ctx = BindingReflections.findQName(context);
189 for (org.opendaylight.yangtools.yang.data.api.InstanceIdentifier path : FluentIterable.from(set).transform(
190 toDOMInstanceIdentifier)) {
191 for (org.opendaylight.controller.sal.core.api.Broker.RoutedRpcRegistration reg : registrations) {
192 reg.unregisterPath(ctx, path);
198 public Set<QName> getSupportedRpcs() {
199 return supportedRpcs;
202 @SuppressWarnings({ "unchecked", "rawtypes" })
203 public void createDefaultDomForwarder() {
204 if (baRpcRegistryImpl != null) {
205 Class<?> cls = rpcServiceType.get();
206 ClassLoader clsLoader = cls.getClassLoader();
207 RpcService proxy = (RpcService) Proxy.newProxyInstance(clsLoader, new Class<?>[] { cls }, this);
209 RpcRouter rpcRouter = baRpcRegistryImpl.getRpcRouter(rpcServiceType.get());
210 rpcRouter.registerDefaultService(proxy);
215 public ListenableFuture<RpcResult<CompositeNode>> invokeRpc(final QName rpc, final CompositeNode domInput) {
216 checkArgument(rpc != null);
217 checkArgument(domInput != null);
219 Class<? extends RpcService> rpcType = rpcServiceType.get();
220 checkState(rpcType != null);
221 RpcService rpcService = baRpcRegistry.getRpcService(rpcType);
222 checkState(rpcService != null);
223 CompositeNode domUnwrappedInput = domInput.getFirstCompositeByName(QName.create(rpc, "input"));
226 return Futures.immediateFuture(resolveInvocationStrategy(rpc).invokeOn(rpcService, domUnwrappedInput));
227 } catch (Exception e) {
228 return Futures.immediateFailedFuture(e);
232 private RpcInvocationStrategy resolveInvocationStrategy(final QName rpc) {
233 return strategiesByQName.get(rpc);
236 private RpcInvocationStrategy createInvocationStrategy(final QName rpc,
237 final Class<? extends RpcService> rpcType, final BindingIndependentMappingService mappingService) throws Exception {
238 return ClassLoaderUtils.withClassLoader(rpcType.getClassLoader(), new Callable<RpcInvocationStrategy>() {
240 public RpcInvocationStrategy call() throws Exception {
241 String methodName = BindingMapping.getMethodName(rpc);
242 Method targetMethod = null;
243 for (Method possibleMethod : rpcType.getMethods()) {
244 if (possibleMethod.getName().equals(methodName)
245 && BindingReflections.isRpcMethod(possibleMethod)) {
246 targetMethod = possibleMethod;
250 checkState(targetMethod != null, "Rpc method not found");
251 return new RpcInvocationStrategy(rpc, targetMethod, mappingService, biRpcRegistry);
258 * Registers RPC Forwarder to Binding Broker,
259 * this means DOM Broekr has implementation of RPC
260 * which is registered to it.
262 * If RPC Forwarder was previously registered to DOM Broker
263 * or to Bidning Broker this method is noop to prevent
264 * creating forwarding loop.
267 public void registerToBindingBroker() {
268 if(!registrationInProgress && forwarderRegistration == null) {
270 registrationInProgress = true;
271 this.forwarderRegistration = baRpcRegistry.addRpcImplementation((Class)rpcServiceType.get(), proxy);
272 } catch (Exception e) {
273 LOG.error("Unable to forward RPCs for {}",rpcServiceType.get(),e);
275 registrationInProgress = false;