<!-- 
RSS generated by JIRA (8.20.10#820010-sha1:ace47f9899e9ee25d7157d59aa17ab06aee30d3d) at Wed Feb 07 20:08:26 UTC 2024

It is possible to restrict the fields that are returned in this document by specifying the 'field' parameter in your request.
For example, to request only the issue key and summary append 'field=key&field=summary' to the URL of your request.
-->
<rss version="0.92" >
<channel>
    <title>OpenDaylight JIRA</title>
    <link>https://jira.opendaylight.org</link>
    <description>This file is an XML representation of an issue</description>
    <language>en-us</language>    <build-info>
        <version>8.20.10</version>
        <build-number>820010</build-number>
        <build-date>22-06-2022</build-date>
    </build-info>


<item>
            <title>[MDSAL-20] Improve RPC API error handling</title>
                <link>https://jira.opendaylight.org/browse/MDSAL-20</link>
                <project id="10137" key="MDSAL">mdsal</project>
                    <description>&lt;p&gt;At the moment, it&#8217;s pretty painful to try to attempt to deal with errors when implementing and using RPC APIs. Much of the reason for this is the use of the RpcResult object which contains a list of very rich RpcError objects that are returned in the case of an error. While in principle it&#8217;s nice to have such a rich notion of error handling, in practice it&#8217;s cumbersome to construct these objects and not always clear to what purpose all the various fields are to be put.&lt;br/&gt;
Further, there is a mismatch between normal Java error-handling semantics and the way we need to interact with these calls.&lt;br/&gt;
What follows is an attempt to actually handle errors in an RPC call. Note that to do this we need to write code that handles both Java exceptions as well as parsing the results of the RpcResult object. This code is hard to write, hard to read, and even worse, this code doesn&#8217;t even handle proper asynchronous semantics, so it&#8217;s not even correct.&lt;/p&gt;

&lt;p&gt;ExampleService.java&lt;/p&gt;
&lt;div class=&quot;code panel&quot; style=&quot;border-width: 1px;&quot;&gt;&lt;div class=&quot;codeContent panelContent&quot;&gt;
&lt;pre class=&quot;code-java&quot;&gt;
@Override
&lt;span class=&quot;code-keyword&quot;&gt;public&lt;/span&gt; Future&amp;lt;RpcResult&amp;lt;&lt;span class=&quot;code-object&quot;&gt;Void&lt;/span&gt;&amp;gt;&amp;gt; exampleRpc(ExampleRpcInput input) {
  &lt;span class=&quot;code-comment&quot;&gt;// Other implementation here
&lt;/span&gt;  &lt;span class=&quot;code-comment&quot;&gt;// ...
&lt;/span&gt;
  List&amp;lt;RpcError&amp;gt; errors;
  &lt;span class=&quot;code-keyword&quot;&gt;try&lt;/span&gt; {
    RpcResult&amp;lt;TransactionStatus&amp;gt; commitresult = t.commit().get();
    errors = commitresult.getErrors();
  } &lt;span class=&quot;code-keyword&quot;&gt;catch&lt;/span&gt; (InterruptedException | ExecutionException e) {
    errors = List.of(RpcErrors.getRpcError(APPLICATION_TAG, objecttag, &lt;span class=&quot;code-quote&quot;&gt;&quot;commit error&quot;&lt;/span&gt;, ErrorSeverity.ERROR, &lt;span class=&quot;code-quote&quot;&gt;&quot;Could not &quot;&lt;/span&gt; + action + &lt;span class=&quot;code-quote&quot;&gt;&quot; &quot;&lt;/span&gt; + objecttag, ErrorType.RPC, e));
  }

  &lt;span class=&quot;code-keyword&quot;&gt;return&lt;/span&gt; Future.immediateFuture(... RpcResultBuilder-based magic ...)
}
&lt;/pre&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;We can do much better than this. First, Java already has a perfectly acceptable mechanism for handling errors: exceptions. Rather than returning an RpcResult with successful set to false and a list of associated errors, our method should throw an exception. This exception needs to be marshaled to the calling service, and thrown on a call to get() as an ExecutionException. We can subclass ExecutionException and add additional context information where appropriate.&lt;br/&gt;
With these changes, our code above could become:&lt;/p&gt;

&lt;p&gt;ExampleService.java (Simplified error handling)&lt;/p&gt;
&lt;div class=&quot;code panel&quot; style=&quot;border-width: 1px;&quot;&gt;&lt;div class=&quot;codeContent panelContent&quot;&gt;
&lt;pre class=&quot;code-java&quot;&gt;
@Override
&lt;span class=&quot;code-keyword&quot;&gt;public&lt;/span&gt; Future&amp;lt;RpcResult&amp;lt;&lt;span class=&quot;code-object&quot;&gt;Void&lt;/span&gt;&amp;gt;&amp;gt; exampleRpc(ExampleRpcInput input)  &lt;span class=&quot;code-keyword&quot;&gt;throws&lt;/span&gt; Exception {
   &lt;span class=&quot;code-comment&quot;&gt;// Other implementation here
&lt;/span&gt;   &lt;span class=&quot;code-comment&quot;&gt;// ...
&lt;/span&gt;   RpcResult&amp;lt;TransactionStatus&amp;gt; commitresult = t.commit().get();
   RpcResult&amp;lt;&lt;span class=&quot;code-object&quot;&gt;Void&lt;/span&gt;&amp;gt; result = Rpcs.&amp;lt;&lt;span class=&quot;code-object&quot;&gt;Void&lt;/span&gt;&amp;gt;getRpcResult();
   &lt;span class=&quot;code-keyword&quot;&gt;return&lt;/span&gt; Futures.immediateFuture(result);
}
&lt;/pre&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;We could simplify this further to get rid of RpcResult as well now.&lt;/p&gt;</description>
                <environment>&lt;p&gt;Operating System: Linux&lt;br/&gt;
Platform: PC&lt;/p&gt;</environment>
        <key id="26842">MDSAL-20</key>
            <summary>Improve RPC API error handling</summary>
                <type id="10100" iconUrl="https://jira.opendaylight.org/secure/viewavatar?size=xsmall&amp;avatarId=10310&amp;avatarType=issuetype">Improvement</type>
                                                <status id="10003" iconUrl="https://jira.opendaylight.org/images/icons/status_generic.gif" description="">Confirmed</status>
                    <statusCategory id="2" key="new" colorName="blue-gray"/>
                                    <resolution id="-1">Unresolved</resolution>
                                        <assignee username="-1">Unassigned</assignee>
                                    <reporter username="readams">Rob Adams</reporter>
                        <labels>
                            <label>pt</label>
                    </labels>
                <created>Fri, 30 May 2014 16:13:43 +0000</created>
                <updated>Tue, 9 Jan 2024 13:02:29 +0000</updated>
                                                            <fixVersion>14.0.0</fixVersion>
                                    <component>Binding codegen</component>
                    <component>Binding runtime</component>
                        <due></due>
                            <votes>0</votes>
                                    <watches>6</watches>
                                                                                                                <comments>
                            <comment id="53947" author="devin.avery@brocade.com" created="Tue, 3 Jun 2014 16:47:58 +0000"  >&lt;p&gt;Tony - to add comments / link this bugs to another one where we are unifying the exceptions etc.&lt;/p&gt;

&lt;p&gt;The other bug talks about redesigning the error handling so we should take these points into consideration to make it easier to use.&lt;/p&gt;</comment>
                            <comment id="53948" author="tpantelis" created="Fri, 11 Jul 2014 02:08:36 +0000"  >&lt;p&gt;I pushed &lt;a href=&quot;https://git.opendaylight.org/gerrit/#/c/8915/&quot; class=&quot;external-link&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener&quot;&gt;https://git.opendaylight.org/gerrit/#/c/8915/&lt;/a&gt; to improve the javadocs on RpcResult and RpcError and also added a DSL RpcResultBuilder that should make it easier to construct instances.&lt;/p&gt;

&lt;p&gt;Re: the error handling and code samples in the desc, it seems there&apos;s 2 issues here. One is about the commit method where errors can be reported in 2 different ways: via an unchecked ExecutionException and via the RpcResult. I agree it would be ideal if there was one mechanism. In fact, that is up for discussion next week on a call. &lt;/p&gt;

&lt;p&gt;The other issue is similar but concerns returning errors from RPC implementations. Re: this sample code:&lt;/p&gt;

&lt;p&gt;   public Future&amp;lt;RpcResult&amp;lt;Void&amp;gt;&amp;gt; exampleRpc(ExampleRpcInput input) &lt;br/&gt;
          throws Exception &lt;/p&gt;
{
        // Other implementation here
        // ...
        RpcResult&amp;lt;TransactionStatus&amp;gt; commitresult = t.commit().get();
        RpcResult&amp;lt;Void&amp;gt; result = Rpcs.&amp;lt;Void&amp;gt;getRpcResult();
        return Futures.immediateFuture(result);
    }

&lt;p&gt;I see a couple issues with this approach. First, throwing just Exception is not a good practice - it&apos;s too general (see &lt;a href=&quot;http://stackoverflow.com/questions/7966148/throws-exception-bad-practice&quot; class=&quot;external-link&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener&quot;&gt;http://stackoverflow.com/questions/7966148/throws-exception-bad-practice&lt;/a&gt;. Also Sonar tools report this as a violation). Throwing some unchecked exception would be even worse - callers would have no idea any ex could be thrown. &lt;/p&gt;

&lt;p&gt;Second, by throwing an exception, we&apos;re back to the first issue except there would 3 mechanisms to report errors to the caller: 1) via the RPC call itself 2) via ExecutionException wrapping an ex set in the Future 3) the RpcResult. We wouldn&apos;t want to do #1 anyway because an RPC impl may be performed async/non-blocking so any error information needs to be reported via the returned Future.  The above code does a blocking commit call which isn&apos;t best practice.&lt;/p&gt;

&lt;p&gt;I think we want a clearly defined way in the API to return structured error information. RpcError, which is patterned after netconf error reporting, in RpcResult provides this mechanism. &lt;/p&gt;

&lt;p&gt;RpcError info could be wrapped by a well-known exception type (similar to RestconfDpcumentedException). However, returning an exception via the Future results in it being wrapped in an ExecutionException to the caller. Callers would have to know to look for the well-known exception (only way would be via javadoc which can be missed) and would need to check for instanceof on the ExecutionException cause. Thus doesn&apos;t seem clean to me.&lt;/p&gt;

&lt;p&gt;So, given the async nature of RPCs, I think reporting error info via the RpcResult is the most effective way.&lt;/p&gt;</comment>
                            <comment id="53949" author="readams@readams.net" created="Fri, 11 Jul 2014 02:59:12 +0000"  >&lt;p&gt;I wasn&apos;t saying we should literally use that exact signature.  Note I also said we could get rid of RpcResult, which should have been a clue &lt;img class=&quot;emoticon&quot; src=&quot;https://jira.opendaylight.org/images/icons/emoticons/smile.png&quot; height=&quot;16&quot; width=&quot;16&quot; align=&quot;absmiddle&quot; alt=&quot;&quot; border=&quot;0&quot;/&gt;.  Having a return value plus the ability to throw an exception gives you 100% of what you need.&lt;/p&gt;

&lt;p&gt;The RpcError type should be eliminated entirely.  You can create a RpcException object with derived exceptions for each of the type fields in RpcError.  The other fields are, from what I can see, not useful, but if you want you can include those as well but expect most applications not to bother with them.  Most of those things are only related to the transport layer anyway which the application wouldn&apos;t ever care about.  If you want to make the method signature clean, you can make this an unchecked exception and document its existence with an @throws javadoc comment in the generated code.  The marshaling code needs to handle unchecked exceptions in any event.&lt;/p&gt;

&lt;p&gt;While we&apos;re at it, get rid of the &quot;Input&quot; object and define the method with parameters for each of the fields in the Input object instead.  The Output object should only be created if there&apos;s more than one value being returned.  This will help to eliminate further boilerplate.&lt;/p&gt;</comment>
                            <comment id="53950" author="tpantelis" created="Fri, 11 Jul 2014 12:51:30 +0000"  >&lt;p&gt;Sorry I missed your clue.&lt;/p&gt;

&lt;p&gt;It sounds like your saying RPC methods should return a result and throw an RpcException, ie&lt;/p&gt;

&lt;p&gt;   public ExampleResult exampleRpc(ExampleRpcInput input) throws RpcException&lt;/p&gt;

&lt;p&gt;, or am I missing another clue &lt;img class=&quot;emoticon&quot; src=&quot;https://jira.opendaylight.org/images/icons/emoticons/smile.png&quot; height=&quot;16&quot; width=&quot;16&quot; align=&quot;absmiddle&quot; alt=&quot;&quot; border=&quot;0&quot;/&gt;? Assuming not, that would be fine, except, how do you handle returning a result or error async? With this signature, you can&apos;t - you&apos;re method has to do blocking calls and block the caller.&lt;/p&gt;

&lt;p&gt;In order to do async, the RPC method must return a Future. The only way to return an RpcException is via wrapping in an ExecutionException that is thrown by the Future. We could do that but I don&apos;t think that&apos;s as clean and intuitive as explicitly returning RpcErrors in the RpcResult. Not to mention the headache of deprecating the currently generated method signatures and migrating to a new signature.  &lt;/p&gt;


&lt;p&gt;(In reply to Rob Adams from comment #3)&lt;br/&gt;
&amp;gt; I wasn&apos;t saying we should literally use that exact signature.  Note I also&lt;br/&gt;
&amp;gt; said we could get rid of RpcResult, which should have been a clue &lt;img class=&quot;emoticon&quot; src=&quot;https://jira.opendaylight.org/images/icons/emoticons/smile.png&quot; height=&quot;16&quot; width=&quot;16&quot; align=&quot;absmiddle&quot; alt=&quot;&quot; border=&quot;0&quot;/&gt;. &lt;br/&gt;
&amp;gt; Having a return value plus the ability to throw an exception gives you 100%&lt;br/&gt;
&amp;gt; of what you need.&lt;br/&gt;
&amp;gt; &lt;br/&gt;
&amp;gt; The RpcError type should be eliminated entirely.  You can create a&lt;br/&gt;
&amp;gt; RpcException object with derived exceptions for each of the type fields in&lt;br/&gt;
&amp;gt; RpcError.  The other fields are, from what I can see, not useful, but if you&lt;br/&gt;
&amp;gt; want you can include those as well but expect most applications not to&lt;br/&gt;
&amp;gt; bother with them.  Most of those things are only related to the transport&lt;br/&gt;
&amp;gt; layer anyway which the application wouldn&apos;t ever care about.  If you want to&lt;br/&gt;
&amp;gt; make the method signature clean, you can make this an unchecked exception&lt;br/&gt;
&amp;gt; and document its existence with an @throws javadoc comment in the generated&lt;br/&gt;
&amp;gt; code.  The marshaling code needs to handle unchecked exceptions in any event.&lt;br/&gt;
&amp;gt; &lt;br/&gt;
&amp;gt; While we&apos;re at it, get rid of the &quot;Input&quot; object and define the method with&lt;br/&gt;
&amp;gt; parameters for each of the fields in the Input object instead.  The Output&lt;br/&gt;
&amp;gt; object should only be created if there&apos;s more than one value being returned.&lt;br/&gt;
&amp;gt; This will help to eliminate further boilerplate.&lt;/p&gt;</comment>
                            <comment id="53951" author="tpantelis" created="Fri, 11 Jul 2014 13:00:19 +0000"  >&lt;p&gt;Another way, instead of returning a Future, pass a callback to the RPC method, something like:&lt;/p&gt;

&lt;p&gt;public interface RpcCallback&amp;lt;T&amp;gt; {&lt;br/&gt;
    void onSuccess( T result );&lt;br/&gt;
    void onFailure( Collection&amp;lt;RpcError&amp;gt; errors );&lt;br/&gt;
  //  OR void onFailure( RpcException error );&lt;br/&gt;
}&lt;/p&gt;

&lt;p&gt;public void exampleRpc(ExampleRpcInput input, RpcCallback&amp;lt;ExampleResult&amp;gt; callback );&lt;/p&gt;

&lt;p&gt;(In reply to Tom Pantelis from comment #4)&lt;br/&gt;
&amp;gt; Sorry I missed your clue.&lt;br/&gt;
&amp;gt; &lt;br/&gt;
&amp;gt; It sounds like your saying RPC methods should return a result and throw an&lt;br/&gt;
&amp;gt; RpcException, ie&lt;br/&gt;
&amp;gt; &lt;br/&gt;
&amp;gt;    public ExampleResult exampleRpc(ExampleRpcInput input) throws RpcException&lt;br/&gt;
&amp;gt; &lt;br/&gt;
&amp;gt; , or am I missing another clue &lt;img class=&quot;emoticon&quot; src=&quot;https://jira.opendaylight.org/images/icons/emoticons/smile.png&quot; height=&quot;16&quot; width=&quot;16&quot; align=&quot;absmiddle&quot; alt=&quot;&quot; border=&quot;0&quot;/&gt;? Assuming not, that would be fine,&lt;br/&gt;
&amp;gt; except, how do you handle returning a result or error async? With this&lt;br/&gt;
&amp;gt; signature, you can&apos;t - you&apos;re method has to do blocking calls and block the&lt;br/&gt;
&amp;gt; caller.&lt;br/&gt;
&amp;gt; &lt;br/&gt;
&amp;gt; In order to do async, the RPC method must return a Future. The only way to&lt;br/&gt;
&amp;gt; return an RpcException is via wrapping in an ExecutionException that is&lt;br/&gt;
&amp;gt; thrown by the Future. We could do that but I don&apos;t think that&apos;s as clean and&lt;br/&gt;
&amp;gt; intuitive as explicitly returning RpcErrors in the RpcResult. Not to mention&lt;br/&gt;
&amp;gt; the headache of deprecating the currently generated method signatures and&lt;br/&gt;
&amp;gt; migrating to a new signature.  &lt;br/&gt;
&amp;gt; &lt;br/&gt;
&amp;gt; &lt;br/&gt;
&amp;gt; (In reply to Rob Adams from comment #3)&lt;br/&gt;
&amp;gt; &amp;gt; I wasn&apos;t saying we should literally use that exact signature.  Note I also&lt;br/&gt;
&amp;gt; &amp;gt; said we could get rid of RpcResult, which should have been a clue &lt;img class=&quot;emoticon&quot; src=&quot;https://jira.opendaylight.org/images/icons/emoticons/smile.png&quot; height=&quot;16&quot; width=&quot;16&quot; align=&quot;absmiddle&quot; alt=&quot;&quot; border=&quot;0&quot;/&gt;. &lt;br/&gt;
&amp;gt; &amp;gt; Having a return value plus the ability to throw an exception gives you 100%&lt;br/&gt;
&amp;gt; &amp;gt; of what you need.&lt;br/&gt;
&amp;gt; &amp;gt; &lt;br/&gt;
&amp;gt; &amp;gt; The RpcError type should be eliminated entirely.  You can create a&lt;br/&gt;
&amp;gt; &amp;gt; RpcException object with derived exceptions for each of the type fields in&lt;br/&gt;
&amp;gt; &amp;gt; RpcError.  The other fields are, from what I can see, not useful, but if you&lt;br/&gt;
&amp;gt; &amp;gt; want you can include those as well but expect most applications not to&lt;br/&gt;
&amp;gt; &amp;gt; bother with them.  Most of those things are only related to the transport&lt;br/&gt;
&amp;gt; &amp;gt; layer anyway which the application wouldn&apos;t ever care about.  If you want to&lt;br/&gt;
&amp;gt; &amp;gt; make the method signature clean, you can make this an unchecked exception&lt;br/&gt;
&amp;gt; &amp;gt; and document its existence with an @throws javadoc comment in the generated&lt;br/&gt;
&amp;gt; &amp;gt; code.  The marshaling code needs to handle unchecked exceptions in any event.&lt;br/&gt;
&amp;gt; &amp;gt; &lt;br/&gt;
&amp;gt; &amp;gt; While we&apos;re at it, get rid of the &quot;Input&quot; object and define the method with&lt;br/&gt;
&amp;gt; &amp;gt; parameters for each of the fields in the Input object instead.  The Output&lt;br/&gt;
&amp;gt; &amp;gt; object should only be created if there&apos;s more than one value being returned.&lt;br/&gt;
&amp;gt; &amp;gt; This will help to eliminate further boilerplate.&lt;/p&gt;</comment>
                            <comment id="53952" author="readams@readams.net" created="Fri, 11 Jul 2014 16:16:10 +0000"  >&lt;p&gt;The Future return can be potentially useful, though not always.&lt;/p&gt;

&lt;p&gt;Let&apos;s say I have the following:&lt;/p&gt;

&lt;p&gt;rpc test-rpc {&lt;br/&gt;
    input {&lt;br/&gt;
        leaf input1 &lt;/p&gt;
{
            type string;
        }&lt;br/&gt;
        leaf input2 {
            type int32;
        }&lt;br/&gt;
    }&lt;br/&gt;
    output {&lt;br/&gt;
        leaf returnVal {            type string;        }
&lt;p&gt;    }&lt;br/&gt;
}&lt;/p&gt;

&lt;p&gt;The method signature could be:&lt;/p&gt;

&lt;p&gt;ListenableFuture&amp;lt;String&amp;gt; testRPC(String input1, Integer input2)&lt;br/&gt;
     throws RpcException {&lt;br/&gt;
   if (somethingwentwrong)&lt;br/&gt;
       throw new RpcApplicationException(&quot;The horror!&quot;);&lt;br/&gt;
}&lt;/p&gt;

&lt;p&gt;If this RPC is going to do something quick and return an immediatefuture, it might be simpler to allow them to specify in the model something like ext:synchronous true;&lt;/p&gt;

&lt;p&gt;which would make the signature be:&lt;br/&gt;
String testRPC(String input1, Integer input2)&lt;br/&gt;
     throws RpcException {&lt;/p&gt;

&lt;p&gt;}&lt;br/&gt;
in this case the framework could wrap it with whatever fake async semantics needed.  Probably a large majority of these &quot;RPC&quot; functions would be something quick and synchronous and in-process.&lt;/p&gt;

&lt;p&gt;Removing the Future is not as large an improvement however so I don&apos;t think we should bother with it right away, and it could be added later.&lt;/p&gt;

&lt;p&gt;To make the transition possible, I would recommend that in the yang generator maven plugin we add a parameter that will enable the new RPC generation style that would be off by default.  We should print a warning that says eventually the default will change.  At the same time, we can also fix &lt;a href=&quot;https://jira.opendaylight.org/browse/MDSAL-18&quot; title=&quot;Return an empty list and never null from list-valued parameters in generated models&quot; class=&quot;issue-link&quot; data-issue-key=&quot;MDSAL-18&quot;&gt;&lt;del&gt;MDSAL-18&lt;/del&gt;&lt;/a&gt;.&lt;/p&gt;</comment>
                            <comment id="53953" author="readams@readams.net" created="Fri, 11 Jul 2014 16:25:48 +0000"  >&lt;p&gt;Another option would be:&lt;/p&gt;

&lt;p&gt;ListenableFuture&amp;lt;String&amp;gt; testRPC(String input1, Integer input2) {&lt;br/&gt;
   if (somethingwentwrong)&lt;br/&gt;
       return Futures.failedFuture(new RpcApplicationException(&quot;The horror!&quot;));&lt;br/&gt;
}&lt;/p&gt;

&lt;p&gt;This is probably better, though we could wrap the call with something that would catch an exception and return a failed future.&lt;/p&gt;</comment>
                            <comment id="53954" author="tpantelis" created="Fri, 11 Jul 2014 17:50:50 +0000"  >&lt;p&gt;Yeah you&apos;d want to always throw the RpcException via Future. If RpcException was declared in the method signature then callers would have to handle it in 2 places:&lt;/p&gt;

&lt;p&gt;The RpcException would get wrapped in an ExecutionException. However, using Futures.addCallback makes this easier on the caller side:  &lt;/p&gt;

&lt;p&gt;   ListenableFuture&amp;lt;String&amp;gt; future = testRPC( ... );&lt;br/&gt;
   Futures.addCallback( future, new FutureCallback&amp;lt;String&amp;gt;() {&lt;br/&gt;
            @Override&lt;br/&gt;
            public void onSuccess( String result ) {&lt;br/&gt;
            }&lt;/p&gt;

&lt;p&gt;            @Override&lt;br/&gt;
            public void onFailure( Throwable ex ) {&lt;/p&gt;

&lt;p&gt;                if( ex instanceof RpcException ) {&lt;br/&gt;
                }&lt;br/&gt;
            }&lt;br/&gt;
        } );&lt;/p&gt;

&lt;p&gt;Now that I think about it some more and see code written, it looks reasonable. As long as we can effectively convey in javadocs that callers can expect only RpcException as a failure. The MD-SAL RPC proxy framework could also ensure only RpcExceptions propagate to the caller by intercepting any other unchecked exception from the RPC impl via a proxy ListenableFuture and converting to RpcException. Also, if an unchecked exception was thrown directly from the method by the impl, the proxy framework could catch it, convert to RpcException and wrap in an immediateFailedFuture. Maybe it already does something similar - not sure.&lt;/p&gt;

&lt;p&gt;Re: changing the method param signature, that&apos;s probably another discussion/bug enhancement. I can see that being tricky for rest conf to call RPCs generically. Right now it uses generated codecs to invoke the *InputBuilder generically with the input data.&lt;/p&gt;

&lt;p&gt;(In reply to Rob Adams from comment #7)&lt;br/&gt;
&amp;gt; Another option would be:&lt;br/&gt;
&amp;gt; &lt;br/&gt;
&amp;gt; ListenableFuture&amp;lt;String&amp;gt; testRPC(String input1, Integer input2) &lt;/p&gt;
{
&amp;gt;    if (somethingwentwrong)
&amp;gt;        return Futures.failedFuture(new RpcApplicationException(&quot;The
&amp;gt; horror!&quot;));
&amp;gt; }
&lt;p&gt;&amp;gt; &lt;br/&gt;
&amp;gt; This is probably better, though we could wrap the call with something that&lt;br/&gt;
&amp;gt; would catch an exception and return a failed future.&lt;/p&gt;</comment>
                            <comment id="53955" author="readams@readams.net" created="Fri, 11 Jul 2014 18:10:03 +0000"  >&lt;p&gt;Invoking a method with arguments is just as easy as invoking a method with one argument.&lt;/p&gt;</comment>
                            <comment id="53956" author="tpantelis" created="Sun, 13 Jul 2014 13:40:07 +0000"  >&lt;p&gt;It would be ideal to return a CheckFuture:&lt;/p&gt;

&lt;p&gt;     CheckedFuture&amp;lt;String,RpcException&amp;gt; testRPC( ... );&lt;/p&gt;</comment>
                            <comment id="53957" author="tpantelis" created="Mon, 14 Jul 2014 14:37:43 +0000"  >&lt;p&gt;A potential use case with the current the usage of RpcResult is that you could return a successful RpcResult and also report warnings/errors to the caller. An example of this is in the toaster example where the KitchenService reports success if the toaster is out of bread with a warning RpcError as it was able to make the rest of the breakfast but just missing the toast. I suppose this could be conveyed via an RpcException but it may not be as easy and/or intuitive.&lt;/p&gt;

&lt;p&gt;This type of use case wouldn&apos;t be common though in real scenarios.&lt;/p&gt;</comment>
                            <comment id="53958" author="readams@readams.net" created="Mon, 14 Jul 2014 16:41:17 +0000"  >&lt;p&gt;I&apos;d say that even if you did want to return some status information that could include a partial failure, you&apos;d want to model that in the output object of your RPC and not use the RpcError thing anyway.&lt;/p&gt;</comment>
                            <comment id="53959" author="rovarga" created="Fri, 13 Nov 2015 13:25:51 +0000"  >&lt;p&gt;Move to MDSAL&lt;/p&gt;</comment>
                            <comment id="71531" author="rovarga" created="Tue, 4 Oct 2022 22:23:22 +0000"  >&lt;p&gt;I think we really want a wrapper service, which will take care of the mapping and exception handling.&lt;/p&gt;

&lt;p&gt;At the end of the day, we really want to have a simple service which can translate a Future&amp;lt;RpcErrorAware&amp;gt; to a Future&amp;lt;RpcResult&amp;lt;?&amp;gt;&amp;gt;. Should probably be a static method somewhere.&lt;/p&gt;

&lt;p&gt;Note the Future.get() part can be handled as a transformation.&lt;/p&gt;</comment>
                            <comment id="72433" author="rovarga" created="Thu, 3 Aug 2023 08:56:23 +0000"  >&lt;p&gt;So, with &lt;a href=&quot;https://jira.opendaylight.org/browse/MDSAL-777&quot; title=&quot;Support single-RPC interfaces in RpcConsumerRegistry and RpcProviderService&quot; class=&quot;issue-link&quot; data-issue-key=&quot;MDSAL-777&quot;&gt;&lt;del&gt;MDSAL-777&lt;/del&gt;&lt;/a&gt; this gets much easier. Each constituent RPC has a org.opendaylight.yangtools.yang.binding.Rpc specialization, which has the same invocation method name and the generated interface acts only as an identifier.&lt;br/&gt;
Introduce something like:&lt;/p&gt;
&lt;div class=&quot;code panel&quot; style=&quot;border-width: 1px;&quot;&gt;&lt;div class=&quot;codeContent panelContent&quot;&gt;
&lt;pre class=&quot;code-java&quot;&gt;
&lt;span class=&quot;code-keyword&quot;&gt;interface&lt;/span&gt; RpcProviderService {

    &amp;lt;I &lt;span class=&quot;code-keyword&quot;&gt;extends&lt;/span&gt; RpcInput, O &lt;span class=&quot;code-keyword&quot;&gt;extends&lt;/span&gt; RpcOutput&amp;gt; @NonNull Registration registerRpcImplementation(&lt;span class=&quot;code-object&quot;&gt;Class&lt;/span&gt;&amp;lt;? &lt;span class=&quot;code-keyword&quot;&gt;extends&lt;/span&gt; Rpc&amp;lt;I, O&amp;gt;&amp;gt; rpcType, SynchronousRpc&amp;lt;I, O&amp;gt; implementation);

    @FuctionalInterface
    &lt;span class=&quot;code-keyword&quot;&gt;interface&lt;/span&gt; SynchronousRpc&amp;lt;I &lt;span class=&quot;code-keyword&quot;&gt;extends&lt;/span&gt; RpcInput, O &lt;span class=&quot;code-keyword&quot;&gt;extends&lt;/span&gt; RpcOutput&amp;gt; {
        &lt;span class=&quot;code-comment&quot;&gt;// &lt;span class=&quot;code-keyword&quot;&gt;null&lt;/span&gt; implies no RpcResult.getResult()
&lt;/span&gt;        @Nullable O invokeSimple(@NonNull I input) &lt;span class=&quot;code-keyword&quot;&gt;throws&lt;/span&gt; RpcException;
    }

    &lt;span class=&quot;code-keyword&quot;&gt;final&lt;/span&gt; &lt;span class=&quot;code-keyword&quot;&gt;class &lt;/span&gt;RpcException &lt;span class=&quot;code-keyword&quot;&gt;extends&lt;/span&gt; Exception {

        &lt;span class=&quot;code-comment&quot;&gt;// checked to be non-empty
&lt;/span&gt;        @NonNull List&amp;lt;RpcError&amp;gt; rpcErrors();
    }
}
&lt;/pre&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Users then can do:&lt;/p&gt;
&lt;div class=&quot;code panel&quot; style=&quot;border-width: 1px;&quot;&gt;&lt;div class=&quot;codeContent panelContent&quot;&gt;
&lt;pre class=&quot;code-java&quot;&gt;
&lt;span class=&quot;code-keyword&quot;&gt;import&lt;/span&gt; FooRpc;

RpcProviderService svc;
&lt;span class=&quot;code-keyword&quot;&gt;var&lt;/span&gt; reg = svc.registerRpcImplementation(FooRpc.class, input -&amp;gt; {
    &lt;span class=&quot;code-keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;code-keyword&quot;&gt;new&lt;/span&gt; FooOutputBuilder()
        &lt;span class=&quot;code-comment&quot;&gt;// whatever
&lt;/span&gt;        .build();
  &#160; &lt;span class=&quot;code-comment&quot;&gt;// or &lt;span class=&quot;code-keyword&quot;&gt;throw&lt;/span&gt; RpcException(&lt;span class=&quot;code-keyword&quot;&gt;new&lt;/span&gt; RpcErrorBuilder...build())
&lt;/span&gt;    &lt;span class=&quot;code-comment&quot;&gt;// or &lt;span class=&quot;code-quote&quot;&gt;&apos;&lt;span class=&quot;code-keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;code-keyword&quot;&gt;null&lt;/span&gt;&apos;&lt;/span&gt; &lt;span class=&quot;code-keyword&quot;&gt;for&lt;/span&gt; empty
&lt;/span&gt; &#160; &#160;});

&lt;/pre&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Once we have this done, we can then deal with defining an asynchronous counterpart.&lt;/p&gt;</comment>
                    </comments>
                <issuelinks>
                            <issuelinktype id="10000">
                    <name>Blocks</name>
                                                                <inwardlinks description="is blocked by">
                                        <issuelink>
            <issuekey id="25646">CONTROLLER-1092</issuekey>
        </issuelink>
            <issuelink>
            <issuekey id="36231">MDSAL-777</issuekey>
        </issuelink>
                            </inwardlinks>
                                    </issuelinktype>
                    </issuelinks>
                <attachments>
                    </attachments>
                <subtasks>
                    </subtasks>
                <customfields>
                                                                            <customfield id="customfield_11400" key="com.atlassian.jira.plugins.jira-development-integration-plugin:devsummary">
                        <customfieldname>Development</customfieldname>
                        <customfieldvalues>
                            
                        </customfieldvalues>
                    </customfield>
                                                                                                                        <customfield id="customfield_10208" key="com.atlassian.jira.plugin.system.customfieldtypes:textfield">
                        <customfieldname>External issue ID</customfieldname>
                        <customfieldvalues>
                            <customfieldvalue>1117</customfieldvalue>

                        </customfieldvalues>
                    </customfield>
                                                                <customfield id="customfield_10201" key="com.atlassian.jira.plugin.system.customfieldtypes:url">
                        <customfieldname>External issue URL</customfieldname>
                        <customfieldvalues>
                            <customfieldvalue><![CDATA[https://bugs.opendaylight.org/show_bug.cgi?id=1117]]></customfieldvalue>

                        </customfieldvalues>
                    </customfield>
                                                                                            <customfield id="customfield_10206" key="com.atlassian.jira.plugin.system.customfieldtypes:select">
                        <customfieldname>Issue Type</customfieldname>
                        <customfieldvalues>
                                <customfieldvalue key="10305"><![CDATA[Improvement]]></customfieldvalue>

                        </customfieldvalues>
                    </customfield>
                                                                                                                                                                                                                                                                                                                                                                                                                                            <customfield id="customfield_10202" key="com.atlassian.jira.plugin.system.customfieldtypes:select">
                        <customfieldname>Priority</customfieldname>
                        <customfieldvalues>
                                <customfieldvalue key="10312"><![CDATA[High]]></customfieldvalue>

                        </customfieldvalues>
                    </customfield>
                                                                <customfield id="customfield_10000" key="com.pyxis.greenhopper.jira:gh-lexo-rank">
                        <customfieldname>Rank</customfieldname>
                        <customfieldvalues>
                            <customfieldvalue>0|i02vtj:</customfieldvalue>

                        </customfieldvalues>
                    </customfield>
                                                                                                                                                                                </customfields>
    </item>
</channel>
</rss>