import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
+import java.util.Map;
+import java.util.Map.Entry;
import org.eclipse.jdt.annotation.NonNull;
+import org.opendaylight.mdsal.binding.runtime.api.RpcRuntimeType;
+import org.opendaylight.mdsal.binding.spec.naming.BindingMapping;
+import org.opendaylight.mdsal.binding.spec.reflect.BindingReflections;
import org.opendaylight.mdsal.dom.api.DOMRpcService;
import org.opendaylight.yangtools.yang.binding.DataObject;
import org.opendaylight.yangtools.yang.binding.RpcService;
+import org.opendaylight.yangtools.yang.model.api.stmt.RpcEffectiveStatement;
class RpcServiceAdapter implements InvocationHandler {
private final ImmutableMap<Method, RpcInvocationStrategy> rpcNames;
this.type = requireNonNull(type);
this.adapterContext = requireNonNull(adapterContext);
delegate = requireNonNull(domService);
-
- final var methods = adapterContext.currentSerializer().getRpcMethodToSchema(type);
- final var rpcBuilder = ImmutableMap.<Method, RpcInvocationStrategy>builderWithExpectedSize(methods.size());
- for (var rpc : methods.entrySet()) {
- final var method = rpc.getKey();
- rpcBuilder.put(method, RpcInvocationStrategy.of(this, method, rpc.getValue().asEffectiveStatement()));
- }
- rpcNames = rpcBuilder.build();
facade = (RpcService) Proxy.newProxyInstance(type.getClassLoader(), new Class[] {type}, this);
+
+ // FIXME: This should be probably part of BindingRuntimeContext and RpcServices perhaps should have their own
+ // RuntimeType. At any rate, we are dancing around to reconstruct information RpcServiceRuntimeType would
+ // carry and the runtime context would bind to actual classes.
+ final var serializer = adapterContext.currentSerializer();
+ final var runtimeContext = serializer.getRuntimeContext();
+ final var types = runtimeContext.getTypes();
+ final var qnameModule = BindingReflections.getQNameModule(type);
+
+ // We are dancing a bit here to reconstruct things a RpcServiceRuntimeType could easily hold
+ final var module = runtimeContext.getEffectiveModelContext().findModuleStatement(qnameModule)
+ .orElseThrow(() -> new IllegalStateException("No module found for " + qnameModule + " service " + type));
+ rpcNames = module.streamEffectiveSubstatements(RpcEffectiveStatement.class)
+ .map(rpc -> {
+ final var rpcName = rpc.argument();
+ final var inputClz = runtimeContext.getRpcInput(rpcName);
+ final var methodName = BindingMapping.getRpcMethodName(rpcName);
+
+ final Method method;
+ try {
+ method = type.getMethod(methodName, inputClz);
+ } catch (NoSuchMethodException e) {
+ throw new IllegalStateException("Cannot find RPC method for " + rpc, e);
+ }
+
+ final var runtimeType = types.schemaTreeChild(rpcName);
+ if (!(runtimeType instanceof RpcRuntimeType rpcType)) {
+ throw new IllegalStateException("Unexpected run-time type " + runtimeType + " for " + rpcName);
+ }
+
+ return Map.entry(method, RpcInvocationStrategy.of(this, method, rpcType));
+ })
+ .collect(ImmutableMap.toImmutableMap(Entry::getKey, Entry::getValue));
}
final @NonNull CurrentAdapterSerializer currentSerializer() {