package org.opendaylight.mdsal.binding.dom.adapter;
import com.google.common.base.Function;
+import com.google.common.base.Optional;
import com.google.common.base.Preconditions;
import com.google.common.collect.ImmutableMap;
import com.google.common.util.concurrent.CheckedFuture;
protected RoutedStrategy(final SchemaPath path, final Method rpcMethod, final QName leafName) {
super(path);
- final Class<? extends DataContainer> inputType = BindingReflections.resolveRpcInputClass(rpcMethod).get();
+ final Optional<Class<? extends DataContainer>> maybeInputType =
+ BindingReflections.resolveRpcInputClass(rpcMethod);
+ Preconditions.checkState(maybeInputType.isPresent(), "RPC method %s has no input", rpcMethod.getName());
+ final Class<? extends DataContainer> inputType = maybeInputType.get();
refExtractor = ContextReferenceExtractor.from(inputType);
this.contextName = new NodeIdentifier(leafName);
}
@Override
public final Future<RpcResult<?>> invokeRpc(@Nonnull final RpcService impl, @Nonnull final QName rpcName, @Nullable final DataObject input) {
- Preconditions.checkNotNull(impl, "implemetation must be supplied");
+ Preconditions.checkNotNull(impl, "Implementation must be supplied");
RpcMethodInvoker invoker = map.get(qnameToKey(rpcName));
Preconditions.checkArgument(invoker != null, "Supplied RPC is not valid for implementation %s", impl);
/**
* Checks if method is RPC invocation
*
- *
- *
* @param possibleMethod
* Method to check
* @return true if method is RPC invocation, false otherwise.
public static boolean isRpcMethod(final Method possibleMethod) {
return possibleMethod != null && RpcService.class.isAssignableFrom(possibleMethod.getDeclaringClass())
&& Future.class.isAssignableFrom(possibleMethod.getReturnType())
- && possibleMethod.getParameterTypes().length <= 1;
+ // length <= 2: it seemed to be impossible to get correct RpcMethodInvoker because of
+ // resolveRpcInputClass() check.While RpcMethodInvoker counts with one argument for
+ // non input type and two arguments for input type, resolveRpcInputClass() counting
+ // with zero for non input and one for input type
+ && possibleMethod.getParameterTypes().length <= 2;
}
/**
*/
@SuppressWarnings("rawtypes")
public static Optional<Class<?>> resolveRpcOutputClass(final Method targetMethod) {
- checkState(isRpcMethod(targetMethod), "Supplied method is not Rpc invocation method");
+ checkState(isRpcMethod(targetMethod), "Supplied method is not a RPC invocation method");
Type futureType = targetMethod.getGenericReturnType();
Type rpcResultType = ClassLoaderUtils.getFirstGenericParameter(futureType);
Type rpcResultArgument = ClassLoaderUtils.getFirstGenericParameter(rpcResultType);
if (rpcResultArgument instanceof Class && !Void.class.equals(rpcResultArgument)) {
- return Optional.<Class<?>> of((Class) rpcResultArgument);
+ return Optional.of((Class) rpcResultArgument);
}
return Optional.absent();
}
* method to scan
* @return Optional.absent() if rpc has no input, Rpc input type otherwise.
*/
- @SuppressWarnings("unchecked")
+ @SuppressWarnings("rawtypes")
public static Optional<Class<? extends DataContainer>> resolveRpcInputClass(final Method targetMethod) {
- @SuppressWarnings("rawtypes")
- Class[] types = targetMethod.getParameterTypes();
- if (types.length == 0) {
- return Optional.absent();
- }
- if (types.length == 1) {
- return Optional.<Class<? extends DataContainer>> of(types[0]);
+ for (Class clazz : targetMethod.getParameterTypes()) {
+ if (DataContainer.class.isAssignableFrom(clazz)) {
+ return Optional.of(clazz);
+ }
}
- throw new IllegalArgumentException("Method has 2 or more arguments.");
+ return Optional.absent();
}
public static QName getQName(final Class<? extends BaseIdentity> context) {
* @return Set of {@link YangModuleInfo} available for supplied classloader.
*/
public static ImmutableSet<YangModuleInfo> loadModuleInfos(final ClassLoader loader) {
- Builder<YangModuleInfo> moduleInfoSet = ImmutableSet.<YangModuleInfo> builder();
+ Builder<YangModuleInfo> moduleInfoSet = ImmutableSet.builder();
ServiceLoader<YangModelBindingProvider> serviceLoader = ServiceLoader.load(YangModelBindingProvider.class,
loader);
for (YangModelBindingProvider bindingProvider : serviceLoader) {
@SuppressWarnings("rawtypes")
Class returnType = method.getReturnType();
if (DataContainer.class.isAssignableFrom(returnType)) {
- return Optional.<Class<? extends DataContainer>> of(returnType);
+ return Optional.of(returnType);
} else if (List.class.isAssignableFrom(returnType)) {
try {
return ClassLoaderUtils.withClassLoader(method.getDeclaringClass().getClassLoader(),
Type listResult = ClassLoaderUtils.getFirstGenericParameter(method.getGenericReturnType());
if (listResult instanceof Class
&& DataContainer.class.isAssignableFrom((Class) listResult)) {
- return Optional.<Class<? extends DataContainer>> of((Class) listResult);
+ return Optional.of((Class) listResult);
}
return Optional.absent();
});
private static class ClassToQNameLoader extends CacheLoader<Class<?>, Optional<QName>> {
@Override
- public Optional<QName> load(final Class<?> key) throws Exception {
+ public Optional<QName> load(@SuppressWarnings("NullableProblems") final Class<?> key) throws Exception {
return resolveQNameNoCache(key);
}
} catch (IllegalAccessException e) {
throw new IllegalStateException("Lookup on public method failed.",e);
}
-
}
-}
+}
\ No newline at end of file
class RpcMethodInvokerWithInput extends RpcMethodInvoker {
- private static final MethodType INVOCATION_SIGNATURE = MethodType.methodType(Future.class, RpcService.class,DataObject.class);
+ private static final MethodType INVOCATION_SIGNATURE =
+ MethodType.methodType(Future.class, RpcService.class, DataObject.class);
private final MethodHandle handle;
RpcMethodInvokerWithInput(MethodHandle methodHandle) {
--- /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.yangtools.yang.binding.util;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Mockito.mock;
+
+import com.google.common.collect.ImmutableMap;
+import com.google.common.util.concurrent.Futures;
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
+import java.util.Map;
+import java.util.Optional;
+import java.util.concurrent.Future;
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+import org.junit.Test;
+import org.opendaylight.yangtools.yang.binding.DataObject;
+import org.opendaylight.yangtools.yang.binding.RpcService;
+import org.opendaylight.yangtools.yang.common.QName;
+
+public class AbstractMappedRpcInvokerTest {
+
+ @Test
+ public void invokeRpcTest() throws Exception {
+ final Method methodWithoutInput =
+ TestRpcService.class.getDeclaredMethod("methodWithoutInput", RpcService.class);
+ final Method methodWithInput =
+ TestRpcService.class.getDeclaredMethod("methodWithInput", RpcService.class, DataObject.class);
+
+ methodWithInput.setAccessible(true);
+ methodWithoutInput.setAccessible(true);
+
+ final RpcService rpcService = new TestRpcService();
+
+ final RpcServiceInvoker testRpcInvoker =
+ new TestRpcInvokerImpl(ImmutableMap.of(
+ "tstWithoutInput", methodWithoutInput,
+ "tstWithInput", methodWithInput));
+
+ final Field testInvokerMapField = testRpcInvoker.getClass().getSuperclass().getDeclaredField("map");
+ testInvokerMapField.setAccessible(true);
+ final Map<String, RpcMethodInvoker> testInvokerMap =
+ (Map<String, RpcMethodInvoker>) testInvokerMapField.get(testRpcInvoker);
+
+ assertTrue(testInvokerMap.get("tstWithInput") instanceof RpcMethodInvokerWithInput);
+ assertTrue(testInvokerMap.get("tstWithoutInput") instanceof RpcMethodInvokerWithoutInput);
+
+ final Crate crateWithoutInput =
+ (Crate) testRpcInvoker.invokeRpc(rpcService, QName.create("tstWithoutInput"), null).get();
+ assertEquals(TestRpcService.methodWithoutInput(rpcService).get().getRpcService(),
+ crateWithoutInput.getRpcService());
+ assertFalse(crateWithoutInput.getDataObject().isPresent());
+
+ final DataObject dataObject = mock(DataObject.class);
+ final Crate crateWithInput =
+ (Crate) testRpcInvoker.invokeRpc(rpcService, QName.create("tstWithInput"), dataObject).get();
+ assertEquals(TestRpcService.methodWithInput(rpcService, dataObject).get().getRpcService(),
+ crateWithInput.getRpcService());
+ assertTrue(crateWithInput.getDataObject().isPresent());
+ assertEquals(dataObject, crateWithInput.getDataObject().get());
+ }
+
+ private class TestRpcInvokerImpl extends AbstractMappedRpcInvoker<String> {
+
+ TestRpcInvokerImpl(Map<String, Method> map) {
+ super(map);
+ }
+
+ @Override
+ protected String qnameToKey(QName qname) {
+ return qname.toString();
+ }
+ }
+
+ static class Crate {
+ private final RpcService rpcService;
+ private final ThreadLocal<Optional<DataObject>> dataObject;
+
+ Crate(@Nonnull RpcService rpcService, @Nullable DataObject dataObject) {
+ this.rpcService = rpcService;
+ this.dataObject = new ThreadLocal<Optional<DataObject>>() {
+ @Override
+ protected Optional<DataObject> initialValue() {
+ return dataObject == null ? Optional.empty() : Optional.of(dataObject);
+ }
+ };
+ }
+
+ RpcService getRpcService() {
+ return this.rpcService;
+ }
+
+ Optional<DataObject> getDataObject() {
+ return this.dataObject.get();
+ }
+ }
+
+ static class TestRpcService implements RpcService {
+ static Future<Crate> methodWithoutInput(RpcService testArgument) {
+ return Futures.immediateFuture(new Crate(testArgument, null));
+ }
+
+ static Future<Crate> methodWithInput(RpcService testArgument, DataObject testArgument2) {
+ return Futures.immediateFuture(new Crate(testArgument, testArgument2));
+ }
+ }
+}
+