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;
5 import com.google.common.base.Function;
6 import com.google.common.collect.FluentIterable;
7 import com.google.common.collect.ImmutableSet;
8 import com.google.common.util.concurrent.Futures;
9 import com.google.common.util.concurrent.ListenableFuture;
10 import java.lang.ref.WeakReference;
11 import java.lang.reflect.InvocationHandler;
12 import java.lang.reflect.Method;
13 import java.lang.reflect.Proxy;
14 import java.util.HashMap;
17 import java.util.WeakHashMap;
18 import java.util.concurrent.Callable;
19 import org.opendaylight.controller.sal.binding.api.RpcProviderRegistry;
20 import org.opendaylight.controller.sal.binding.api.rpc.RpcRouter;
21 import org.opendaylight.controller.sal.binding.impl.RpcProviderRegistryImpl;
22 import org.opendaylight.controller.sal.core.api.Broker;
23 import org.opendaylight.controller.sal.core.api.RpcImplementation;
24 import org.opendaylight.controller.sal.core.api.RpcProvisionRegistry;
25 import org.opendaylight.yangtools.concepts.CompositeObjectRegistration;
26 import org.opendaylight.yangtools.concepts.ObjectRegistration;
27 import org.opendaylight.yangtools.util.ClassLoaderUtils;
28 import org.opendaylight.yangtools.yang.binding.BaseIdentity;
29 import org.opendaylight.yangtools.yang.binding.BindingMapping;
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.common.QName;
35 import org.opendaylight.yangtools.yang.common.RpcResult;
36 import org.opendaylight.yangtools.yang.data.api.CompositeNode;
37 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
38 import org.opendaylight.yangtools.yang.data.impl.codec.BindingIndependentMappingService;
39 import org.slf4j.Logger;
40 import org.slf4j.LoggerFactory;
42 class DomToBindingRpcForwarder implements RpcImplementation, InvocationHandler {
44 private final Logger LOG = LoggerFactory.getLogger(DomToBindingRpcForwarder.class);
46 private final Set<QName> supportedRpcs;
47 private final WeakReference<Class<? extends RpcService>> rpcServiceType;
48 private Set<org.opendaylight.controller.sal.core.api.Broker.RoutedRpcRegistration> registrations;
49 private final Map<QName, RpcInvocationStrategy> strategiesByQName = new HashMap<>();
50 private final WeakHashMap<Method, RpcInvocationStrategy> strategiesByMethod = new WeakHashMap<>();
51 private final RpcService proxy;
52 private ObjectRegistration<?> forwarderRegistration;
53 private boolean registrationInProgress = false;
55 private final RpcProvisionRegistry biRpcRegistry;
56 private final RpcProviderRegistry baRpcRegistry;
57 private final RpcProviderRegistryImpl baRpcRegistryImpl;
59 private final Function<InstanceIdentifier<?>, YangInstanceIdentifier> toDOMInstanceIdentifier;
61 private final static Method EQUALS_METHOD;
65 EQUALS_METHOD = Object.class.getMethod("equals", Object.class);
66 } catch (NoSuchMethodException | SecurityException e) {
67 throw new ExceptionInInitializerError(e);
71 public DomToBindingRpcForwarder(final Class<? extends RpcService> service, final BindingIndependentMappingService mappingService,
72 final RpcProvisionRegistry biRpcRegistry, final RpcProviderRegistry baRpcRegistry, final RpcProviderRegistryImpl registryImpl) {
73 this.rpcServiceType = new WeakReference<Class<? extends RpcService>>(service);
74 this.supportedRpcs = mappingService.getRpcQNamesFor(service);
76 this.toDOMInstanceIdentifier = new Function<InstanceIdentifier<?>, YangInstanceIdentifier>() {
78 public YangInstanceIdentifier apply(final InstanceIdentifier<?> input) {
79 return mappingService.toDataDom(input);
83 this.biRpcRegistry = biRpcRegistry;
84 this.baRpcRegistry = baRpcRegistry;
85 this.baRpcRegistryImpl = registryImpl;
87 Class<?> cls = rpcServiceType.get();
88 ClassLoader clsLoader = cls.getClassLoader();
89 proxy =(RpcService) Proxy.newProxyInstance(clsLoader, new Class<?>[] { cls }, this);
90 createStrategies(mappingService);
94 * Constructor for Routed RPC Forwarder.
100 public DomToBindingRpcForwarder(final Class<? extends RpcService> service,
101 final Class<? extends BaseIdentity> context, final BindingIndependentMappingService mappingService,
102 final RpcProvisionRegistry biRpcRegistry, final RpcProviderRegistry baRpcRegistry, final RpcProviderRegistryImpl registryImpl) {
103 this(service, mappingService, biRpcRegistry, baRpcRegistry,registryImpl);
105 final ImmutableSet.Builder<Broker.RoutedRpcRegistration> registrationsBuilder = ImmutableSet.builder();
107 for (QName rpc : supportedRpcs) {
108 registrationsBuilder.add(biRpcRegistry.addRoutedRpcImplementation(rpc, this));
110 createDefaultDomForwarder();
111 } catch (Exception e) {
112 LOG.error("Could not forward Rpcs of type {}", service.getName(), e);
114 registrations = registrationsBuilder.build();
119 private void createStrategies(final BindingIndependentMappingService mappingService) {
121 for (QName rpc : supportedRpcs) {
122 RpcInvocationStrategy strategy = createInvocationStrategy(rpc, rpcServiceType.get(), mappingService);
123 strategiesByMethod.put(strategy.targetMethod, strategy);
124 strategiesByQName.put(rpc, strategy);
126 } catch (Exception e) {
127 LOG.error("Could not forward Rpcs of type {}", rpcServiceType.get(), e);
133 * Registers RPC Forwarder to DOM Broker,
134 * this means Binding Aware Broker has implementation of RPC
135 * which is registered to it.
137 * If RPC Forwarder was previously registered to DOM Broker
138 * or to Bidning Broker this method is noop to prevent
139 * creating forwarding loop.
142 public void registerToDOMBroker() {
143 if(!registrationInProgress && forwarderRegistration == null) {
144 registrationInProgress = true;
145 CompositeObjectRegistration.CompositeObjectRegistrationBuilder<DomToBindingRpcForwarder> builder = CompositeObjectRegistration.builderFor(this);
147 for (QName rpc : supportedRpcs) {
148 builder.add(biRpcRegistry.addRpcImplementation(rpc, this));
150 } catch (Exception e) {
151 LOG.error("Could not forward Rpcs of type {}", rpcServiceType.get(), e);
153 this.forwarderRegistration = builder.toInstance();
154 registrationInProgress = false;
159 public void registerPaths(final Class<? extends BaseIdentity> context,
160 final Class<? extends RpcService> service, final Set<InstanceIdentifier<?>> set) {
161 QName ctx = BindingReflections.findQName(context);
162 for (YangInstanceIdentifier path : FluentIterable.from(set).transform(
163 toDOMInstanceIdentifier)) {
164 for (org.opendaylight.controller.sal.core.api.Broker.RoutedRpcRegistration reg : registrations) {
165 reg.registerPath(ctx, path);
171 public Object invoke(final Object proxy, final Method method, final Object[] args) throws Throwable {
172 if (EQUALS_METHOD.equals(method)) {
175 RpcInvocationStrategy strategy = strategiesByMethod.get(method);
176 checkState(strategy != null);
177 checkArgument(args.length <= 2);
178 if (args.length == 1) {
179 checkArgument(args[0] instanceof DataObject);
180 return strategy.forwardToDomBroker((DataObject) args[0]);
182 return strategy.forwardToDomBroker(null);
185 public void removePaths(final Class<? extends BaseIdentity> context, final Class<? extends RpcService> service,
186 final Set<InstanceIdentifier<?>> set) {
187 QName ctx = BindingReflections.findQName(context);
188 for (YangInstanceIdentifier path : FluentIterable.from(set).transform(
189 toDOMInstanceIdentifier)) {
190 for (org.opendaylight.controller.sal.core.api.Broker.RoutedRpcRegistration reg : registrations) {
191 reg.unregisterPath(ctx, path);
197 public Set<QName> getSupportedRpcs() {
198 return supportedRpcs;
201 @SuppressWarnings({ "unchecked", "rawtypes" })
202 public void createDefaultDomForwarder() {
203 if (baRpcRegistryImpl != null) {
204 Class<?> cls = rpcServiceType.get();
205 ClassLoader clsLoader = cls.getClassLoader();
206 RpcService proxy = (RpcService) Proxy.newProxyInstance(clsLoader, new Class<?>[] { cls }, this);
208 RpcRouter rpcRouter = baRpcRegistryImpl.getRpcRouter(rpcServiceType.get());
209 rpcRouter.registerDefaultService(proxy);
214 public ListenableFuture<RpcResult<CompositeNode>> invokeRpc(final QName rpc, final CompositeNode domInput) {
215 checkArgument(rpc != null);
216 checkArgument(domInput != null);
218 Class<? extends RpcService> rpcType = rpcServiceType.get();
219 checkState(rpcType != null);
220 RpcService rpcService = baRpcRegistry.getRpcService(rpcType);
221 checkState(rpcService != null);
222 CompositeNode domUnwrappedInput = domInput.getFirstCompositeByName(QName.create(rpc, "input"));
225 return Futures.immediateFuture(resolveInvocationStrategy(rpc).invokeOn(rpcService, domUnwrappedInput));
226 } catch (Exception e) {
227 return Futures.immediateFailedFuture(e);
231 private RpcInvocationStrategy resolveInvocationStrategy(final QName rpc) {
232 return strategiesByQName.get(rpc);
235 private RpcInvocationStrategy createInvocationStrategy(final QName rpc,
236 final Class<? extends RpcService> rpcType, final BindingIndependentMappingService mappingService) throws Exception {
237 return ClassLoaderUtils.withClassLoader(rpcType.getClassLoader(), new Callable<RpcInvocationStrategy>() {
239 public RpcInvocationStrategy call() throws Exception {
240 String methodName = BindingMapping.getMethodName(rpc);
241 Method targetMethod = null;
242 for (Method possibleMethod : rpcType.getMethods()) {
243 if (possibleMethod.getName().equals(methodName)
244 && BindingReflections.isRpcMethod(possibleMethod)) {
245 targetMethod = possibleMethod;
249 checkState(targetMethod != null, "Rpc method not found");
250 return new RpcInvocationStrategy(rpc, targetMethod, mappingService, biRpcRegistry);
257 * Registers RPC Forwarder to Binding Broker,
258 * this means DOM Broekr has implementation of RPC
259 * which is registered to it.
261 * If RPC Forwarder was previously registered to DOM Broker
262 * or to Bidning Broker this method is noop to prevent
263 * creating forwarding loop.
266 public void registerToBindingBroker() {
267 if(!registrationInProgress && forwarderRegistration == null) {
269 registrationInProgress = true;
270 this.forwarderRegistration = baRpcRegistry.addRpcImplementation((Class)rpcServiceType.get(), proxy);
271 } catch (Exception e) {
272 LOG.error("Unable to forward RPCs for {}",rpcServiceType.get(),e);
274 registrationInProgress = false;