4

I am working on an Android application in which I am implementing Chat functionality. The chat is quite fast given the usage of Cometd, but for some reason, Cometd is sending alternate messages. If it sends message-1, it doesn't send message-2, then 3 is sent, so on and so-forth. This is a very strange behaviour and hard to isolate the problem as there is no error.

I added system logs to check if the onClick method is getting called and the loop inside which sends the message. Also, I added a system.out at server-side code, and only alternate messages are received. This lead to the conclusion that Cometd is somehow not sending every alternate message. Any help would be nice. Thank you.

Please note, the PUSH service is provided by Cometd which is instantiated in ConsoleChatClient.java

Code :

public class ChatMessagesActivity extends ApplicationDrawerLoader {

 HttpClient httpClient;
 ConsoleChatClient consoleChatClient;

 @Override
    protected void onStart() {
        super.onStart();
        Intent intent = new Intent(this, ConsoleChatClient.class);
        bindService(intent, mConnection, Context.BIND_IMPORTANT);
    }

    private ServiceConnection mConnection = new ServiceConnection() {

        @Override
        public void onServiceConnected(ComponentName className,
                                       IBinder service) {
            ConsoleChatClient.LocalBinder binder = (ConsoleChatClient.LocalBinder) service;
            consoleChatClient = binder.getService();
            mBound = true;
            onConsoleChatClientReady();
        }

        @Override
        public void onServiceDisconnected(ComponentName arg0) {
            mBound = false;
        }
    };


    private void onConsoleChatClientReady() {
        httpClient = consoleChatClient.httpClient;
        subscribeFlag = true;
        Bundle extras = getIntent().getExtras();
        if (extras != null) {
            groupAccountId = extras.getLong("groupid");
            conversationId = extras.getInt("conversationid");
        }

        if (conversationId != 0) {
            consoleChatClient.bayeuxClient.getChannel("/person/" + conversationId).subscribe(chatListener);
        }

        if (groupAccountId != 0) {
            consoleChatClient.bayeuxClient.getChannel("/chat/" + groupAccountId).subscribe(chatListener);
        }
    }
sendMessageButton.setOnClickListener(new View.OnClickListener() {

            @Override
            public void onClick(View v) {
// method below sends the message, and it does so for every //alternate message precisely. 
  Log.d("We","groupmessage");
Map<String, Object> outputData = new HashMap<>();
                    outputData.put("name", typeMessageField.getText().toString());
                    outputData.put("timestamp", new Timestamp(System.currentTimeMillis()));
                    outputData.put("type", false);
                    consoleChatClient.bayeuxClient.getChannel("/service/chat/" + String.valueOf(groupAccountId)).publish(outputData);
}

ConsoleChatClient :

public class ConsoleChatClient extends Service {

    private final IBinder mBinder = new LocalBinder();
    BayeuxClient bayeuxClient = StaticRestTemplate.getClient();
    HttpClient httpClient = StaticRestTemplate.getHttpClient();
    String defaultURL = StaticRestTemplate.baseURL + "/cometd";


    public class LocalBinder extends Binder {
        ConsoleChatClient getService() {
            // Return this instance of LocalService so clients can call public methods
            return ConsoleChatClient.this;
        }
    }

    private void connectionEstablished() {
        System.err.printf("system: Connection to Server Opened%n");

    }

    private void connectionClosed() {
        System.err.printf("system: Connection to Server Closed%n");
    }

    private void connectionBroken() {
        System.err.printf("system: Connection to Server Broken%n");
    }

    @Override
    public void onCreate() {
        super.onCreate();
        performConnection();
    }

    @Override
    public IBinder onBind(Intent intent) {
        performConnection();
        return mBinder;

    }

    private void performConnection() {
        try {
            httpClient.start();
            ClientTransport clientTransport = new LongPollingTransport(null, httpClient);
            bayeuxClient = new BayeuxClient(defaultURL, clientTransport);
            // Below for use with Spring-Security post-login.
            bayeuxClient.putCookie(new HttpCookie("JSESSIONID", StaticRestTemplate.getJsessionid()));
            bayeuxClient.getChannel(Channel.META_HANDSHAKE).addListener(new InitializerListener());
            bayeuxClient.getChannel(Channel.META_CONNECT).addListener(new ConnectionListener());
            bayeuxClient.handshake();
            StaticRestTemplate.setClient(bayeuxClient);
            StaticRestTemplate.setHttpClient(httpClient);
            boolean success = bayeuxClient.waitFor(2000, BayeuxClient.State.CONNECTED);
            if (!success) {
                System.err.printf("Could not handshake with server at %s%n", defaultURL);
            }else {
                System.err.printf("Handhskare complete");
            }

        } catch (Exception ignored) {}
    }

    private class InitializerListener implements ClientSessionChannel.MessageListener {
        @Override
        public void onMessage(ClientSessionChannel channel, Message message) {
            if (message.isSuccessful()) {
                System.out.println("Message successful");
            }
        }
    }

    private class ConnectionListener implements ClientSessionChannel.MessageListener {
        private boolean wasConnected;
        private boolean connected;

        public void onMessage(ClientSessionChannel channel, Message message) {
            if (bayeuxClient.isDisconnected()) {
                connected = false;
                connectionClosed();
                return;
            }
            wasConnected = connected;
            connected = message.isSuccessful();
            if (!wasConnected && connected) {
                connectionEstablished();
            } else if (wasConnected && !connected) {
                connectionBroken();
            }
        }
    }
}
public class ConsoleChatClient extends Service {

    private final IBinder mBinder = new LocalBinder();
    BayeuxClient bayeuxClient = StaticRestTemplate.getClient();
    HttpClient httpClient = StaticRestTemplate.getHttpClient();
    String defaultURL = StaticRestTemplate.baseURL + "/cometd";


    public class LocalBinder extends Binder {
        ConsoleChatClient getService() {
            // Return this instance of LocalService so clients can call public methods
            return ConsoleChatClient.this;
        }
    }

    private void connectionEstablished() {
        System.err.printf("system: Connection to Server Opened%n");

    }

    private void connectionClosed() {
        System.err.printf("system: Connection to Server Closed%n");
    }

    private void connectionBroken() {
        System.err.printf("system: Connection to Server Broken%n");
    }

    @Override
    public void onCreate() {
        super.onCreate();
        performConnection();
    }

    @Override
    public IBinder onBind(Intent intent) {
        performConnection();
        return mBinder;

    }

    private void performConnection() {
        try {
            httpClient.start();
            ClientTransport clientTransport = new LongPollingTransport(null, httpClient);
            bayeuxClient = new BayeuxClient(defaultURL, clientTransport);
            // Below for use with Spring-Security post-login.
            bayeuxClient.putCookie(new HttpCookie("JSESSIONID", StaticRestTemplate.getJsessionid()));
            bayeuxClient.getChannel(Channel.META_HANDSHAKE).addListener(new InitializerListener());
            bayeuxClient.getChannel(Channel.META_CONNECT).addListener(new ConnectionListener());
            bayeuxClient.handshake();
            StaticRestTemplate.setClient(bayeuxClient);
            StaticRestTemplate.setHttpClient(httpClient);
            boolean success = bayeuxClient.waitFor(2000, BayeuxClient.State.CONNECTED);
            if (!success) {
                System.err.printf("Could not handshake with server at %s%n", defaultURL);
            }else {
                System.err.printf("Handhskare complete");
            }

        } catch (Exception ignored) {}
    }

    private class InitializerListener implements ClientSessionChannel.MessageListener {
        @Override
        public void onMessage(ClientSessionChannel channel, Message message) {
            if (message.isSuccessful()) {
                System.out.println("Message successful");
            }
        }
    }

    private class ConnectionListener implements ClientSessionChannel.MessageListener {
        private boolean wasConnected;
        private boolean connected;

        public void onMessage(ClientSessionChannel channel, Message message) {
            if (bayeuxClient.isDisconnected()) {
                connected = false;
                connectionClosed();
                return;
            }
            wasConnected = connected;
            connected = message.isSuccessful();
            if (!wasConnected && connected) {
                connectionEstablished();
            } else if (wasConnected && !connected) {
                connectionBroken();
            }
        }
    }
}

Code with counter : Counter initialized with 0.

Map<String, Object> outputData = new HashMap<>();
                    outputData.put("name", typeMessageField.getText().toString());
                    outputData.put("timestamp", new Timestamp(System.currentTimeMillis()));
                    outputData.put("type", "false");
                    outputData.put("counter",counter);
                    counter++;
                    try {
                        if(consoleChatClient.httpClient.isStarted()) {
                            consoleChatClient.bayeuxClient.getChannel("/service/chat/" + String.valueOf(groupAccountId)).publish(outputData);
                            Log.d("Android, counter",String.valueOf(counter));
                        }else {
                            consoleChatClient.httpClient.start();
                            Log.d("Client","not started");
                        }
                    }catch (Exception e){
                        e.printStackTrace();
                    }

Server side printing of counter :

  @Listener("/service/chat/{id}")
    public void processHello(ServerSession remote, ServerMessage message, @Param("id") String id) {

        System.out.println("I was called"+message.toString());
// Other code
}

Android logs :

04-04 10:30:11.465 2047-2271/mycompany.app I/System.out: Message successful
04-04 10:30:11.485 2047-2265/mycompany.app W/System.err: system: Connection to Server Opened
04-04 10:30:11.585 2047-2266/mycompany.app I/System.out: Message successful
04-04 10:30:11.697 2047-2270/mycompany.app W/System.err: Handhskare completesystem: Connection to Server Opened
04-04 10:30:11.720 2047-2047/mycompany.app I/Choreographer: Skipped 41 frames!  The application may be doing too much work on its main thread.
04-04 10:30:13.738 2047-2047/mycompany.app W/Settings: Setting airplane_mode_on has moved from android.provider.Settings.System to android.provider.Settings.Global, returning read-only value.
04-04 10:30:19.394 2047-2047/mycompany.app D/Android, counter: 1
04-04 10:30:29.557 2047-2047/mycompany.app D/Android, counter: 2
04-04 10:30:51.787 2047-2047/mycompany.app D/Android, counter: 3
04-04 10:31:05.414 2047-2047/mycompany.app D/Android, counter: 4
04-04 10:31:15.590 2047-2047/mycompany.app D/Android, counter: 5
04-04 10:31:26.513 2047-2047/mycompany.app D/Android, counter: 6
04-04 10:31:32.510 2047-2047/mycompany.app D/Android, counter: 7
04-04 10:31:43.192 2047-2047/mycompany.app D/Android, counter: 8
04-04 10:31:49.566 2047-2047/mycompany.app D/Android, counter: 9

Server side logs :

I was called{clientId=412fqdbm458ip31je6r676za42t, data={name=hello, counter=1, type=false, timestamp=2016-04-04 10:30:29.547}, channel=/service/chat/5250, id=9}
Authenticated user is AKSHAY
I was called{clientId=412fqdbm458ip31je6r676za42t, data={name=wassup, counter=2, type=false, timestamp=2016-04-04 10:30:51.78}, channel=/service/chat/5250, id=12}
Authenticated user is AKSHAY
I was called{clientId=412fqdbm458ip31je6r676za42t, data={name=yoyo, counter=4, type=false, timestamp=2016-04-04 10:31:15.583}, channel=/service/chat/5250, id=16}
Authenticated user is AKSHAY
I was called{clientId=412fqdbm458ip31je6r676za42t, data={name=hhhh, counter=6, type=false, timestamp=2016-04-04 10:31:32.501}, channel=/service/chat/5250, id=18}
Authenticated user is AKSHAY
I was called{clientId=412fqdbm458ip31je6r676za42t, data={name=hhhhh, counter=8, type=false, timestamp=2016-04-04 10:31:49.557}, channel=/service/chat/5250, id=22}
Authenticated user is AKSHAY

Log images :

enter image description here

enter image description here

enter image description here

We are Borg
  • 5,117
  • 17
  • 102
  • 225
  • I doubt this is a CometD problem, as many others are using CometD on Android without problems. There is no evidence (as in log statements) that show the behavior you are describing, and the messages you send do not have any counter so that one can tell whether odd messages are sent while event messages are not. Seems more likely you have a problem elsewhere. Try remove code until you get the bare minimum CometD working, then start adding code again. – sbordet Apr 01 '16 at 09:22
  • @sbordet : This is just 4-5 lines of code, where I creating a map and sending the message. I can see both the Log.d messages, as well as the Listener on the server-side has a System.out, where again I can see if message arrives, and exactly alternate message arrives...That much I have confirmed, and my colleague as well. Stripping the code to bare minimum for any or all problem makes no sense, integration is an important aspect of any project, cannot ignore it... – We are Borg Apr 01 '16 at 09:27
  • @sbordet : I debugged the code and found that the toString method is failing. I have added the images for it in the main post, if there is any other information you require from the debugger, please let me know. Thank you.. :-) – We are Borg Apr 01 '16 at 15:21
  • @sbordet : Notice the code posted at bottom of image as well, if the httpClient is not started, I am starting it, and printing log. And as I already knew, not even once the Log message was printed, and still the alternate message thing kept going on. – We are Borg Apr 01 '16 at 15:33
  • It is not clear to me what do you mean by "alternate". If you have a counter, that is not evident from what you have posted here. If you don't have a counter, then you have to explain better what you mean by "alternate". The NPE you found in toString() is only possible if a `null` `ChannelId` is being passed to the channel constructor. CometD never does that. – sbordet Apr 01 '16 at 17:58
  • @sbordet : As per your saying, I have added a counter to the data being sent out and have logged it. I have uploaded images, code, and log at bottom of main post. I hope this helps. Kindly let me know. Thank you. :-) – We are Borg Apr 04 '16 at 08:38
  • Two things to try: 1) does your code work in non-Android environment ? 2) Does your code work in Android if you use Jetty instead of Tomcat ? – sbordet Apr 06 '16 at 13:36
  • @sbordet : 1) The server side code works, without any problem and with JavaScript API's in front-end, how is that related to Android is what I fail to understand 2) Same problem with Jetty, was the first thing we tried. .. You were not sure if it was sending alternate messages, now you are... If you know any Cometd developers, can you kindly share this question with them.. Thank you.. :-) – We are Borg Apr 06 '16 at 13:40

0 Answers0