X-Git-Url: https://git.opendaylight.org/gerrit/gitweb?a=blobdiff_plain;f=binding%2Fmdsal-binding-dom-adapter%2Fsrc%2Fmain%2Fjava%2Forg%2Fopendaylight%2Fmdsal%2Fbinding%2Fdom%2Fadapter%2FRpcServiceAdapter.java;h=18b2f2e41fdb324a51f61c924f7a4e318782505e;hb=1366c55dcdfba3248d1c62ecb221a3b0c325fc99;hp=c476ce0d2b0ee0c9bc2f260b598d1ed305a4d69b;hpb=7d2244383a8218a62e1fc1acbb24796b8547f1e4;p=mdsal.git diff --git a/binding/mdsal-binding-dom-adapter/src/main/java/org/opendaylight/mdsal/binding/dom/adapter/RpcServiceAdapter.java b/binding/mdsal-binding-dom-adapter/src/main/java/org/opendaylight/mdsal/binding/dom/adapter/RpcServiceAdapter.java index c476ce0d2b..18b2f2e41f 100644 --- a/binding/mdsal-binding-dom-adapter/src/main/java/org/opendaylight/mdsal/binding/dom/adapter/RpcServiceAdapter.java +++ b/binding/mdsal-binding-dom-adapter/src/main/java/org/opendaylight/mdsal/binding/dom/adapter/RpcServiceAdapter.java @@ -8,84 +8,66 @@ package org.opendaylight.mdsal.binding.dom.adapter; import static java.util.Objects.requireNonNull; -import static org.opendaylight.mdsal.binding.dom.adapter.StaticConfiguration.ENABLE_CODEC_SHORTCUT; -import com.google.common.base.Preconditions; +import com.google.common.collect.ImmutableBiMap; import com.google.common.collect.ImmutableMap; -import com.google.common.util.concurrent.Futures; -import com.google.common.util.concurrent.ListenableFuture; -import com.google.common.util.concurrent.MoreExecutors; 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 java.util.Optional; -import org.opendaylight.mdsal.binding.dom.codec.api.BindingNormalizedNodeSerializer; +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.DOMRpcResult; import org.opendaylight.mdsal.dom.api.DOMRpcService; -import org.opendaylight.mdsal.dom.spi.RpcRoutingStrategy; -import org.opendaylight.yangtools.yang.binding.DataContainer; import org.opendaylight.yangtools.yang.binding.DataObject; -import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; import org.opendaylight.yangtools.yang.binding.RpcService; -import org.opendaylight.yangtools.yang.common.QName; -import org.opendaylight.yangtools.yang.common.RpcResult; -import org.opendaylight.yangtools.yang.common.YangConstants; -import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier; -import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier; -import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode; -import org.opendaylight.yangtools.yang.data.api.schema.LeafNode; -import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode; -import org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNodes; -import org.opendaylight.yangtools.yang.model.api.RpcDefinition; -import org.opendaylight.yangtools.yang.model.api.SchemaPath; +import org.opendaylight.yangtools.yang.model.api.stmt.RpcEffectiveStatement; class RpcServiceAdapter implements InvocationHandler { private final ImmutableMap rpcNames; - private final Class type; - private final BindingToNormalizedNodeCodec codec; - private final DOMRpcService delegate; - private final RpcService proxy; + private final @NonNull Class type; + private final @NonNull AdapterContext adapterContext; + private final @NonNull DOMRpcService delegate; + private final @NonNull RpcService facade; - RpcServiceAdapter(final Class type, final BindingToNormalizedNodeCodec codec, + RpcServiceAdapter(final Class type, final AdapterContext adapterContext, final DOMRpcService domService) { this.type = requireNonNull(type); - this.codec = requireNonNull(codec); - this.delegate = requireNonNull(domService); - final ImmutableMap.Builder rpcBuilder = ImmutableMap.builder(); - for (final Entry rpc : codec.getRpcMethodToSchema(type).entrySet()) { - rpcBuilder.put(rpc.getKey(), createStrategy(rpc.getKey(), rpc.getValue())); + this.adapterContext = requireNonNull(adapterContext); + delegate = requireNonNull(domService); + facade = (RpcService) Proxy.newProxyInstance(type.getClassLoader(), new Class[] {type}, this); + + final var methods = getRpcMethodToSchema(adapterContext.currentSerializer(), type); + final var rpcBuilder = ImmutableMap.builderWithExpectedSize(methods.size()); + for (var entry : methods.entrySet()) { + final var method = entry.getKey(); + rpcBuilder.put(method, RpcInvocationStrategy.of(this, method, entry.getValue())); } rpcNames = rpcBuilder.build(); - proxy = (RpcService) Proxy.newProxyInstance(type.getClassLoader(), new Class[] {type}, this); } - private RpcInvocationStrategy createStrategy(final Method method, final RpcDefinition schema) { - final RpcRoutingStrategy strategy = RpcRoutingStrategy.from(schema); - if (strategy.isContextBasedRouted()) { - return new RoutedStrategy(schema.getPath(), method, strategy.getLeaf()); - } - return new NonRoutedStrategy(schema.getPath()); + final @NonNull CurrentAdapterSerializer currentSerializer() { + return adapterContext.currentSerializer(); } - RpcService getProxy() { - return proxy; + final @NonNull DOMRpcService delegate() { + return delegate; } - @Override - @SuppressWarnings("checkstyle:hiddenField") - public Object invoke(final Object proxy, final Method method, final Object[] args) throws Throwable { + final @NonNull RpcService facade() { + return facade; + } - final RpcInvocationStrategy rpc = rpcNames.get(method); - if (rpc != null) { - if (method.getParameterCount() == 0) { - return rpc.invokeEmpty(); - } + @Override + public Object invoke(final Object proxy, final Method method, final Object[] args) { + final var strategy = rpcNames.get(method); + if (strategy != null) { if (args.length != 1) { throw new IllegalArgumentException("Input must be provided."); } - return rpc.invoke((DataObject) args[0]); + return strategy.invoke((DataObject) requireNonNull(args[0])); } switch (method.getName()) { @@ -112,94 +94,36 @@ class RpcServiceAdapter implements InvocationHandler { throw new UnsupportedOperationException("Method " + method.toString() + "is unsupported."); } - private abstract class RpcInvocationStrategy { - - private final SchemaPath rpcName; - - protected RpcInvocationStrategy(final SchemaPath path) { - rpcName = path; - } - - final ListenableFuture> invoke(final DataObject input) { - return invoke0(rpcName, serialize(input)); - } - - abstract ContainerNode serialize(DataObject input); - - final ListenableFuture> invokeEmpty() { - return invoke0(rpcName, null); - } - - final SchemaPath getRpcName() { - return rpcName; - } - - ListenableFuture> invoke0(final SchemaPath schemaPath, final ContainerNode input) { - final ListenableFuture result = delegate.invokeRpc(schemaPath, input); - if (ENABLE_CODEC_SHORTCUT && result instanceof BindingRpcFutureAware) { - return ((BindingRpcFutureAware) result).getBindingFuture(); - } - - return transformFuture(schemaPath, result, codec.getCodecFactory()); - } - - private ListenableFuture> transformFuture(final SchemaPath rpc, - final ListenableFuture domFuture, final BindingNormalizedNodeSerializer resultCodec) { - return Futures.transform(domFuture, input -> { - final NormalizedNode domData = input.getResult(); - final DataObject bindingResult; - if (domData != null) { - final SchemaPath rpcOutput = rpc.createChild(YangConstants.operationOutputQName( - rpc.getLastComponent().getModule())); - bindingResult = resultCodec.fromNormalizedNodeRpcData(rpcOutput, (ContainerNode) domData); - } else { - bindingResult = null; + // FIXME: This should be probably part of BindingRuntimeContext and RpcServices perhaps should have their own + // RuntimeType + private static ImmutableBiMap getRpcMethodToSchema( + final CurrentAdapterSerializer serializer, final Class key) { + final var runtimeContext = serializer.getRuntimeContext(); + final var types = runtimeContext.getTypes(); + final var qnameModule = BindingReflections.getQNameModule(key); + + // 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 " + key)); + return 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 = key.getMethod(methodName, inputClz); + } catch (NoSuchMethodException e) { + throw new IllegalStateException("Cannot find RPC method for " + rpc, e); } - return RpcResultUtil.rpcResultFromDOM(input.getErrors(), bindingResult); - }, MoreExecutors.directExecutor()); - } - } - - private final class NonRoutedStrategy extends RpcInvocationStrategy { - - protected NonRoutedStrategy(final SchemaPath path) { - super(path); - } - - @Override - ContainerNode serialize(final DataObject input) { - return LazySerializedContainerNode.create(getRpcName(), input, codec.getCodecRegistry()); - } - - } - - private final class RoutedStrategy extends RpcInvocationStrategy { - - private final ContextReferenceExtractor refExtractor; - private final NodeIdentifier contextName; - - protected RoutedStrategy(final SchemaPath path, final Method rpcMethod, final QName leafName) { - super(path); - final Optional> maybeInputType = - BindingReflections.resolveRpcInputClass(rpcMethod); - Preconditions.checkState(maybeInputType.isPresent(), "RPC method %s has no input", rpcMethod.getName()); - final Class inputType = maybeInputType.get(); - refExtractor = ContextReferenceExtractor.from(inputType); - this.contextName = new NodeIdentifier(leafName); - } - - @Override - ContainerNode serialize(final DataObject input) { - final InstanceIdentifier bindingII = refExtractor.extract(input); - if (bindingII != null) { - final YangInstanceIdentifier yangII = codec.toYangInstanceIdentifierCached(bindingII); - final LeafNode contextRef = ImmutableNodes.leafNode(contextName, yangII); - return LazySerializedContainerNode.withContextRef(getRpcName(), input, contextRef, - codec.getCodecRegistry()); - } - return LazySerializedContainerNode.create(getRpcName(), input, codec.getCodecRegistry()); - } - + final var type = types.schemaTreeChild(rpcName); + if (!(type instanceof RpcRuntimeType rpcType)) { + throw new IllegalStateException("Unexpected run-time type " + type + " for " + rpcName); + } + return Map.entry(method, rpcType); + }) + .collect(ImmutableBiMap.toImmutableBiMap(Entry::getKey, Entry::getValue)); } }