Integrate getRpcMethodToSchema() into constructor
[mdsal.git] / binding / mdsal-binding-dom-adapter / src / main / java / org / opendaylight / mdsal / binding / dom / adapter / RpcServiceAdapter.java
index 62e39cf17d2f8ff8fddaf7424b523b3b59a5d3f5..4d4b03937ae0fcbf230dc9ffa89bbeafdeb668f4 100644 (file)
@@ -13,10 +13,16 @@ import com.google.common.collect.ImmutableMap;
 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;
@@ -30,15 +36,40 @@ class RpcServiceAdapter implements InvocationHandler {
         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() {