Search code examples
javajavafxdecouplingcustom-events

How can i decouple my networkmanager using events?


i'm writing a program that connects with various TCP network devices. The GUI is made using JavaFX. The whole connection part is in its own package "Network". Roughly described, it looks like this: (I don't know much about UML, no blaming plaese :/ - i just needed a way to quickly describe how my program structure looks). https://i.sstatic.net/PSdsH.jpg

okay thats how it is: The TCP classes are stored in a synchronized List in "NetworkManager". These classes hold information about the connection (how much data received yet, ip, mac etc.). The Rcv-Thread constantly tries to receive data.

well, this is what i want: As soon as the Rcv-Thread receives a specific message, the controller should be invoked to do something (GUI refresh or whatever). Also the controller should stay decoupled from the "Network" module-> it is reused in another project. I want to achieve this behaviour through an custom event. In short: TCP-Rcv-Thread needs to be able to give information to the Controller. But i dont really know how to get it all to work. Lets see where i am:

  • I have an event class in the "Network" module.

    import java.util.EventObject;
    
    public class XEvent extends EventObject{
      String message;
        public XEvent(Object source, String message) {
        super(source);
        this.message = message;
      }
    
    public String getMessage() {
        return message;
     }
    }  
    
  • I have a listener class in the "Network" module.

     import java.util.EventListener;
        public interface XListener extends EventListener{
        void handlerMethod1(XEvent event);
        void handlerMethod2(XEvent event);
    }
    
  • I tried to prepare my Rcv-Thread for firing the event:

    import javax.swing.event.EventListenerList;
    import java.io.IOException;
    
    public class ReceiveDataThread implements Runnable {
    protected EventListenerList listenerList = new EventListenerList();
    }
    
    protected void addXListener(XListener xListener) {
            listenerList.add(XListener.class, xListener);
        }
    
    
    
    protected void removeListener(XListener xListener) {
            listenerList.remove(XListener.class, xListener);
        }
    
    protected void fireHandlerMethod1(String message) {
        XEvent event = null;
        Object[] list = listenerList.getListenerList();
        for (int i = 0; i < list.length; i += 2) {
            if (list[i] == XListener.class) {
                if (event == null) event = new XEvent(this, message);
                XListener l = (XListener) list[i + 1];
                l.handlerMethod1(event);
            }
        }
    }
    
    protected void fireHandlerMethod2(String message) {
        XEvent event = null;
        Object[] list = listenerList.getListenerList();
        for (int i = 0; i < list.length; i += 2) {
            if (list[i] == XListener.class) {
                if (event == null) event = new XEvent(this, message);
                XListener l = (XListener) list[i + 1];
                l.handlerMethod2(event);
            }
        }
    }
    
    @Override
    public void run() {
        String s;
        while (!stopThread) {
            s = receiveData();
            System.out.println("test");
            fireHandlerMethod1(s);
        }
    }
    
  • The Controller (this class should react on the custom events) implements the Listener:

    public class Controller implements Initializable, XListener {
    @Override
    public void handlerMethod1(XEvent event) {
        System.out.println("Event1: " + event.getMessage());
    }
    
    @Override
    public void handlerMethod2(XEvent event) {
    
     }
    }
    

And from there on i'm not really shure how to get it work that my events (fired from my Rcv-Thread) are noticed by my controller class. I think i have to add a listener to every Rcv-Thread object via the controller class (just like when i use a ButtonListener, ...) . The problem is: from my TCP Class i can't access the Rcv-Thread-object's addXListener method - even when set to public (but i can access the Rcv-Thread-Classes from the list). I tried to read as much as i can about the problem but cant figure out how to get this to work. What am i missing?

edit1: TCP class:

public class TCPClass{
private Thread receiveDataThread;
private String MAC;     
private InetAddress IP;
private Socket socket = new Socket();  
private int tcpSendPort;
private int timeOut = 10;    
private ObjectOutputStream objectOutputStream;
private BufferedReader bufferedReader;
private String connectionStatus = "offline";  


public TCPClass(DatagramPacket datagramPacket) {
    IP = datagramPacket.getAddress();
    setConnectionStatusOnline();
    tcpSendPort = 50000 + NetworkManager.getNumberOfConnections();
    MAC = extractMac(datagramPacket);
}
    public void connect(int tcpPort) {
    try {
        socket = new Socket(IP, tcpPort, null, tcpSendPort);
        bufferedReader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
        receiveDataThread = new Thread(new ReceiveDataThread(this));
        receiveDataThread.start();
        InputStreamReader(socket.getInputStream()));
    } catch (IOException e) {
        e.printStackTrace();
        System.out.println("on MAC: " + getMAC() + "\non Device:" + toString());
    }
    if (socket.isConnected()) {
        setConnectionStatusConnected();
    }
}
}

The NetworkManager creates an object of TCPClass and calls the connect() method.


Solution

  • Ok so after days i figured it out myself. The main problem was that i was not able to call the addXListener() method of Rcv-Thread from the Controller. I took the Custom Event stuff out of the Rcv-Thread and moved it to the TCP-Class. Now i'm able to add the Listener to these classes. If i want to fire an event from the Rcv-Thread i simply call fireHandlerMethod() from its superclass (TCP-Class) - and everything works as expected.