import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture;
+import org.opendaylight.mdsal.dom.api.DOMActionImplementation;
import org.opendaylight.mdsal.dom.api.DOMActionNotAvailableException;
import org.opendaylight.mdsal.dom.api.DOMDataTreeIdentifier;
import org.opendaylight.mdsal.dom.api.DOMRpcIdentifier;
+import org.opendaylight.mdsal.dom.api.DOMRpcImplementation;
import org.opendaylight.mdsal.dom.api.DOMRpcImplementationNotAvailableException;
import org.opendaylight.mdsal.dom.api.DOMRpcResult;
+import org.opendaylight.mdsal.dom.api.DefaultDOMRpcException;
import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNodes;
}
}
- return impls.get(0).invokeAction(type, path, input);
+ return invokeAction(impls.get(0), type, path, input);
}
static ListenableFuture<? extends DOMRpcResult> invoke(final AbstractDOMRpcRoutingTableEntry entry,
// Find a DOMRpcImplementation for a specific iid
final var specificImpls = entry.getImplementations(iid);
if (specificImpls != null) {
- return specificImpls.get(0)
- .invokeRpc(DOMRpcIdentifier.create(entry.getType(), iid), input);
+ return invokeRpc(specificImpls.get(0), DOMRpcIdentifier.create(entry.getType(), iid), input);
}
LOG.debug("No implementation for context {} found will now look for wildcard id", iid);
// implementation this way
final var mayBeRemoteImpls = entry.getImplementations(YangInstanceIdentifier.of());
if (mayBeRemoteImpls != null) {
- return mayBeRemoteImpls.get(0)
- .invokeRpc(DOMRpcIdentifier.create(entry.getType(), iid), input);
+ return invokeRpc(mayBeRemoteImpls.get(0), DOMRpcIdentifier.create(entry.getType(), iid), input);
}
-
} else {
LOG.warn("Ignoring wrong context value {}", value);
}
final var impls = entry.getImplementations(null);
if (impls != null) {
- return impls.get(0).invokeRpc(entry.getRpcId(), input);
+ return invokeRpc(impls.get(0), entry.getRpcId(), input);
}
return Futures.immediateFailedFuture(new DOMRpcImplementationNotAvailableException(
private static ListenableFuture<? extends DOMRpcResult> invokeGlobalRpc(
final GlobalDOMRpcRoutingTableEntry entry, final ContainerNode input) {
- return entry.getImplementations(YangInstanceIdentifier.of()).get(0).invokeRpc(entry.getRpcId(), input);
+ return invokeRpc(entry.getImplementations(YangInstanceIdentifier.of()).get(0), entry.getRpcId(), input);
+ }
+
+ @SuppressWarnings("checkstyle:illegalCatch")
+ private static ListenableFuture<? extends DOMRpcResult> invokeAction(final DOMActionImplementation impl,
+ final Absolute type, final DOMDataTreeIdentifier path, final ContainerNode input) {
+ try {
+ return impl.invokeAction(type, path, input);
+ } catch (Exception e) {
+ LOG.debug("{} failed on {} with {}", impl, path, input.prettyTree(), e);
+ return Futures.immediateFailedFuture(new DefaultDOMRpcException("Action implementation failed: " + e, e));
+ }
+ }
+
+ @SuppressWarnings("checkstyle:illegalCatch")
+ private static ListenableFuture<? extends DOMRpcResult> invokeRpc(final DOMRpcImplementation impl,
+ final DOMRpcIdentifier rpc, final ContainerNode input) {
+ try {
+ return impl.invokeRpc(rpc, input);
+ } catch (Exception e) {
+ LOG.debug("{} failed on {} with {}", impl, rpc, input.prettyTree(), e);
+ return Futures.immediateFailedFuture(new DefaultDOMRpcException("RPC implementation failed: " + e, e));
+ }
}
}
\ No newline at end of file
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotEquals;
import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertSame;
import static org.junit.Assert.assertThrows;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.doCallRealMethod;
import org.opendaylight.mdsal.dom.api.DOMActionService;
import org.opendaylight.mdsal.dom.api.DOMDataTreeIdentifier;
import org.opendaylight.mdsal.dom.api.DOMRpcAvailabilityListener;
+import org.opendaylight.mdsal.dom.api.DOMRpcException;
import org.opendaylight.mdsal.dom.api.DOMRpcIdentifier;
import org.opendaylight.mdsal.dom.api.DOMRpcImplementationNotAvailableException;
import org.opendaylight.mdsal.dom.api.DOMRpcResult;
import org.opendaylight.mdsal.dom.api.DOMSchemaService;
+import org.opendaylight.mdsal.dom.api.DefaultDOMRpcException;
import org.opendaylight.mdsal.dom.spi.DefaultDOMRpcResult;
import org.opendaylight.yangtools.concepts.Registration;
import org.opendaylight.yangtools.yang.common.QName;
@Test
public void testFailedInvokeRpc() {
try (var rpcRouter = rpcsRouter()) {
- final ListenableFuture<?> future = rpcRouter.rpcService().invokeRpc(Rpcs.FOO, null);
- final Throwable cause = assertThrows(ExecutionException.class, () -> Futures.getDone(future)).getCause();
+ final var input = ImmutableNodes.newContainerBuilder()
+ .withNodeIdentifier(new NodeIdentifier(Actions.INPUT))
+ .build();
+ final var thrown = new RuntimeException("mumble-mumble");
+
+ try (var reg = rpcRouter.rpcProviderService().registerRpcImplementation(
+ (rpc, unused) -> {
+ throw thrown;
+ }, DOMRpcIdentifier.create(Rpcs.FOO))) {
+
+ final var future = rpcRouter.rpcService().invokeRpc(Rpcs.FOO, input);
+ final var cause = assertThrows(ExecutionException.class, () -> Futures.getDone(future)).getCause();
+ assertThat(cause, instanceOf(DefaultDOMRpcException.class));
+ assertEquals("RPC implementation failed: java.lang.RuntimeException: mumble-mumble",
+ cause.getMessage());
+ assertSame(thrown, cause.getCause());
+ }
+
+ final var future = rpcRouter.rpcService().invokeRpc(Rpcs.FOO, input);
+ final var cause = assertThrows(ExecutionException.class, () -> Futures.getDone(future)).getCause();
assertThat(cause, instanceOf(DOMRpcImplementationNotAvailableException.class));
assertEquals("No implementation of RPC (rpcs)foo available", cause.getMessage());
}
}
}
+ @Test
+ public void testActionInstanceThrowing() throws ExecutionException {
+ try (var rpcRouter = actionsRouter()) {
+ final var actionProvider = rpcRouter.actionProviderService();
+ assertNotNull(actionProvider);
+ final var actionConsumer = rpcRouter.actionService();
+ assertNotNull(actionConsumer);
+
+ final var thrown = new RuntimeException("test-two-three");
+
+ try (var reg = actionProvider.registerActionImplementation(
+ (type, path, input) -> {
+ throw thrown;
+ }, DOMActionInstance.of(Actions.BAZ_TYPE, LogicalDatastoreType.OPERATIONAL, BAZ_PATH_GOOD))) {
+
+ final var future = invokeBaz(actionConsumer, BAZ_PATH_GOOD);
+ final var ex = assertThrows(ExecutionException.class, () -> Futures.getDone(future)).getCause();
+ assertThat(ex, instanceOf(DOMRpcException.class));
+ assertEquals("Action implementation failed: java.lang.RuntimeException: test-two-three",
+ ex.getMessage());
+ assertSame(thrown, ex.getCause());
+ }
+ }
+ }
+
private static DOMRpcRouter actionsRouter() {
final DOMRpcRouter router = new DOMRpcRouter();
router.onModelContextUpdated(Actions.CONTEXT);