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;
12 import java.lang.ref.WeakReference;
13 import java.lang.reflect.InvocationHandler;
14 import java.lang.reflect.Method;
15 import java.lang.reflect.Proxy;
16 import java.util.HashMap;
19 import java.util.WeakHashMap;
20 import java.util.concurrent.Callable;
22 import org.opendaylight.controller.sal.binding.api.RpcProviderRegistry;
23 import org.opendaylight.controller.sal.binding.api.rpc.RpcRouter;
24 import org.opendaylight.controller.sal.binding.impl.RpcProviderRegistryImpl;
25 import org.opendaylight.controller.sal.core.api.Broker;
26 import org.opendaylight.controller.sal.core.api.RpcImplementation;
27 import org.opendaylight.controller.sal.core.api.RpcProvisionRegistry;
28 import org.opendaylight.yangtools.concepts.CompositeObjectRegistration;
29 import org.opendaylight.yangtools.concepts.ObjectRegistration;
30 import org.opendaylight.yangtools.util.ClassLoaderUtils;
31 import org.opendaylight.yangtools.yang.binding.BaseIdentity;
32 import org.opendaylight.yangtools.yang.binding.BindingMapping;
33 import org.opendaylight.yangtools.yang.binding.DataObject;
34 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
35 import org.opendaylight.yangtools.yang.binding.RpcService;
36 import org.opendaylight.yangtools.yang.binding.util.BindingReflections;
37 import org.opendaylight.yangtools.yang.common.QName;
38 import org.opendaylight.yangtools.yang.common.RpcResult;
39 import org.opendaylight.yangtools.yang.data.api.CompositeNode;
40 import org.opendaylight.yangtools.yang.data.impl.codec.BindingIndependentMappingService;
41 import org.slf4j.Logger;
42 import org.slf4j.LoggerFactory;
44 class DomToBindingRpcForwarder implements RpcImplementation, InvocationHandler {
46 private final Logger LOG = LoggerFactory.getLogger(DomToBindingRpcForwarder.class);
48 private final Set<QName> supportedRpcs;
49 private final WeakReference<Class<? extends RpcService>> rpcServiceType;
50 private Set<org.opendaylight.controller.sal.core.api.Broker.RoutedRpcRegistration> registrations;
51 private final Map<QName, RpcInvocationStrategy> strategiesByQName = new HashMap<>();
52 private final WeakHashMap<Method, RpcInvocationStrategy> strategiesByMethod = new WeakHashMap<>();
53 private final RpcService proxy;
54 private ObjectRegistration<?> forwarderRegistration;
55 private boolean registrationInProgress = false;
57 private final RpcProvisionRegistry biRpcRegistry;
58 private final RpcProviderRegistry baRpcRegistry;
59 private final RpcProviderRegistryImpl baRpcRegistryImpl;
61 private final Function<InstanceIdentifier<?>, org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier> toDOMInstanceIdentifier;
63 private final static Method EQUALS_METHOD;
67 EQUALS_METHOD = Object.class.getMethod("equals", Object.class);
68 } catch (NoSuchMethodException | SecurityException e) {
69 throw new ExceptionInInitializerError(e);
73 public DomToBindingRpcForwarder(final Class<? extends RpcService> service, final BindingIndependentMappingService mappingService,
74 final RpcProvisionRegistry biRpcRegistry, final RpcProviderRegistry baRpcRegistry, final RpcProviderRegistryImpl registryImpl) {
75 this.rpcServiceType = new WeakReference<Class<? extends RpcService>>(service);
76 this.supportedRpcs = mappingService.getRpcQNamesFor(service);
78 toDOMInstanceIdentifier = new Function<InstanceIdentifier<?>, org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier>() {
81 public org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier apply(final InstanceIdentifier<?> input) {
82 return mappingService.toDataDom(input);
86 this.biRpcRegistry = biRpcRegistry;
87 this.baRpcRegistry = baRpcRegistry;
88 this.baRpcRegistryImpl = registryImpl;
90 Class<?> cls = rpcServiceType.get();
91 ClassLoader clsLoader = cls.getClassLoader();
92 proxy =(RpcService) Proxy.newProxyInstance(clsLoader, new Class<?>[] { cls }, this);
93 createStrategies(mappingService);
97 * Constructor for Routed RPC Forwarder.
101 * @param registryImpl
103 public DomToBindingRpcForwarder(final Class<? extends RpcService> service,
104 final Class<? extends BaseIdentity> context, final BindingIndependentMappingService mappingService,
105 final RpcProvisionRegistry biRpcRegistry, final RpcProviderRegistry baRpcRegistry, final RpcProviderRegistryImpl registryImpl) {
106 this(service, mappingService, biRpcRegistry, baRpcRegistry,registryImpl);
108 final ImmutableSet.Builder<Broker.RoutedRpcRegistration> registrationsBuilder = ImmutableSet.builder();
110 for (QName rpc : supportedRpcs) {
111 registrationsBuilder.add(biRpcRegistry.addRoutedRpcImplementation(rpc, this));
113 createDefaultDomForwarder();
114 } catch (Exception e) {
115 LOG.error("Could not forward Rpcs of type {}", service.getName(), e);
117 registrations = registrationsBuilder.build();
122 private void createStrategies(final BindingIndependentMappingService mappingService) {
124 for (QName rpc : supportedRpcs) {
125 RpcInvocationStrategy strategy = createInvocationStrategy(rpc, rpcServiceType.get(), mappingService);
126 strategiesByMethod.put(strategy.targetMethod, strategy);
127 strategiesByQName.put(rpc, strategy);
129 } catch (Exception e) {
130 LOG.error("Could not forward Rpcs of type {}", rpcServiceType.get(), e);
136 * Registers RPC Forwarder to DOM Broker,
137 * this means Binding Aware Broker has implementation of RPC
138 * which is registered to it.
140 * If RPC Forwarder was previously registered to DOM Broker
141 * or to Bidning Broker this method is noop to prevent
142 * creating forwarding loop.
145 public void registerToDOMBroker() {
146 if(!registrationInProgress && forwarderRegistration == null) {
147 registrationInProgress = true;
148 CompositeObjectRegistration.CompositeObjectRegistrationBuilder<DomToBindingRpcForwarder> builder = CompositeObjectRegistration.builderFor(this);
150 for (QName rpc : supportedRpcs) {
151 builder.add(biRpcRegistry.addRpcImplementation(rpc, this));
153 } catch (Exception e) {
154 LOG.error("Could not forward Rpcs of type {}", rpcServiceType.get(), e);
156 this.forwarderRegistration = builder.toInstance();
157 registrationInProgress = false;
162 public void registerPaths(final Class<? extends BaseIdentity> context,
163 final Class<? extends RpcService> service, final Set<InstanceIdentifier<?>> set) {
164 QName ctx = BindingReflections.findQName(context);
165 for (org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier path : FluentIterable.from(set).transform(
166 toDOMInstanceIdentifier)) {
167 for (org.opendaylight.controller.sal.core.api.Broker.RoutedRpcRegistration reg : registrations) {
168 reg.registerPath(ctx, path);
174 public Object invoke(final Object proxy, final Method method, final Object[] args) throws Throwable {
175 if (EQUALS_METHOD.equals(method)) {
178 RpcInvocationStrategy strategy = strategiesByMethod.get(method);
179 checkState(strategy != null);
180 checkArgument(args.length <= 2);
181 if (args.length == 1) {
182 checkArgument(args[0] instanceof DataObject);
183 return strategy.forwardToDomBroker((DataObject) args[0]);
185 return strategy.forwardToDomBroker(null);
188 public void removePaths(final Class<? extends BaseIdentity> context, final Class<? extends RpcService> service,
189 final Set<InstanceIdentifier<?>> set) {
190 QName ctx = BindingReflections.findQName(context);
191 for (org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier path : FluentIterable.from(set).transform(
192 toDOMInstanceIdentifier)) {
193 for (org.opendaylight.controller.sal.core.api.Broker.RoutedRpcRegistration reg : registrations) {
194 reg.unregisterPath(ctx, path);
200 public Set<QName> getSupportedRpcs() {
201 return supportedRpcs;
204 @SuppressWarnings({ "unchecked", "rawtypes" })
205 public void createDefaultDomForwarder() {
206 if (baRpcRegistryImpl != null) {
207 Class<?> cls = rpcServiceType.get();
208 ClassLoader clsLoader = cls.getClassLoader();
209 RpcService proxy = (RpcService) Proxy.newProxyInstance(clsLoader, new Class<?>[] { cls }, this);
211 RpcRouter rpcRouter = baRpcRegistryImpl.getRpcRouter(rpcServiceType.get());
212 rpcRouter.registerDefaultService(proxy);
217 public ListenableFuture<RpcResult<CompositeNode>> invokeRpc(final QName rpc, final CompositeNode domInput) {
218 checkArgument(rpc != null);
219 checkArgument(domInput != null);
221 Class<? extends RpcService> rpcType = rpcServiceType.get();
222 checkState(rpcType != null);
223 RpcService rpcService = baRpcRegistry.getRpcService(rpcType);
224 checkState(rpcService != null);
225 CompositeNode domUnwrappedInput = domInput.getFirstCompositeByName(QName.create(rpc, "input"));
228 return Futures.immediateFuture(resolveInvocationStrategy(rpc).invokeOn(rpcService, domUnwrappedInput));
229 } catch (Exception e) {
230 return Futures.immediateFailedFuture(e);
234 private RpcInvocationStrategy resolveInvocationStrategy(final QName rpc) {
235 return strategiesByQName.get(rpc);
238 private RpcInvocationStrategy createInvocationStrategy(final QName rpc,
239 final Class<? extends RpcService> rpcType, final BindingIndependentMappingService mappingService) throws Exception {
240 return ClassLoaderUtils.withClassLoader(rpcType.getClassLoader(), new Callable<RpcInvocationStrategy>() {
242 public RpcInvocationStrategy call() throws Exception {
243 String methodName = BindingMapping.getMethodName(rpc);
244 Method targetMethod = null;
245 for (Method possibleMethod : rpcType.getMethods()) {
246 if (possibleMethod.getName().equals(methodName)
247 && BindingReflections.isRpcMethod(possibleMethod)) {
248 targetMethod = possibleMethod;
252 checkState(targetMethod != null, "Rpc method not found");
253 return new RpcInvocationStrategy(rpc, targetMethod, mappingService, biRpcRegistry);
260 * Registers RPC Forwarder to Binding Broker,
261 * this means DOM Broekr has implementation of RPC
262 * which is registered to it.
264 * If RPC Forwarder was previously registered to DOM Broker
265 * or to Bidning Broker this method is noop to prevent
266 * creating forwarding loop.
269 public void registerToBindingBroker() {
270 if(!registrationInProgress && forwarderRegistration == null) {
272 registrationInProgress = true;
273 this.forwarderRegistration = baRpcRegistry.addRpcImplementation((Class)rpcServiceType.get(), proxy);
274 } catch (Exception e) {
275 LOG.error("Unable to forward RPCs for {}",rpcServiceType.get(),e);
277 registrationInProgress = false;