javafreeswitch

NPE when sending sendBackgroundApiCommand to FreeSwitch Client


I downloaded Freeswitch client from https://github.com/fivetime/esl-client-netty4 and I was able to build it with no errors using Java 17. However, I receive NPE each time I'm trying to execute sendBackgroundApiCommand().

What might be the cause of NPE? Did I miss anything in my Client initialization?

The minimum reproducible example is below:

public class Main {
    private static final Logger log = LoggerFactory.getLogger(Main.class);

    private static class DemoEventListener implements IEslEventListener {
        @Override
        public void onEslEvent(Context ctx, EslEvent eslEvent) {
            log.info("Event Name : {}", eslEvent.getEventName());
        }
    }

    public static void main(String[] args) {
        SocketAddress host = new InetSocketAddress("freeswitch", 19601);
        String password = "fsevent";
        int timeoutSeconds = 10;
        Client inboundClient = new Client();
        try {
            inboundClient.connect(host, password, timeoutSeconds);
            inboundClient.addEventListener(new DemoEventListener());
            inboundClient.setEventSubscriptions(IModEslApi.EventFormat.PLAIN, "all");
            
            // sendApiCommand() works fine
            EslMessage response = inboundClient.sendApiCommand( "show", "registrations");
            log.info("Registrations total : {}", response.getBodyLines().size());

            // it throws NPE
            inboundClient.sendBackgroundApiCommand("chat", "sip|1000@172.16.1.114|1001@172.16.1.114|Test case message|text/html");
        } catch (Exception e) {
            log.error("ERROR: ", e);
        } finally {
            inboundClient.close();
        }
    }
} 

The full log inluding stacktrace is below:

17:27:50.493 [main] INFO  org.freeswitch.esl.client.inbound.Client - Connecting to freeswitch/172.16.2.161:19601 ...
17:27:50.888 [main] INFO  org.freeswitch.esl.client.inbound.Client - Connected to freeswitch/172.16.2.161:19601
17:27:50.910 [nioEventLoopGroup-2-1] INFO  org.freeswitch.esl.client.inbound.InboundClientHandler - Received message: [EslMessage{contentType=auth/request, headers=1, body=0 lines}]
17:27:50.916 [nioEventLoopGroup-2-1] INFO  org.freeswitch.esl.client.inbound.InboundClientHandler - Received message: [EslMessage{contentType=command/reply, headers=2, body=0 lines}]
17:27:51.152 [main] INFO  org.freeswitch.esl.client.inbound.Client - Authenticated
17:27:51.158 [nioEventLoopGroup-2-1] INFO  org.freeswitch.esl.client.inbound.InboundClientHandler - Received message: [EslMessage{contentType=command/reply, headers=2, body=0 lines}]
17:27:51.161 [nioEventLoopGroup-2-1] INFO  org.freeswitch.esl.client.inbound.InboundClientHandler - Received message: [EslMessage{contentType=api/response, headers=2, body=2 lines}]
17:27:51.162 [main] INFO  org.my_test.netty.Main - Registrations total : 2
17:27:51.166 [nioEventLoopGroup-2-1] INFO  org.freeswitch.esl.client.inbound.InboundClientHandler - Received message: [EslMessage{contentType=command/reply, headers=3, body=0 lines}]
17:27:51.166 [pool-2-thread-1] INFO  org.my_test.netty.Main - Event Name : API
17:27:51.167 [pool-2-thread-1] INFO  org.my_test.netty.Main - Event Name : API
17:27:51.163 [main] ERROR org.my_test.netty.Main - ERROR: 
java.lang.NullPointerException: null
    at java.base/java.util.concurrent.CompletableFuture.screenExecutor(CompletableFuture.java:455) ~[?:?]
    at java.base/java.util.concurrent.CompletableFuture.thenComposeAsync(CompletableFuture.java:2320) ~[?:?]
    at org.freeswitch.esl.client.internal.AbstractEslClientHandler.sendBackgroundApiCommand(AbstractEslClientHandler.java:222) ~[esl-client-netty4-0.9.2.jar:?]
    at org.freeswitch.esl.client.internal.Context.sendBackgroundApiCommand(Context.java:106) ~[esl-client-netty4-0.9.2.jar:?]
    at org.freeswitch.esl.client.inbound.Client.sendBackgroundApiCommand(Client.java:183) ~[esl-client-netty4-0.9.2.jar:?]
    at org.my_test.netty.Main.main(Main.java:38) [classes/:?]
17:27:51.182 [nioEventLoopGroup-2-1] INFO  org.freeswitch.esl.client.inbound.InboundClientHandler - Received message: [EslMessage{contentType=command/reply, headers=2, body=0 lines}]
17:27:51.182 [nioEventLoopGroup-2-1] INFO  org.freeswitch.esl.client.inbound.InboundClientHandler - Received message: [EslMessage{contentType=text/disconnect-notice, headers=2, body=2 lines}]
17:27:51.183 [nioEventLoopGroup-2-1] INFO  org.freeswitch.esl.client.inbound.Client - Disconnected ...

Solution

  • Finally, I found where the problem is. There is a sendBackgroundApiCommand() implementation in public abstract class AbstractEslClientHandler extends SimpleChannelInboundHandler<EslMessage>. The NPE happens when thenComposeAsync() is being called and the reason for that is callbackExecutor. not initialized.

    public CompletableFuture<EslEvent> sendBackgroundApiCommand(Channel channel, final String command) {
        return sendApiSingleLineCommand(channel, command)
              .thenComposeAsync(result -> {
                    // some code here
                 }
              }, callbackExecutor);
    }
    

    I added intialization to a child class like below and the problem gone.

    class InboundClientHandler extends AbstractEslClientHandler {
        // ...
        public InboundClientHandler(String password, IEslProtocolListener listener) {
           this.password = password;
           this.listener = listener;
           this.callbackExecutor = Executors.newSingleThreadExecutor();
        }
        // ...
    }