Ситуация такая, имеется клиент-серверное приложение, обычный сетевой чат. Исходники: 3 модуля Клиент, Сервер и модуль отвечающий за соединение, первый и второй модули зависят от третьего. (Далее г**но код, а потом суть вопроса):
Начнем с третьего модуля, а именно сетевого:
Интерфейс TCPConnectionListenerpublic interface TCPConnectionListener {
void onConnectionReady(TCPConnection tcpConnection);
void onReceiveString(TCPConnection tcpConnection, String value);
void onDisconnect(TCPConnection tcpConnection);
void onExeption(TCPConnection tcpConnection, Exception e);
}
Класс TCPConnectionimport java.io.*;
import java.net.Socket;
import java.nio.charset.Charset;
public class TCPConnection {
private final Socket socket;
private final Thread rxThread;
private final TCPConnectionListener eventListener;
private final BufferedReader in;
private final BufferedWriter out;
public TCPConnection(TCPConnectionListener eventListener, String ip, int port) throws IOException {
this(eventListener, new Socket(ip,port));
}
public TCPConnection(TCPConnectionListener eventListener, Socket socket)throws IOException {
this.socket =socket;
this.eventListener=eventListener;
in =new BufferedReader(new InputStreamReader(socket.getInputStream(), Charset.forName("UTF-8")));
out =new BufferedWriter(new OutputStreamWriter(socket.getOutputStream(), Charset.forName("UTF-8")));
rxThread=new Thread(new Runnable() {
@Override
public void run() {
try {
eventListener.onConnectionReady(TCPConnection.this);
while (!rxThread.isInterrupted()){
eventListener.onReceiveString(TCPConnection.this, in.readLine());
}
} catch (IOException e) {
eventListener.onExeption(TCPConnection.this,e);
}finally {
eventListener.onDisconnect(TCPConnection.this);
}
}
});
rxThread.start();
}
public synchronized void sendMessage(String value){
try {
out.write(value+"\r\n");
out.flush();
} catch (IOException e) {
eventListener.onExeption(TCPConnection.this, e);
setDissconnect();
}
}
public synchronized void setDissconnect(){
rxThread.interrupt();
try {
socket.close();
} catch (IOException e) {
eventListener.onExeption(TCPConnection.this, e);
}
}
@Override
public String toString() {
return "TCPConnection: "+socket.getInetAddress()+" port: "+socket.getPort();
}
}
Далее серверный модуль:
Класс ChatServerimport java.io.IOException;
import java.net.ServerSocket;
import java.util.ArrayList;
public class ChatServer implements TCPConnectionListener{
public static void main(String[]args){
new ChatServer();
}
private final ArrayList<TCPConnection> connections =new ArrayList<>();
private ChatServer(){
System.out.println("Server running...");
try(ServerSocket serverSocket=new ServerSocket(8189)){
while (true){
try {
new TCPConnection(this, serverSocket.accept());
}catch (IOException e){
System.out.println("TCPConnection exeption...");
}}
}catch (IOException e){
throw new RuntimeException(e);
}
}
@Override
public synchronized void onConnectionReady(TCPConnection tcpConnection) {
connections.add(tcpConnection);
sendToAllConnections("Client connect: "+tcpConnection);
}
@Override
public synchronized void onReceiveString(TCPConnection tcpConnection, String value) {
System.out.println("ttt");
sendToAllConnections(value);
}
@Override
public synchronized void onDisconnect(TCPConnection tcpConnection) {
connections.remove(tcpConnection);
sendToAllConnections("Client disconnect: "+tcpConnection);
}
@Override
public synchronized void onExeption(TCPConnection tcpConnection, Exception e) {
System.out.println("TCPConnections exeption...");
}
private void sendToAllConnections(String message){
System.out.println(message);
final int lh=connections.size();
for (int i=0;i<lh;i++){
connections.get(i).sendMessage(message);
}
}
}
И последний модуль - клиентский. Он состоит из главного класса, контроллера, и fxml файла:
Главный классimport javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.stage.Stage;
public class ClientWindow extends Application {
@Override
public void start(Stage primaryStage) throws Exception{
FXMLLoader loader =new FXMLLoader(getClass().getResource("sample.fxml"));
Parent root = loader.load();
primaryStage.setTitle("Hello World");
primaryStage.setResizable(false);
primaryStage.setScene(new Scene(root, 300, 500));
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}
Класс контроллераimport javafx.fxml.FXML;
import javafx.scene.control.TextArea;
import javafx.scene.control.TextField;
import javafx.scene.input.MouseEvent;
import java.io.IOException;
public class Controller implements TCPConnectionListener{
@FXML
public TextArea dialogWn;
@FXML
public TextField nickname;
TCPConnection connection;
public void onToSendClick(MouseEvent mouseEvent) {
connection.sendMessage(nickname.getText());
}
public void onExitClicked(MouseEvent mouseEvent) {
try {
connection =new TCPConnection(this, "127.0.0.1", 8189);
} catch (IOException e) {
e.printStackTrace();
}
}
public void printMessage(String msg){
dialogWn.appendText(msg);
}
@Override
public void onConnectionReady(TCPConnection tcpConnection) {
}
@Override
public void onReceiveString(TCPConnection tcpConnection, String value) {
printMessage(value+"\n\r");
}
@Override
public void onDisconnect(TCPConnection tcpConnection) {
}
@Override
public void onExeption(TCPConnection tcpConnection, Exception e) {
}
}
Шаблон<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.control.Button?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.control.ScrollPane?>
<?import javafx.scene.control.TextArea?>
<?import javafx.scene.control.TextField?>
<?import javafx.scene.layout.AnchorPane?>
<?import javafx.scene.text.Font?>
<AnchorPane prefHeight="500.0" prefWidth="300.0" xmlns="http://javafx.com/javafx/8.0.172-ea" xmlns:fx="http://javafx.com/fxml/1" fx:controller="Controller">
<children>
<Label prefHeight="40.0" prefWidth="80.0" text="Ваш ник:" textFill="#3c39a3" underline="true" AnchorPane.leftAnchor="20.0" AnchorPane.topAnchor="0.0">
<font>
<Font name="System Bold" size="17.0" />
</font>
</Label>
<TextField fx:id="nickname" prefHeight="25.0" prefWidth="174.0" AnchorPane.rightAnchor="20.0" AnchorPane.topAnchor="8.0" />
<ScrollPane prefHeight="200.0" prefWidth="200.0" AnchorPane.bottomAnchor="50.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="40.0">
<content>
<TextArea fx:id="dialogWn" editable="false" prefHeight="408.0" prefWidth="298.0" />
</content>
</ScrollPane>
<Button fx:id="send" mnemonicParsing="false" onMouseClicked="#onToSendClick" prefHeight="25.0" prefWidth="100.0" text="Отправить" AnchorPane.bottomAnchor="10.0" AnchorPane.leftAnchor="40.0" />
<Button fx:id="exit" mnemonicParsing="false" onMouseClicked="#onExitClicked" prefHeight="25.0" prefWidth="100.0" text="Выход" AnchorPane.bottomAnchor="10.0" AnchorPane.rightAnchor="40.0" />
</children>
</AnchorPane>
Все вроде работает, но проблема в том , что я в контроллере создаю соединение (я потом спец кнопку добавлю, сейчас оно создается по кнопке выход, а текст диалога вводится в поле имени), т.е. у меня все легло на контроллер. Я понимаю, что это дикие костыли. Как это поправить? Даже если я создам отдельный класс, создам в нем соединение, унаследую его от интерфейса все хорошо, я даже смогу передать туда объект контроллер, дабы выводить смс на форму полученные с сервера, но я не смогу сделать обратного, из контроллера передать сообщение в этот класс. Как это решить, и как вообще правильно строятся данные приложения??