import com.google.common.annotations.VisibleForTesting;
import com.google.common.collect.ClassToInstanceMap;
-import com.google.common.collect.ImmutableBiMap;
import com.google.common.collect.ImmutableClassToInstanceMap;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
-import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.Set;
import org.opendaylight.mdsal.binding.api.RpcProviderService;
-import org.opendaylight.mdsal.binding.dom.adapter.invoke.RpcMethodInvoker;
-import org.opendaylight.mdsal.binding.spec.naming.BindingMapping;
import org.opendaylight.mdsal.binding.spec.reflect.BindingReflections;
import org.opendaylight.mdsal.dom.api.DOMRpcIdentifier;
import org.opendaylight.mdsal.dom.api.DOMRpcImplementation;
import org.opendaylight.yangtools.yang.binding.Rpc;
import org.opendaylight.yangtools.yang.binding.RpcService;
import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.common.YangConstants;
import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
@VisibleForTesting
public class BindingDOMRpcProviderServiceAdapter extends AbstractBindingAdapter<DOMRpcProviderService>
implements RpcProviderService {
- private static final Logger LOG = LoggerFactory.getLogger(BindingDOMRpcProviderServiceAdapter.class);
private static final ImmutableSet<YangInstanceIdentifier> GLOBAL = ImmutableSet.of(YangInstanceIdentifier.empty());
public BindingDOMRpcProviderServiceAdapter(final AdapterContext adapterContext,
private <S extends RpcService, T extends S> ObjectRegistration<T> register(
final CurrentAdapterSerializer serializer, final Class<S> type, final T implementation,
final Collection<YangInstanceIdentifier> rpcContextPaths) {
- final var qnameToMethod = createQNameToMethod(currentSerializer(), type);
+ // FIXME: do not use BindingReflections here
+ final var inputName = YangConstants.operationInputQName(BindingReflections.getQNameModule(type)).intern();
+ final var methodHandles = currentSerializer().getRpcMethods(type);
final var builder = ImmutableMap.<DOMRpcIdentifier, DOMRpcImplementation>builderWithExpectedSize(
- qnameToMethod.size());
- for (var entry : qnameToMethod.entrySet()) {
- final var impl = new LegacyDOMRpcImplementationAdapter<>(adapterContext(), type, implementation,
- RpcMethodInvoker.from(entry.getValue()));
+ methodHandles.size());
+ for (var entry : methodHandles.entrySet()) {
+ final var impl = new LegacyDOMRpcImplementationAdapter(adapterContext(), inputName,
+ entry.getValue().bindTo(implementation));
for (var id : createDomRpcIdentifiers(Set.of(entry.getKey()), rpcContextPaths)) {
builder.put(id, impl);
}
getDelegate().registerRpcImplementations(builder.build()));
}
- @Deprecated
- @VisibleForTesting
- // FIXME: This should be probably part of Binding Runtime context
- static ImmutableMap<QName, Method> createQNameToMethod(final CurrentAdapterSerializer serializer,
- final Class<? extends RpcService> key) {
- final var moduleName = BindingReflections.getQNameModule(key);
- final var runtimeContext = serializer.getRuntimeContext();
- final var module = runtimeContext.getEffectiveModelContext().findModule(moduleName).orElse(null);
- if (module == null) {
- LOG.trace("Schema for {} is not available; expected module name: {}; BindingRuntimeContext: {}",
- key, moduleName, runtimeContext);
- throw new IllegalStateException(String.format("Schema for %s is not available; expected module name: %s;"
- + " full BindingRuntimeContext available in trace log", key, moduleName));
- }
-
- final var ret = ImmutableBiMap.<QName, Method>builder();
- try {
- for (var rpcDef : module.getRpcs()) {
- final var rpcName = rpcDef.getQName();
- ret.put(rpcName, key.getMethod(BindingMapping.getRpcMethodName(rpcName),
- runtimeContext.getRpcInput(rpcName)));
- }
- } catch (NoSuchMethodException e) {
- throw new IllegalStateException("Rpc defined in model does not have representation in generated class.", e);
- }
- return ret.build();
- }
-
private static Set<DOMRpcIdentifier> createDomRpcIdentifiers(final Set<QName> rpcs,
final Collection<YangInstanceIdentifier> paths) {
final Set<DOMRpcIdentifier> ret = new HashSet<>();
import com.google.common.cache.CacheBuilder;
import com.google.common.cache.CacheLoader;
import com.google.common.cache.LoadingCache;
+import com.google.common.collect.ImmutableBiMap;
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.Maps;
+import com.google.common.util.concurrent.ListenableFuture;
+import java.lang.invoke.MethodHandle;
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.MethodType;
+import java.lang.reflect.Method;
import java.util.Collection;
import java.util.Map;
import java.util.Map.Entry;
import org.opendaylight.mdsal.binding.dom.codec.spi.ForwardingBindingDOMCodecServices;
import org.opendaylight.mdsal.binding.model.api.JavaTypeName;
import org.opendaylight.mdsal.binding.runtime.api.InputRuntimeType;
+import org.opendaylight.mdsal.binding.spec.naming.BindingMapping;
import org.opendaylight.mdsal.binding.spec.reflect.BindingReflections;
import org.opendaylight.mdsal.dom.api.DOMDataTreeIdentifier;
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.QNameModule;
import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.AugmentationIdentifier;
import org.opendaylight.yangtools.yang.model.api.stmt.NotificationEffectiveStatement;
import org.opendaylight.yangtools.yang.model.api.stmt.SchemaNodeIdentifier.Absolute;
import org.opendaylight.yangtools.yang.model.util.SchemaInferenceStack;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
@Beta
@VisibleForTesting
public final class CurrentAdapterSerializer extends ForwardingBindingDOMCodecServices {
+ private static final Logger LOG = LoggerFactory.getLogger(CurrentAdapterSerializer.class);
+ private static final MethodType RPC_SERVICE_METHOD_SIGNATURE = MethodType.methodType(ListenableFuture.class,
+ RpcService.class, DataObject.class);
+
private final LoadingCache<InstanceIdentifier<?>, YangInstanceIdentifier> cache = CacheBuilder.newBuilder()
.softValues().build(new CacheLoader<InstanceIdentifier<?>, YangInstanceIdentifier>() {
@Override
});
private final ConcurrentMap<JavaTypeName, ContextReferenceExtractor> extractors = new ConcurrentHashMap<>();
+ @Deprecated
+ private final ConcurrentMap<Class<? extends RpcService>, ImmutableMap<QName, MethodHandle>> rpcMethods =
+ new ConcurrentHashMap<>();
private final @NonNull BindingDOMCodecServices delegate;
public CurrentAdapterSerializer(final BindingDOMCodecServices delegate) {
return raced != null ? raced : created;
}
+ @Deprecated
+ @NonNull ImmutableMap<QName, MethodHandle> getRpcMethods(final @NonNull Class<? extends RpcService> serviceType) {
+ return rpcMethods.computeIfAbsent(serviceType, ignored -> {
+ final var lookup = MethodHandles.publicLookup();
+ return ImmutableMap.copyOf(Maps.transformValues(createQNameToMethod(serviceType), method -> {
+ final MethodHandle raw;
+ try {
+ raw = lookup.unreflect(method);
+ } catch (IllegalAccessException e) {
+ throw new IllegalStateException("Lookup on public method failed", e);
+ }
+ return raw.asType(RPC_SERVICE_METHOD_SIGNATURE);
+ }));
+ });
+ }
+
+ @Deprecated
+ @VisibleForTesting
+ // FIXME: This should be probably part of Binding Runtime context
+ ImmutableMap<QName, Method> createQNameToMethod(final Class<? extends RpcService> key) {
+ final var moduleName = BindingReflections.getQNameModule(key);
+ final var runtimeContext = getRuntimeContext();
+ final var module = runtimeContext.getEffectiveModelContext().findModule(moduleName).orElse(null);
+ if (module == null) {
+ LOG.trace("Schema for {} is not available; expected module name: {}; BindingRuntimeContext: {}",
+ key, moduleName, runtimeContext);
+ throw new IllegalStateException(String.format("Schema for %s is not available; expected module name: %s;"
+ + " full BindingRuntimeContext available in trace log", key, moduleName));
+ }
+
+ final var ret = ImmutableBiMap.<QName, Method>builder();
+ try {
+ for (var rpcDef : module.getRpcs()) {
+ final var rpcName = rpcDef.getQName();
+ ret.put(rpcName, key.getMethod(BindingMapping.getRpcMethodName(rpcName),
+ runtimeContext.getRpcInput(rpcName)));
+ }
+ } catch (NoSuchMethodException e) {
+ throw new IllegalStateException("Rpc defined in model does not have representation in generated class.", e);
+ }
+ return ret.build();
+ }
+
private @NonNull Entry<SchemaInferenceStack, QNameModule> resolvePath(final @NonNull InstanceIdentifier<?> path) {
final var stack = SchemaInferenceStack.of(getRuntimeContext().getEffectiveModelContext());
final var it = toYangInstanceIdentifier(path).getPathArguments().iterator();
import static java.util.Objects.requireNonNull;
+import com.google.common.base.Throwables;
import com.google.common.util.concurrent.ListenableFuture;
-import org.opendaylight.mdsal.binding.dom.adapter.invoke.RpcMethodInvoker;
-import org.opendaylight.mdsal.binding.spec.reflect.BindingReflections;
+import java.lang.invoke.MethodHandle;
import org.opendaylight.mdsal.dom.api.DOMRpcIdentifier;
-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.schema.ContainerNode;
@Deprecated(since = "11.0.0", forRemoval = true)
-final class LegacyDOMRpcImplementationAdapter<T extends RpcService> extends AbstractDOMRpcImplementationAdapter {
- private final RpcMethodInvoker invoker;
- private final T delegate;
+final class LegacyDOMRpcImplementationAdapter extends AbstractDOMRpcImplementationAdapter {
+ private final MethodHandle handle;
- LegacyDOMRpcImplementationAdapter(final AdapterContext adapterContext, final Class<T> type, final T delegate,
- final RpcMethodInvoker invoker) {
- // FIXME: do not use BindingReflections here
- super(adapterContext, YangConstants.operationInputQName(BindingReflections.getQNameModule(type)).intern());
- this.delegate = requireNonNull(delegate);
- this.invoker = requireNonNull(invoker);
+ LegacyDOMRpcImplementationAdapter(final AdapterContext adapterContext, final QName inputName,
+ final MethodHandle handle) {
+ super(adapterContext, inputName);
+ this.handle = requireNonNull(handle);
}
@Override
+ @SuppressWarnings("checkstyle:illegalCatch")
ListenableFuture<RpcResult<?>> invokeRpc(final CurrentAdapterSerializer serializer, final DOMRpcIdentifier rpc,
final ContainerNode input) {
- return invoker.invokeOn(delegate, deserialize(serializer, rpc.getType(), input));
+ try {
+ return (ListenableFuture<RpcResult<?>>) handle.invokeExact(deserialize(serializer, rpc.getType(), input));
+ } catch (Throwable e) {
+ Throwables.throwIfUnchecked(e);
+ throw new IllegalStateException(e);
+ }
}
}
+++ /dev/null
-/*
- * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.
- *
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0 which accompanies this distribution,
- * and is available at http://www.eclipse.org/legal/epl-v10.html
- */
-package org.opendaylight.mdsal.binding.dom.adapter.invoke;
-
-import com.google.common.annotations.VisibleForTesting;
-import com.google.common.base.Throwables;
-import com.google.common.util.concurrent.ListenableFuture;
-import java.lang.invoke.MethodHandle;
-import java.lang.invoke.MethodHandles;
-import java.lang.invoke.MethodType;
-import java.lang.reflect.Method;
-import org.eclipse.jdt.annotation.NonNull;
-import org.opendaylight.yangtools.yang.binding.DataObject;
-import org.opendaylight.yangtools.yang.binding.RpcService;
-import org.opendaylight.yangtools.yang.common.RpcResult;
-
-@Deprecated(since = "11.0.0", forRemoval = true)
-public final class RpcMethodInvoker {
- private static final MethodType INVOCATION_SIGNATURE = MethodType.methodType(ListenableFuture.class,
- RpcService.class, DataObject.class);
-
- private final MethodHandle handle;
-
- @VisibleForTesting
- RpcMethodInvoker(final MethodHandle handle) {
- this.handle = handle.asType(INVOCATION_SIGNATURE);
- }
-
- public static @NonNull RpcMethodInvoker from(final Method method) {
- try {
- return new RpcMethodInvoker(MethodHandles.publicLookup().unreflect(method));
- } catch (IllegalAccessException e) {
- throw new IllegalStateException("Lookup on public method failed.", e);
- }
- }
-
- @SuppressWarnings("checkstyle:illegalCatch")
- public @NonNull ListenableFuture<RpcResult<?>> invokeOn(final RpcService impl, final DataObject input) {
- try {
- return (ListenableFuture<RpcResult<?>>) handle.invokeExact(impl, input);
- } catch (Throwable e) {
- Throwables.throwIfUnchecked(e);
- throw new IllegalStateException(e);
- }
- }
-}
@Test
public void testGetRpcMethodToQName() {
- assertTrue(
- BindingDOMRpcProviderServiceAdapter.createQNameToMethod(serializer,
- OpendaylightTestRpcServiceService.class)
+ assertTrue(serializer.createQNameToMethod(OpendaylightTestRpcServiceService.class)
.values().stream()
.map(Method::getName)
.anyMatch("rockTheHouse"::equals));
+++ /dev/null
-/*
- * Copyright (c) 2016 Cisco Systems, Inc. and others. All rights reserved.
- *
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0 which accompanies this distribution,
- * and is available at http://www.eclipse.org/legal/epl-v10.html
- */
-package org.opendaylight.mdsal.binding.dom.adapter.invoke;
-
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertThrows;
-
-import com.google.common.util.concurrent.Futures;
-import com.google.common.util.concurrent.ListenableFuture;
-import java.lang.invoke.MethodHandle;
-import java.lang.invoke.MethodHandles;
-import org.junit.Test;
-import org.opendaylight.yangtools.yang.binding.DataObject;
-import org.opendaylight.yangtools.yang.binding.RpcService;
-
-@Deprecated(since = "11.0.0", forRemoval = true)
-public class RpcMethodInvokerTest {
- private static final TestImplClassWithInput TEST_IMPL_CLASS = new TestImplClassWithInput();
-
- @Test
- public void invokeOnTest() throws Exception {
- final MethodHandle methodHandle = MethodHandles.lookup().unreflect(
- TestImplClassWithInput.class.getDeclaredMethod("testMethod", RpcService.class, DataObject.class));
- final RpcMethodInvoker rpcMethodInvokerWithInput = new RpcMethodInvoker(methodHandle);
- assertNotNull(rpcMethodInvokerWithInput.invokeOn(TEST_IMPL_CLASS, null));
- }
-
- @Test
- public void invokeOnWithException() throws Exception {
- final MethodHandle methodHandle = MethodHandles.lookup().unreflect(TestImplClassWithInput.class
- .getDeclaredMethod("testMethodWithException", RpcService.class, DataObject.class));
- final RpcMethodInvoker rpcMethodInvokerWithInput = new RpcMethodInvoker(methodHandle);
-
- assertThrows(InternalError.class, () -> rpcMethodInvokerWithInput.invokeOn(TEST_IMPL_CLASS, null));
- }
-
- static final class TestImplClassWithInput implements RpcService {
-
- static ListenableFuture<?> testMethod(final RpcService testArg, final DataObject data) {
- return Futures.immediateFuture(null);
- }
-
- static ListenableFuture<?> testMethodWithException(final RpcService testArg, final DataObject data) {
- throw new InternalError();
- }
- }
-}
\ No newline at end of file