0

Issue:

After receiving a message from a the MessageListener class adds a message to a private final ObservableList<String> which in turn updates the GUI on change. the problem is that this happens inconsistently and for some unknown reason there seems to be 2 lists that interchange in adding the message to its list.

here is a log of this behavior:

INFO: Message received: 
Text: SSN= 1223 Requested amount= 11€ time= 110
ID: ID:78-192.168.0.23(84:be:e3:92:5b:b3)-1-1519325025180
Reply to: null
Feb 22, 2018 7:43:45 PM Bank.ABNAmbro addMessages
INFO: Adding message to List:SSN= 1223 Requested amount= 11€ time= 110
Feb 22, 2018 7:43:45 PM Bank.ABNAmbro addMessages
INFO: New size: 2

Feb 22, 2018 7:43:54 PM Bank.BankMessageListener onMessage
INFO: Message received: 
Text: SSN= 1223 Requested amount= 11€ time= 110
ID: ID:82-192.168.0.23(84:be:e3:92:5b:b3)-1-1519325034484
Reply to: null
Feb 22, 2018 7:43:54 PM Bank.ABNAmbro addMessages
INFO: Adding message to List:SSN= 1223 Requested amount= 11€ time= 110
Feb 22, 2018 7:43:54 PM Bank.ABNAmbro addMessages
INFO: New size: 9

Feb 22, 2018 7:43:55 PM Bank.BankMessageListener onMessage
INFO: Message received: 
Text: SSN= 1223 Requested amount= 11€ time= 110
ID: ID:86-192.168.0.23(84:be:e3:92:5b:b3)-1-1519325035575
Reply to: null
Feb 22, 2018 7:43:55 PM Bank.ABNAmbro addMessages
INFO: Adding message to List:SSN= 1223 Requested amount= 11€ time= 110
Feb 22, 2018 7:43:55 PM Bank.ABNAmbro addMessages
INFO: New size: 10

Feb 22, 2018 7:43:57 PM Bank.BankMessageListener onMessage
INFO: Message received: 
Text: SSN= 1223 Requested amount= 11€ time= 110
ID: ID:90-192.168.0.23(84:be:e3:92:5b:b3)-1-1519325037074
Reply to: null
Feb 22, 2018 7:43:57 PM Bank.ABNAmbro addMessages
INFO: Adding message to List:SSN= 1223 Requested amount= 11€ time= 110
Feb 22, 2018 7:43:57 PM Bank.ABNAmbro addMessages
INFO: New size: 11

Feb 22, 2018 7:43:58 PM Bank.BankMessageListener onMessage
INFO: Message received: 
Text: SSN= 1223 Requested amount= 11€ time= 110
ID: ID:94-192.168.0.23(84:be:e3:92:5b:b3)-1-1519325038499
Reply to: null
Feb 22, 2018 7:43:58 PM Bank.ABNAmbro addMessages
INFO: Adding message to List:SSN= 1223 Requested amount= 11€ time= 110
Feb 22, 2018 7:43:58 PM Bank.ABNAmbro addMessages
INFO: New size: 3

If I mock the MessageListener class to just add a String every few seconds the log shows 2 lists that have the same size.

Feb 22, 2018 9:12:16 PM Bank.ABNAmbro addMessages
INFO: Adding message to List:Test 0
Feb 22, 2018 9:12:16 PM Bank.ABNAmbro addMessages
INFO: New sieze: 0

Feb 22, 2018 9:12:16 PM Bank.ABNAmbro addMessages
INFO: Adding message to List:Test 0
Feb 22, 2018 9:12:16 PM Bank.ABNAmbro addMessages
INFO: New sieze: 0

Feb 22, 2018 9:12:17 PM Bank.ABNAmbro addMessages
INFO: Adding message to List:Test 1
Feb 22, 2018 9:12:17 PM Bank.ABNAmbro addMessages
INFO: New sieze: 1

Feb 22, 2018 9:12:17 PM Bank.ABNAmbro addMessages
INFO: Adding message to List:Test 1
Feb 22, 2018 9:12:17 PM Bank.ABNAmbro addMessages
INFO: New sieze: 1

Feb 22, 2018 9:12:18 PM Bank.ABNAmbro addMessages
INFO: Adding message to List:Test 2
Feb 22, 2018 9:12:18 PM Bank.ABNAmbro addMessages
INFO: New sieze: 2

Feb 22, 2018 9:12:18 PM Bank.ABNAmbro addMessages
INFO: Adding message to List:Test 2
Feb 22, 2018 9:12:18 PM Bank.ABNAmbro addMessages
INFO: New sieze: 2

The Controller class:

package Bank;

import javafx.application.Application;
import javafx.application.Platform;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.control.ListView;
import javafx.stage.Stage;

import javax.jms.*;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;

public class ABNAmbro extends Application implements Bank {

    private String tile = "bank";

    private List<String> messages = new ArrayList<String>();

    private final ObservableList<String> olMessages = FXCollections.observableArrayList(messages);

    Logger logger = Logger.getLogger("ABNAmbro");

    @FXML
    ListView lsRequestView;

    @Override
    public void start(Stage primaryStage) throws IOException {
        Parent root = FXMLLoader.load(getClass().getResource("/Bank/Bank.fxml"));

        Scene scene = new Scene(root);

        primaryStage.setTitle(tile);
        primaryStage.setScene(scene);
        primaryStage.show();
    }

    @FXML
    public void initialize() {
        lsRequestView.setItems(olMessages);
    }

    public ABNAmbro() throws NamingException {

        tile = "ABNAmbro Loan Department.";
        String queuename = "ABNBankqueue";
        MessageListener messageListener = new BankMessageListener(this);

        InitialContext initialContext = new InitialContext();

        //JMS 2.0 lookup
        ConnectionFactory connectionFactory = (ConnectionFactory) initialContext.lookup("java:comp/DefaultJMSConnectionFactory");

        //Creating context to reseive messages
        JMSContext context = connectionFactory.createContext();
        Queue queue = (Queue) initialContext.lookup(queuename);

        //create consumer and add a message listener to it so it can get its message async 
        JMSConsumer consumer = context.createConsumer(queue);
        consumer.setMessageListener(messageListener);

    }

    @FXML
    public void SendResponse(ActionEvent event) {

    }

    public void addMessages(final String messages) {
        logger.log(Level.INFO,"Adding message to List:" + messages);
        Platform.runLater(new Runnable() {
            @Override
            public void run() {

                //adding message to list
                olMessages.add(messages);
            }
        });
        logger.log(Level.INFO, "New sieze: " + olMessages.size());
    }

}

MessageListener:

package Bank;

import javax.jms.JMSException;
import javax.jms.Message;
import javax.jms.MessageListener;
import javax.jms.TextMessage;
import java.util.logging.Level;
import java.util.logging.Logger;

public class BankMessageListener implements MessageListener{

    private Bank bank;
    private Logger logger;

    public BankMessageListener(Bank bank){
        this.bank = bank;
        logger = Logger.getLogger("BankMessageListener");
    }

    public void onMessage(final Message message) {
        try {
            logger.log(Level.INFO,"Message received: \n" +
                    "Text: "+((TextMessage)message).getText()
                    + "\nID: " +message.getJMSMessageID()
                    + "\nReply to: "  +((message.getJMSReplyTo() != null) ? message.getJMSReplyTo().toString() : "null")

            );
            bank.addMessages(((TextMessage) message).getText());
        } catch (JMSException e) {
            e.printStackTrace();
        }
    }
}
Luuky19
  • 169
  • 1
  • 1
  • 11
  • The `Platform.runLater(...)` is probably better in the controller class (you presumably mean "Controller class", not "Application class") than in the message listener, but it shouldn't make any difference. I would: 1. Write a mock message listener that just generates messages periodically and sends them, without the distributed application. That way you can isolate the problems to the UI application, and not the network. 2. Add logging both to the message listener and the controller's `addMessages()` method. – James_D Feb 22 '18 at 18:21
  • If you still can't fix it from there, and it's showing the same issues with the "mock" message listener, create and post a [MCVE] with those issues (which will be possible since it doesn't rely on JMS any more). There's not really enough information to help you fix it here: there's nothing wrong with the code that you posted. – James_D Feb 22 '18 at 18:22
  • Thanks for the feedback. I Updated the post to hopefully better reflect the issue. – Luuky19 Feb 22 '18 at 20:18
  • 1
    You create two instances of the `MessageListener`: one for the application, and one for the controller. The list view in the application instance is null, so obviously messages sent to that cannot be displayed (you should be seeing null pointer exceptions all over the place). Why are you trying to use the same class for the application and for the controller? – James_D Feb 22 '18 at 20:24
  • 1
    Ah, yes: you don't get null pointer exceptions, because you initialize the list in the initializer. The list belonging to the application isn't connected to the list view (because you make that connection in the `initialize()` method, which is only called on the controller). So the messages passed to the application just sit in the list and are never displayed. The messages passed to the controller are placed in the list which is actually connected to the list view. So you only see the messages that happen to be handled by the message listener created by the controller. – James_D Feb 22 '18 at 20:36
  • *facepalm* I indeed forgot to remove the constructor and move the code back into `initialize()` method. after moving it back into `initialize()` everything worked fine. – Luuky19 Feb 22 '18 at 20:44
  • Well, actually, you really should not use the same class for both the application and the controller. So as long as you follow the intended use of the classes, it's just fine to leave that code in the *controller* constructor. Why? 1. You should not have two instances of your `Application` class (since it represents the application, and you only have one application). 2. You should not have instances of classes with fields that remain uninitialized. And 3. you should not use the same class for two entirely different purposes (principle of single responsibility). – James_D Feb 22 '18 at 20:46

0 Answers0