Требования: 1. Метод main должен создавать новый объект типа Client и вызывать у него метод run. 2. Метод run должен создавать запускать новый поток, полученный с помощью метода getSocketThread. 3. Поток созданный с помощью метода getSocketThread должен быть отмечен как демон (setDaemon(true)). 4. После запуска нового socketThread метод run должен ожидать до тех пор, пока не будет пробужден. 5. До тех пор, пока флаг clientConnected равен true,с консоли должны считываться сообщения с помощью метода ConsoleHelper.readString. 6. Если была введена команда "exit" цикл считывания сообщений должен быть прерван. 7. Если метод shouldSentTextFromConsole возвращает true, должен быть вызван метод sendTextMessage со считанным текстом в качестве параметра.
public class Client {
    /**
     * Клиент, в начале своей работы, должен запросить у пользователя адрес и порт сервера, подсоединиться к
     * указанному адресу, получить запрос имени от сервера, спросить имя у пользователя, отправить имя пользователя
     * серверу, дождаться принятия имени сервером. После этого клиент может обмениваться текстовыми сообщениями с
     * сервером. Обмен сообщениями будет происходить в двух параллельно работающих потоках. Один будет заниматься
     * чтением из консоли и отправкой прочитанного серверу, а второй поток будет получать данные от сервера и выводить
     * их в консоль.
     */

    protected Connection connection;
    private volatile boolean clientConnected = false; // true - if client connected server

    protected String getServerAddress(){
        //make a request address of server of the user
        ConsoleHelper.writeMessage("Введите адрес сервера: ");
        return ConsoleHelper.readString();
    }

    protected  int getServerPort(){
        // make a request ports of server of the user
        ConsoleHelper.writeMessage("Введите порт сервера сервера: ");
        return ConsoleHelper.readInt();
    }

    protected String getUserName(){
        // make a request name of user
        ConsoleHelper.writeMessage("Введите порт сервера сервера: ");
        return ConsoleHelper.readString();
    }

    protected boolean shouldSendTextFromConsole(){return true;};

    protected SocketThread getSocketThread(){return new SocketThread();}

    protected void sendTextMessage(String text){
        try {
            connection.send(new Message(MessageType.TEXT, text));
        } catch (IOException e) {
            ConsoleHelper.writeMessage("не возможно отправить сообщение");
            clientConnected=false;
        }
    }

    public static void main(String[] args){
        Client client = new Client();
        client.run();
    }

    public  void run(){
        /**
         * Он должен создавать вспомогательный поток SocketThread, ожидать пока тот установит соединение с
         * сервером, а после этого в цикле считывать сообщения с консоли и отправлять их серверу. Условием
         * выхода из цикла будет отключение клиента или ввод пользователем команды ‘exit‘.
         */
        SocketThread socketThread = getSocketThread();
        socketThread.setDaemon(true);
        socketThread.start();
        try {
            synchronized (this){
                this.wait();
            }
        } catch (InterruptedException e) {
            ConsoleHelper.writeMessage("произошла ошибка, программа будет закрыта");
            System.exit(1);
            if(clientConnected){
                ConsoleHelper.writeMessage("Соединение установлено. Для выхода наберите команду ‘exit’");
                while (clientConnected) {
                    String text = ConsoleHelper.readString();
                    if (text.equalsIgnoreCase("exit")) {
                        break;
                    }else if(shouldSendTextFromConsole()){
                        sendTextMessage(text);
                    }
                }
            } else {
                ConsoleHelper.writeMessage("Произошла ошибка соединения");
            }
        }
    }

    public class SocketThread extends Thread{
    }

}