diff --git a/OWNER.md b/OWNER.md new file mode 100644 index 0000000..ba42dad --- /dev/null +++ b/OWNER.md @@ -0,0 +1 @@ +Кудрявцев Дмитрий Вальтерович diff --git a/config.xml b/config.xml index 7d4cac2..75c54c2 100644 --- a/config.xml +++ b/config.xml @@ -1,16 +1,12 @@ - - + + - - + + - - - - diff --git a/pom.xml b/pom.xml index f822ba6..b28dea2 100644 --- a/pom.xml +++ b/pom.xml @@ -28,7 +28,7 @@ exec-maven-plugin 1.4.0 - arhangel.dim.lections.jdbc.JdbcExample + arhangel.dim.core.jdbc.DataBaseOrganizer diff --git a/src/main/java/arhangel/dim/client/Client.java b/src/main/java/arhangel/dim/client/Client.java deleted file mode 100644 index f9daeea..0000000 --- a/src/main/java/arhangel/dim/client/Client.java +++ /dev/null @@ -1,195 +0,0 @@ -package arhangel.dim.client; - -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.net.Socket; -import java.util.Arrays; -import java.util.Scanner; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import arhangel.dim.container.Container; -import arhangel.dim.container.InvalidConfigurationException; -import arhangel.dim.core.messages.Message; -import arhangel.dim.core.messages.TextMessage; -import arhangel.dim.core.messages.Type; -import arhangel.dim.core.net.ConnectionHandler; -import arhangel.dim.core.net.Protocol; -import arhangel.dim.core.net.ProtocolException; - -/** - * Клиент для тестирования серверного приложения - */ -public class Client implements ConnectionHandler { - - /** - * Механизм логирования позволяет более гибко управлять записью данных в лог (консоль, файл и тд) - * */ - static Logger log = LoggerFactory.getLogger(Client.class); - - /** - * Протокол, хост и порт инициализируются из конфига - * - * */ - private Protocol protocol; - private int port; - private String host; - - /** - * Тред "слушает" сокет на наличие входящих сообщений от сервера - */ - private Thread socketThread; - - /** - * С каждым сокетом связано 2 канала in/out - */ - private InputStream in; - private OutputStream out; - - public Protocol getProtocol() { - return protocol; - } - - public void setProtocol(Protocol protocol) { - this.protocol = protocol; - } - - public int getPort() { - return port; - } - - public void setPort(int port) { - this.port = port; - } - - public String getHost() { - return host; - } - - public void setHost(String host) { - this.host = host; - } - - public void initSocket() throws IOException { - Socket socket = new Socket(host, port); - in = socket.getInputStream(); - out = socket.getOutputStream(); - - /** - * Инициализируем поток-слушатель. Синтаксис лямбды скрывает создание анонимного класса Runnable - */ - socketThread = new Thread(() -> { - final byte[] buf = new byte[1024 * 64]; - log.info("Starting listener thread..."); - while (!Thread.currentThread().isInterrupted()) { - try { - // Здесь поток блокируется на ожидании данных - int read = in.read(buf); - if (read > 0) { - - // По сети передается поток байт, его нужно раскодировать с помощью протокола - Message msg = protocol.decode(Arrays.copyOf(buf, read)); - onMessage(msg); - } - } catch (Exception e) { - log.error("Failed to process connection: {}", e); - e.printStackTrace(); - Thread.currentThread().interrupt(); - } - } - }); - - socketThread.start(); - } - - /** - * Реагируем на входящее сообщение - */ - @Override - public void onMessage(Message msg) { - log.info("Message received: {}", msg); - } - - /** - * Обрабатывает входящую строку, полученную с консоли - * Формат строки можно посмотреть в вики проекта - */ - public void processInput(String line) throws IOException, ProtocolException { - String[] tokens = line.split(" "); - log.info("Tokens: {}", Arrays.toString(tokens)); - String cmdType = tokens[0]; - switch (cmdType) { - case "/login": - // TODO: реализация - break; - case "/help": - // TODO: реализация - break; - case "/text": - // FIXME: пример реализации для простого текстового сообщения - TextMessage sendMessage = new TextMessage(); - sendMessage.setType(Type.MSG_TEXT); - sendMessage.setText(tokens[1]); - send(sendMessage); - break; - // TODO: implement another types from wiki - - default: - log.error("Invalid input: " + line); - } - } - - /** - * Отправка сообщения в сокет клиент -> сервер - */ - @Override - public void send(Message msg) throws IOException, ProtocolException { - log.info(msg.toString()); - out.write(protocol.encode(msg)); - out.flush(); // принудительно проталкиваем буфер с данными - } - - @Override - public void close() { - // TODO: написать реализацию. Закройте ресурсы и остановите поток-слушатель - } - - public static void main(String[] args) throws Exception { - - Client client = null; - // Пользуемся механизмом контейнера - try { - Container context = new Container("client.xml"); - client = (Client) context.getByName("client"); - } catch (InvalidConfigurationException e) { - log.error("Failed to create client", e); - return; - } - try { - client.initSocket(); - - // Цикл чтения с консоли - Scanner scanner = new Scanner(System.in); - System.out.println("$"); - while (true) { - String input = scanner.nextLine(); - if ("q".equals(input)) { - return; - } - try { - client.processInput(input); - } catch (ProtocolException | IOException e) { - log.error("Failed to process user input", e); - } - } - } catch (Exception e) { - log.error("Application failed.", e); - } finally { - if (client != null) { - client.close(); - } - } - } -} diff --git a/src/main/java/arhangel/dim/client/ClientMain.java b/src/main/java/arhangel/dim/client/ClientMain.java new file mode 100644 index 0000000..5db09f9 --- /dev/null +++ b/src/main/java/arhangel/dim/client/ClientMain.java @@ -0,0 +1,111 @@ +package arhangel.dim.client; + +import arhangel.dim.container.Container; +import arhangel.dim.container.beans.WebConnection; +import arhangel.dim.core.message.Message; + +import java.io.BufferedReader; +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.InputStreamReader; +import java.net.Socket; +import java.util.concurrent.ArrayBlockingQueue; +import java.util.concurrent.BlockingQueue; + +public class ClientMain { + + private Socket socket; + + private DataInputStream in; + private DataOutputStream out; + + /** + * Нить, отвечающая за получение сообщений от сервера + */ + private Thread listenThread; + + /** + * Нить, отвечающая за отправку сообщений на сервер + */ + private Thread writeThread; + + /** + * Очередь, для обмена сообщений для отправки между главной нитью и writeThread + */ + private BlockingQueue messagesToWrite; + + /** + * Классы, отвечающие за работу нитей + */ + private MessageListener listener; + private MessageWriter writer; + + public ClientMain() { + } + + public void init() { + try { + Container container = new Container("C:\\Users\\Дмитрий\\Documents\\technotrack\\java\\messenger\\config.xml"); + WebConnection portAndHost = (WebConnection)container.getByClass("arhangel.dim.container.beans.WebConnection"); + int port = portAndHost.getPort(); + String host = portAndHost.getHost(); + socket = new Socket(host, port); + in = new DataInputStream(socket.getInputStream()); + out = new DataOutputStream(socket.getOutputStream()); + messagesToWrite = new ArrayBlockingQueue<>(10); + listener = new MessageListener(in); + writer = new MessageWriter(out, messagesToWrite); + listenThread = new Thread(listener); + writeThread = new Thread(writer); + listenThread.start(); + writeThread.start(); + } catch (Exception e) { + System.err.println("Client initialization: exception caught: " + e.toString()); + } + } + + public void handleUserCommands() throws Exception { + BufferedReader reader = new BufferedReader(new InputStreamReader(System.in)); + String line; + while (true) { + line = reader.readLine(); + Message writeMessage; + if (line.startsWith("/")) { + writeMessage = new Message(); + writeMessage.setMessage(line); + messagesToWrite.put(writeMessage); + if (line.equals("/exit")) { + System.out.println("Closing.."); + stopThreads(); + break; + } + } else { + writeMessage = new Message(); + writeMessage.setMessage(line); + messagesToWrite.put(writeMessage); + } + } + } + + public void stopThreads() { + try { + listenThread.interrupt(); + writeThread.interrupt(); + // join + } catch (Exception e) { + System.err.println("Failed to stop threads " + e.toString()); + } finally { + IoUtil.closeQuietly(socket); + } + } + + public static void main(String[] args) { + ClientMain threadedClient = new ClientMain(); + threadedClient.init(); + try { + threadedClient.handleUserCommands(); + } catch (Exception e) { + System.err.println("Client: exception caught: " + e.toString()); + } + } +} diff --git a/src/main/java/arhangel/dim/lections/socket/IoUtil.java b/src/main/java/arhangel/dim/client/IoUtil.java similarity index 91% rename from src/main/java/arhangel/dim/lections/socket/IoUtil.java rename to src/main/java/arhangel/dim/client/IoUtil.java index dcb4176..1766d38 100644 --- a/src/main/java/arhangel/dim/lections/socket/IoUtil.java +++ b/src/main/java/arhangel/dim/client/IoUtil.java @@ -1,4 +1,4 @@ -package arhangel.dim.lections.socket; +package arhangel.dim.client; import java.io.Closeable; diff --git a/src/main/java/arhangel/dim/client/MessageListener.java b/src/main/java/arhangel/dim/client/MessageListener.java new file mode 100644 index 0000000..3a9e1b6 --- /dev/null +++ b/src/main/java/arhangel/dim/client/MessageListener.java @@ -0,0 +1,65 @@ +package arhangel.dim.client; + +import arhangel.dim.core.message.AnswerMessage; +import arhangel.dim.core.message.Protocol; +import arhangel.dim.core.message.SerializationProtocol; + +import java.io.DataInputStream; + +/** + * Класс, получающий сообщения от сервера + */ +public class MessageListener implements Runnable { + private DataInputStream reader; + + /** + * Протокол кодирования + */ + private Protocol readProtocol; + + public MessageListener(DataInputStream reader) { + this.reader = reader; + readProtocol = new SerializationProtocol<>(); + } + + @Override + public void run() { + try { + while (!Thread.currentThread().isInterrupted()) { + byte[] buf = new byte[1024 * 60]; + int readSize = reader.read(buf); + if (readSize > 0) { + AnswerMessage answer = readProtocol.decode(buf); + handleAnswer(answer); + } + } + } catch (Exception e) { + System.err.println("Listener: exception caught: " + e.toString()); + } + } + + public void handleAnswer(AnswerMessage answer) throws Exception { + AnswerMessage.Value type = answer.getResult(); + String message = answer.getMessage(); + switch (type) { + case SUCCESS: + System.out.println(message); + break; + case ERROR: + System.out.println("Error:"); + System.out.println(message); + break; + case LOGIN: + System.out.println("Error:\nPlease login first"); + break; + case NUM_ARGS: + System.out.println("Error:\nWrong number of arguments"); + break; + case CHAT: + System.out.println(message); + break; + default: + break; + } + } +} diff --git a/src/main/java/arhangel/dim/client/MessageWriter.java b/src/main/java/arhangel/dim/client/MessageWriter.java new file mode 100644 index 0000000..1f2f6bd --- /dev/null +++ b/src/main/java/arhangel/dim/client/MessageWriter.java @@ -0,0 +1,39 @@ +package arhangel.dim.client; + +import arhangel.dim.core.message.Message; +import arhangel.dim.core.message.Protocol; +import arhangel.dim.core.message.SerializationProtocol; + +import java.io.DataOutputStream; +import java.util.concurrent.BlockingQueue; + +/** + * Класс, отправляющий сообщения серверу + */ + +public class MessageWriter implements Runnable { + + private DataOutputStream out; + private BlockingQueue messagesToWrite; + + private Protocol writeProtocol; + + public MessageWriter(DataOutputStream out, BlockingQueue messagesToWrite) { + this.out = out; + this.messagesToWrite = messagesToWrite; + writeProtocol = new SerializationProtocol<>(); + } + + @Override + public void run() { + try { + while (!Thread.currentThread().isInterrupted()) { + Message messageToWrite = messagesToWrite.take(); + out.write(writeProtocol.encode(messageToWrite)); + out.flush(); + } + } catch (Exception e) { + System.err.println("MessageWriter: exception caught " + e.toString()); + } + } +} diff --git a/src/main/java/arhangel/dim/container/Bean.java b/src/main/java/arhangel/dim/container/Bean.java index 34b8f1e..4ed7463 100644 --- a/src/main/java/arhangel/dim/container/Bean.java +++ b/src/main/java/arhangel/dim/container/Bean.java @@ -49,4 +49,4 @@ public String toString() { ", properties=" + properties + '}'; } -} +} \ No newline at end of file diff --git a/src/main/java/arhangel/dim/container/BeanGraph.java b/src/main/java/arhangel/dim/container/BeanGraph.java index 306c0e6..3c44915 100644 --- a/src/main/java/arhangel/dim/container/BeanGraph.java +++ b/src/main/java/arhangel/dim/container/BeanGraph.java @@ -1,50 +1,154 @@ package arhangel.dim.container; +import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; -/** - * - */ public class BeanGraph { - // Граф представлен в виде списка связности для каждой вершины + // Граф представляем в виде списка связности private Map> vertices = new HashMap<>(); + private Map used; + private Map left; //вершины из которых вышли в dfs + private List answerForSort; + + public BeanGraph() { + } + + public BeanGraph(List beans) { + beans.forEach(this::addVertex); + } /** * Добавить вершину в граф + * * @param value - объект, привязанный к вершине */ public BeanVertex addVertex(Bean value) { - return null; + BeanVertex beanVertex = new BeanVertex(value); + if (vertices.containsKey(beanVertex)) { + return beanVertex; + } + vertices.put(beanVertex, new ArrayList<>()); + + //добавляем ребра в новую вершину (т.к порядок добавления может быть рандомным и пердыдущие вершины ждут эту + for (BeanVertex tmp : vertices.keySet()) { + for (Property property : tmp.getBean().getProperties().values()) { + if (property.getType() == ValueType.REF && property.getValue().equals(value.getName())) { + addEdge(tmp, beanVertex); + } + } + } + + //добавляем ребра из новой вершины + for (Property property : value.getProperties().values()) { + if (property.getType() == ValueType.REF) { + for (BeanVertex tmp : vertices.keySet()) { + if (tmp.getBean().getName().equals(property.getValue())) { + addEdge(beanVertex, tmp); + } + } + } + } + return beanVertex; } /** * Соединить вершины ребром + * * @param from из какой вершины - * @param to в какую вершину + * @param to в какую вершину */ - public void addEdge(BeanVertex from ,BeanVertex to) { + public void addEdge(BeanVertex from, BeanVertex to) { + List beanVertexes = getLinked(from); + if (beanVertexes.contains(to)) { + return; + } + beanVertexes.add(to); } /** * Проверяем, связаны ли вершины */ public boolean isConnected(BeanVertex v1, BeanVertex v2) { - return false; + return getLinked(v1).contains(v2); } /** * Получить список вершин, с которыми связана vertex */ public List getLinked(BeanVertex vertex) { - return null; + return vertices.get(vertex); } /** * Количество вершин в графе */ public int size() { - return 0; + return vertices.size(); + } + + /** + * Проверка на отсутствие циклов + */ + public boolean checkCycle() { + used = new HashMap<>(); + left = new HashMap<>(); + for (BeanVertex tmp : vertices.keySet()) { + used.put(tmp, false); + left.put(tmp, false); + } + for (BeanVertex tmp : vertices.keySet()) { + if (!used.get(tmp)) { + if (dfsCheck(tmp)) { + return false; + } + } + } + return true; + } + + public List topSort() { + answerForSort = new ArrayList<>(); + used = new HashMap<>(); + for (BeanVertex tmp : vertices.keySet()) { + used.put(tmp, false); + } + for (BeanVertex tmp : vertices.keySet()) { + if (!used.get(tmp)) { + dfs(tmp); + } + } + ArrayList reverseAnswer = new ArrayList<>(); + for (int i = 0; i < size(); ++i) { + reverseAnswer.add(answerForSort.get(i)); + } + + return reverseAnswer; + } + + private void dfs(BeanVertex tmp) { + used.put(tmp, true); + for (BeanVertex nextBean : getLinked(tmp)) { + if (!used.get(nextBean)) { + dfs(nextBean); + } + } + answerForSort.add(tmp); + } + + // Проверка на то, есть ли цикл из этой вершины + private boolean dfsCheck(BeanVertex tmp) { + used.put(tmp, true); + for (BeanVertex nextBean : getLinked(tmp)) { + if (used.get(nextBean) && !left.get(nextBean)) { + return true; + } + if (!used.get(nextBean) && dfsCheck(nextBean)) { + return true; + } + } + left.put(tmp, true); + return false; } -} +} \ No newline at end of file diff --git a/src/main/java/arhangel/dim/container/BeanVertex.java b/src/main/java/arhangel/dim/container/BeanVertex.java index 1fbd084..3f746a2 100644 --- a/src/main/java/arhangel/dim/container/BeanVertex.java +++ b/src/main/java/arhangel/dim/container/BeanVertex.java @@ -17,4 +17,4 @@ public Bean getBean() { public void setBean(Bean bean) { this.bean = bean; } -} +} \ No newline at end of file diff --git a/src/main/java/arhangel/dim/container/BeanXmlReader.java b/src/main/java/arhangel/dim/container/BeanXmlReader.java index 3350f1e..d37347d 100644 --- a/src/main/java/arhangel/dim/container/BeanXmlReader.java +++ b/src/main/java/arhangel/dim/container/BeanXmlReader.java @@ -1,10 +1,24 @@ package arhangel.dim.container; +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; +import org.xml.sax.SAXException; + +import javax.naming.NameNotFoundException; +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.parsers.ParserConfigurationException; +import java.io.File; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.util.ArrayList; +import java.util.HashMap; import java.util.List; +import java.util.Map; + -/** - * - */ public class BeanXmlReader { private static final String TAG_BEAN = "bean"; private static final String TAG_PROPERTY = "property"; @@ -14,8 +28,47 @@ public class BeanXmlReader { private static final String ATTR_BEAN_ID = "id"; private static final String ATTR_BEAN_CLASS = "class"; - public List parseBeans(String pathToFile) { - return null; - } + public static List parseBeans(String pathToFile) throws IOException, ParserConfigurationException, SAXException, + NameNotFoundException { + List parseResult = new ArrayList<>(); + File inputXmlFile = Utils.initFile(pathToFile); + if (!inputXmlFile.exists()) { + throw new FileNotFoundException("Incorrect input file"); + } + + DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance(); + DocumentBuilder documentBuilder = documentBuilderFactory.newDocumentBuilder(); + Document xmlDocument = documentBuilder.parse(inputXmlFile); + NodeList listOfBeanNodes = xmlDocument.getElementsByTagName(TAG_BEAN); + + //поочередно разбираем данные о bean + for (int i = 0; i < listOfBeanNodes.getLength(); ++i) { + Node node = listOfBeanNodes.item(i); + Element nextElement = (Element) node; + NodeList propertiesList = nextElement.getElementsByTagName(TAG_PROPERTY); + Map properties = new HashMap<>(); -} + //парсим properties + for (int j = 0; j < propertiesList.getLength(); ++j) { + Element nextProperty = (Element) propertiesList.item(j); + String name = nextProperty.getAttribute(ATTR_NAME); + Property nextValue; + if (nextProperty.hasAttribute(ATTR_VALUE)) { + nextValue = new Property(name, nextProperty.getAttribute(ATTR_VALUE), ValueType.VAL); + } else if (nextProperty.hasAttribute(ATTR_REF)) { + nextValue = new Property(name, nextProperty.getAttribute(ATTR_REF), ValueType.REF); + } else { + throw new NameNotFoundException("Incorrect name of attribute"); + } + properties.put(name, nextValue); + + } + + Bean nextBean = new Bean(nextElement.getAttribute(ATTR_BEAN_ID), nextElement.getAttribute(ATTR_BEAN_CLASS), + properties); + parseResult.add(nextBean); + } + + return parseResult; + } +} \ No newline at end of file diff --git a/src/main/java/arhangel/dim/container/Container.java b/src/main/java/arhangel/dim/container/Container.java index 4213396..36a6799 100644 --- a/src/main/java/arhangel/dim/container/Container.java +++ b/src/main/java/arhangel/dim/container/Container.java @@ -1,28 +1,106 @@ package arhangel.dim.container; +import org.xml.sax.SAXException; + +import javax.naming.NameNotFoundException; +import javax.xml.parsers.ParserConfigurationException; +import java.io.IOException; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.HashMap; import java.util.List; +import java.util.Map; + -/** - * Используйте ваш xml reader чтобы прочитать конфиг и получить список бинов - */ public class Container { private List beans; + private Map objectByName; + private Map objectByClassName; /** - * Если не получается считать конфиг, то бросьте исключение - * @throws InvalidConfigurationException неверный конфиг + * @throws arhangel.dim.container.InvalidConfigurationException - неверный конфиг */ public Container(String pathToConfig) throws InvalidConfigurationException { + objectByClassName = new HashMap<>(); + objectByName = new HashMap<>(); + List beansFromXml; + try { + beansFromXml = BeanXmlReader.parseBeans(pathToConfig); + } catch (IOException e) { + throw new InvalidConfigurationException(e.getMessage()); + } catch (ParserConfigurationException e) { + throw new InvalidConfigurationException("Can't parse configuration." + e.getMessage()); + } catch (SAXException e) { + throw new InvalidConfigurationException("SAX parse exception." + e.getMessage()); + } catch (NameNotFoundException e) { + throw new InvalidConfigurationException("File does not exist." + e.getMessage()); + } + List tmp = (new BeanGraph(beansFromXml).topSort()); + beans = new ArrayList<>(); + for (BeanVertex beanVertex : tmp) { + beans.add(beanVertex.getBean()); + } + init(beans); + } + + private void init(List beans) { + for (int i = 0; i < beans.size(); ++i) { + initBean(beans.get(i)); + } + } + + private void initBean(Bean bean) { + String name = bean.getClassName(); + Class clazz; + try { + clazz = Class.forName(name); + } catch (ClassNotFoundException e) { + System.err.println("Incorrect name of class " + e.getMessage()); + return; + } + + // Создаём объект нужного нам класса + Object object; + try { + object = clazz.newInstance(); + } catch (InstantiationException e) { + System.err.println("Can't initialize class " + e.getMessage()); + return; + } catch (IllegalAccessException e) { + System.err.print(e.getMessage()); + return; + } + + // Создаём и применяем к нему методы для установки нужных значений + for (Property property : bean.getProperties().values()) { + String methodName = "set" + Utils.capitalize(property.getName()); + try { + if (property.getType() == ValueType.REF) { + Object parameter = getByName(property.getValue()); + Method method = clazz.getMethod(methodName, + parameter.getClass()); + method.invoke(object, parameter); + } else { + Method method = clazz.getMethod(methodName, + int.class); + method.invoke(object, new Integer(property.getValue())); + } + } catch (NoSuchMethodException | InvocationTargetException | IllegalAccessException e) { + System.err.println(e.getMessage()); + } + } + objectByClassName.put(bean.getClassName(), object); + objectByName.put(bean.getName(), object); - // вызываем BeanXmlReader } /** - * Вернуть объект по имени бина из конфига - * Например, Car car = (Car) container.getByName("carBean") + * Вернуть объект по имени бина из конфига + * Например, Car car = (Car) container.getByName("carBean") */ public Object getByName(String name) { - return null; + return objectByName.get(name); } /** @@ -30,35 +108,7 @@ public Object getByName(String name) { * Например, Car car = (Car) container.getByClass("arhangel.dim.container.Car") */ public Object getByClass(String className) { - return null; - } - - private void instantiateBean(Bean bean) { - - /* - // Примерный ход работы - - String className = bean.getClassName(); - Class clazz = Class.forName(className); - // ищем дефолтный конструктор - Object ob = clazz.newInstance(); - - - for (String name : bean.getProperties().keySet()) { - // ищем поле с таким именен внутри класса - // учитывая приватные - Field field = clazz.getDeclaredField(name); - // проверяем, если такого поля нет, то кидаем InvalidConfigurationException с описание ошибки - - // Делаем приватные поля доступными - field.setAccessible(true); - - // Далее определяем тип поля и заполняем его - // Если поле - примитив, то все просто - // Если поле ссылка, то эта ссылка должа была быть инициализирована ранее - - */ - + return objectByClassName.get(className); } -} +} \ No newline at end of file diff --git a/src/main/java/arhangel/dim/container/CycleReferenceException.java b/src/main/java/arhangel/dim/container/CycleReferenceException.java index 14edb65..a274377 100644 --- a/src/main/java/arhangel/dim/container/CycleReferenceException.java +++ b/src/main/java/arhangel/dim/container/CycleReferenceException.java @@ -7,4 +7,4 @@ public class CycleReferenceException extends Exception { public CycleReferenceException(String message) { super(message); } -} +} \ No newline at end of file diff --git a/src/main/java/arhangel/dim/container/Messenger.java b/src/main/java/arhangel/dim/container/Messenger.java new file mode 100644 index 0000000..cb4b575 --- /dev/null +++ b/src/main/java/arhangel/dim/container/Messenger.java @@ -0,0 +1,39 @@ +package arhangel.dim.container; + +import org.xml.sax.SAXException; + +import javax.naming.NameNotFoundException; +import javax.xml.parsers.ParserConfigurationException; +import java.io.IOException; +import java.util.List; + +public class Messenger { + public static void main(String[] arg) { + BeanXmlReader xmlReader = new BeanXmlReader(); + List beans; + + String path = "C:\\Users\\Дмитрий\\Documents\\technotrack\\java\\messenger" + + "\\src\\main\\java\\arhangel\\dim\\container\\test"; + try { + beans = xmlReader.parseBeans(path); + } catch (IOException e) { + System.out.println(e.getMessage()); + return; + } catch (ParserConfigurationException e) { + System.out.println("Parsing xml-file" + e.getMessage()); + return; + } catch (SAXException e) { + e.printStackTrace(); + return; + } catch (NameNotFoundException e) { + System.out.println("Please add attribute (ref or val) " + e.getMessage()); + return; + } + + for (Bean bean : beans) { + System.out.println(bean.toString()); + } + + + } +} \ No newline at end of file diff --git a/src/main/java/arhangel/dim/container/Property.java b/src/main/java/arhangel/dim/container/Property.java index d5b2e4e..4d1a0cf 100644 --- a/src/main/java/arhangel/dim/container/Property.java +++ b/src/main/java/arhangel/dim/container/Property.java @@ -47,4 +47,4 @@ public String toString() { ", type=" + type + '}'; } -} +} \ No newline at end of file diff --git a/src/main/java/arhangel/dim/container/Utils.java b/src/main/java/arhangel/dim/container/Utils.java new file mode 100644 index 0000000..655020e --- /dev/null +++ b/src/main/java/arhangel/dim/container/Utils.java @@ -0,0 +1,22 @@ +package arhangel.dim.container; + +import java.io.File; + +public class Utils { + + public static String capitalize(String string) { + string = string.toLowerCase(); + string = Character.toString(string.charAt(0)).toUpperCase() + string.substring(1); + return string; + } + + + public static File initFile(String pathToFile) { + File file = new File(pathToFile); + if (!file.exists()) { + String tryPath = System.getProperty("user.dir") + "/" + pathToFile; + file = new File(tryPath); + } + return file; + } +} \ No newline at end of file diff --git a/src/main/java/arhangel/dim/container/beans/WebConnection.java b/src/main/java/arhangel/dim/container/beans/WebConnection.java new file mode 100644 index 0000000..f2f05bf --- /dev/null +++ b/src/main/java/arhangel/dim/container/beans/WebConnection.java @@ -0,0 +1,41 @@ +package arhangel.dim.container.beans; + +/** + * Created by Дмитрий on 16.05.2016. + */ +public class WebConnection { + private int port; + private String host; + + public int getPort() { + return port; + } + + public String getHost() { + return host; + } + + public void setPort(int port) { + this.port = port; + } + + public void setHost(String host) { + this.host = host; + } + + public void setHost(int host) { + if (host == 0) { + this.host = "localhost"; + } + } + + public WebConnection() { + port = 9000; + host = "localhost"; + } + + public WebConnection(String host, int port) { + this.port = port; + this.host = host; + } +} diff --git a/src/main/java/arhangel/dim/container/test b/src/main/java/arhangel/dim/container/test new file mode 100644 index 0000000..d678420 --- /dev/null +++ b/src/main/java/arhangel/dim/container/test @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/main/java/arhangel/dim/core/Chat.java b/src/main/java/arhangel/dim/core/Chat.java deleted file mode 100644 index 4363d4b..0000000 --- a/src/main/java/arhangel/dim/core/Chat.java +++ /dev/null @@ -1,8 +0,0 @@ -package arhangel.dim.core; - -/** - * А над этим классом надо еще поработать - */ -public class Chat { - private Long id; -} diff --git a/src/main/java/arhangel/dim/core/User.java b/src/main/java/arhangel/dim/core/User.java deleted file mode 100644 index 0f21c0c..0000000 --- a/src/main/java/arhangel/dim/core/User.java +++ /dev/null @@ -1,25 +0,0 @@ -package arhangel.dim.core; - -/** - * Представление пользователя - */ -public class User { - private Long id; - private String name; - - public Long getId() { - return id; - } - - public void setId(Long id) { - this.id = id; - } - - public String getName() { - return name; - } - - public void setName(String name) { - this.name = name; - } -} diff --git a/src/main/java/arhangel/dim/core/authorization/Authorize.java b/src/main/java/arhangel/dim/core/authorization/Authorize.java new file mode 100644 index 0000000..47ddcbe --- /dev/null +++ b/src/main/java/arhangel/dim/core/authorization/Authorize.java @@ -0,0 +1,81 @@ +package arhangel.dim.core.authorization; + + +import arhangel.dim.core.message.AnswerMessage; +import arhangel.dim.core.message.Protocol; +import arhangel.dim.core.message.SerializationProtocol; +import arhangel.dim.core.session.Session; +import arhangel.dim.core.store.UserStore; + +import java.io.DataOutputStream; +import java.util.List; + +/** + * Класс для авторизации и регистрации пользователей + */ +public class Authorize { + + private UserStore userStore; + + private Authorize() {} + + public Authorize(UserStore userStore) { + this.userStore = userStore; + } + + public synchronized void registerUser(String name, String password, Session session) throws Exception { + DataOutputStream writer = session.getWriter(); + Protocol protocol = new SerializationProtocol<>(); + String message = ""; + AnswerMessage.Value success; + if (name != null && password != null) { + List userByName = userStore.getUserByName(name); + if (userByName.size() > 0) { + message = "Sorry, but user with this name has already registered"; + success = AnswerMessage.Value.ERROR; + } else { + int id = userStore.addUser(new User(name, password, name)); + session.setCurrentUserName(name); + session.setCurrentUserId(id); + message = String.format("User was successfully signed up\n" + + "Login: %s, Password: %s, Id: %d", name, password, id); + success = AnswerMessage.Value.SUCCESS; + } + } else { + message = "Incorrect name/password"; + success = AnswerMessage.Value.ERROR; + } + writer.write(protocol.encode(new AnswerMessage(message, success))); + } + + public synchronized void authorizeUser(String name, String password, Session session) throws Exception { + DataOutputStream writer = session.getWriter(); + Protocol protocol = new SerializationProtocol<>(); + String message = ""; + AnswerMessage.Value success; + List userByName = userStore.getUserByName(name); + if (userByName.size() == 1) { + User user = userByName.get(0); + if (user.getPassword().equals(Integer.toString(password.hashCode()))) { + session.setCurrentUserName(name); + session.setCurrentUserId(user.getId()); + message = String.format("Hello, %s! Your id = %d", name, user.getId()); + success = AnswerMessage.Value.SUCCESS; + } else { + message = "Password is incorrect"; + success = AnswerMessage.Value.ERROR; + } + } else { + message = "Sorry, but we didn't find user with this name: " + name; + success = AnswerMessage.Value.ERROR; + } + writer.write(protocol.encode(new AnswerMessage(message, success))); + } + + /** + * Возвращает класс User по идентификатору пользователя + */ + public User getUserInfo(int id) throws Exception { + return userStore.getUser(id); + } +} diff --git a/src/main/java/arhangel/dim/core/authorization/User.java b/src/main/java/arhangel/dim/core/authorization/User.java new file mode 100644 index 0000000..369df2c --- /dev/null +++ b/src/main/java/arhangel/dim/core/authorization/User.java @@ -0,0 +1,48 @@ +package arhangel.dim.core.authorization; + +/** + * Класс-информация о пользователе + */ +public class User { + + private String name; + private String password; + private String nickname; + private int id; + + public User() {} + + public User(String name, String password, String nickname) { + this.name = name; + this.password = password; + this.nickname = nickname; + } + + public String getName() { + return name; + } + + public String getPassword() { + return password; + } + + public String getNick() { + return nickname; + } + + public void setNickname(String nickname) { + this.nickname = nickname; + } + + public void setPassword(String password) { + this.password = password; + } + + public int getId() { + return id; + } + + public void setId(int id) { + this.id = id; + } +} diff --git a/src/main/java/arhangel/dim/core/commands/ChatCreateCommand.java b/src/main/java/arhangel/dim/core/commands/ChatCreateCommand.java new file mode 100644 index 0000000..b813ee6 --- /dev/null +++ b/src/main/java/arhangel/dim/core/commands/ChatCreateCommand.java @@ -0,0 +1,58 @@ +package arhangel.dim.core.commands; + +import arhangel.dim.core.store.UserStore; +import arhangel.dim.core.message.AnswerMessage; +import arhangel.dim.core.message.Protocol; +import arhangel.dim.core.message.SerializationProtocol; +import arhangel.dim.core.store.DataStore; +import arhangel.dim.core.session.Session; + +import java.io.DataOutputStream; +import java.util.ArrayList; +import java.util.List; + +public class ChatCreateCommand implements Command { + + /** + * args 0 - название команды, 1 - список участников чата через запятую + */ + @Override + public void run(String[] args, Session session) throws Exception { + DataOutputStream writer = session.getWriter(); + Protocol protocol = new SerializationProtocol<>(); + String message = ""; + AnswerMessage.Value success; + DataStore dataStore = session.getDataStore(); + int authorId = session.getCurrentUserId(); + if (authorId == -1) { + success = AnswerMessage.Value.LOGIN; + } else { + if (args.length != 2) { + success = AnswerMessage.Value.NUM_ARGS; + } else { + UserStore userStore = dataStore.getUserStore(); + List participants = new ArrayList<>(); + String[] parsedArg = args[1].split(","); + participants.add(authorId); + for (String it : parsedArg) { + int id = Integer.parseInt(it); + participants.add(id); + if (userStore.getUser(id) == null) { + message = String.format("There is no user with id %d", id); + success = AnswerMessage.Value.ERROR; + writer.write(protocol.encode(new AnswerMessage(message, success))); + return; + } + } + int result = dataStore.getChatStore().createChat(participants); + message = "Chat was successfully created, id: " + result; + success = AnswerMessage.Value.SUCCESS; + } + } + writer.write(protocol.encode(new AnswerMessage(message, success))); + } + + public String toString() { + return "/chat_create"; + } +} diff --git a/src/main/java/arhangel/dim/core/commands/ChatHistoryCommand.java b/src/main/java/arhangel/dim/core/commands/ChatHistoryCommand.java new file mode 100644 index 0000000..9003dc3 --- /dev/null +++ b/src/main/java/arhangel/dim/core/commands/ChatHistoryCommand.java @@ -0,0 +1,57 @@ +package arhangel.dim.core.commands; + +import arhangel.dim.core.message.AnswerMessage; +import arhangel.dim.core.message.Chat; +import arhangel.dim.core.message.Protocol; +import arhangel.dim.core.message.SerializationProtocol; +import arhangel.dim.core.message.Message; +import arhangel.dim.core.session.Session; +import arhangel.dim.core.store.ChatStore; + +import java.io.DataOutputStream; +import java.util.Map; + +public class ChatHistoryCommand implements Command { + /** + * args 0 - название команды, 1 - идентификатор чата + */ + @Override + public void run(String[] args, Session session) throws Exception { + DataOutputStream writer = session.getWriter(); + Protocol protocol = new SerializationProtocol<>(); + String message = ""; + AnswerMessage.Value success; + if (session.getCurrentUserName() == null) { + success = AnswerMessage.Value.LOGIN; + writer.write(protocol.encode(new AnswerMessage(message, success))); + return; + } + if (args.length == 2) { + int chatId = Integer.parseInt(args[1]); + ChatStore chatStore = session.getDataStore().getChatStore(); + Chat chat = chatStore.getChat(chatId); + if (chat == null) { + message = "Chat " + chatId + " not found"; + success = AnswerMessage.Value.ERROR; + writer.write(protocol.encode(new AnswerMessage(message, success))); + return; + } + StringBuilder stringBuilder = new StringBuilder(); + Map messageMap = chat.getMessageMap(); + for (Map.Entry pair : messageMap.entrySet()) { + stringBuilder.append(pair.getValue().toString()); + stringBuilder.append("\n"); + } + message = stringBuilder.toString(); + success = AnswerMessage.Value.SUCCESS; + } else { + success = AnswerMessage.Value.NUM_ARGS; + } + writer.write(protocol.encode(new AnswerMessage(message, success))); + } + + @Override + public String toString() { + return "/chat_history"; + } +} diff --git a/src/main/java/arhangel/dim/core/commands/ChatListCommand.java b/src/main/java/arhangel/dim/core/commands/ChatListCommand.java new file mode 100644 index 0000000..fce303b --- /dev/null +++ b/src/main/java/arhangel/dim/core/commands/ChatListCommand.java @@ -0,0 +1,51 @@ +package arhangel.dim.core.commands; + +import arhangel.dim.core.message.AnswerMessage; +import arhangel.dim.core.message.Chat; +import arhangel.dim.core.message.Protocol; +import arhangel.dim.core.message.SerializationProtocol; +import arhangel.dim.core.store.DataStore; +import arhangel.dim.core.session.Session; + +import java.io.DataOutputStream; +import java.util.List; +import java.util.Map; + +public class ChatListCommand implements Command { + + @Override + public void run(String[] args, Session session) throws Exception { + DataOutputStream writer = session.getWriter(); + Protocol protocol = new SerializationProtocol<>(); + AnswerMessage.Value success; + String message = ""; + DataStore dataStore = session.getDataStore(); + if (session.getCurrentUserId() == -1) { + success = AnswerMessage.Value.LOGIN; + } else { + success = AnswerMessage.Value.SUCCESS; + Map result = dataStore.getChatStore().getChatList(); + StringBuilder builder = new StringBuilder(); + builder.append("Chat list:\n"); + for (Map.Entry it : result.entrySet()) { + builder.append("Chat "); + builder.append(it.getKey()); + builder.append(", users: "); + List participantsId = it.getValue().getParticipantIds(); + for (Integer userIdIt : participantsId) { + builder.append(userIdIt); + builder.append(", "); + } + builder.deleteCharAt(builder.length() - 1); + builder.append("\n"); + } + builder.deleteCharAt(builder.length() - 1); + message = builder.toString(); + } + writer.write(protocol.encode(new AnswerMessage(message, success))); + } + + public String toString() { + return "/chat_list"; + } +} diff --git a/src/main/java/arhangel/dim/core/commands/Command.java b/src/main/java/arhangel/dim/core/commands/Command.java new file mode 100644 index 0000000..e2f2e7c --- /dev/null +++ b/src/main/java/arhangel/dim/core/commands/Command.java @@ -0,0 +1,10 @@ +package arhangel.dim.core.commands; + +import arhangel.dim.core.session.Session; + +public interface Command { + + void run(String[] args, Session session) throws Exception; + + String toString(); +} diff --git a/src/main/java/arhangel/dim/core/commands/HelpCommand.java b/src/main/java/arhangel/dim/core/commands/HelpCommand.java new file mode 100644 index 0000000..d7ef314 --- /dev/null +++ b/src/main/java/arhangel/dim/core/commands/HelpCommand.java @@ -0,0 +1,33 @@ +package arhangel.dim.core.commands; + +import arhangel.dim.core.message.AnswerMessage; +import arhangel.dim.core.message.Protocol; +import arhangel.dim.core.message.SerializationProtocol; +import arhangel.dim.core.session.Session; + +import java.io.DataOutputStream; + +public class HelpCommand implements Command { + + @Override + public void run(String[] args, Session session) throws Exception { + DataOutputStream writer = session.getWriter(); + Protocol protocol = new SerializationProtocol<>(); + String message = "List of commands:\n" + + " /register - sign up a user\n" + + " /login - sign in with these parameters\n" + + " /info - get the information about you\n" + + " /info - get the information about \'nick\'\n" + + " /chat_list - list of all chats\n" + + " /chat_create - create chat with participants in list\n" + + " /chat_history - show messages in \'id\' chat\n" + + " /text send message in 'id' chat\n" + + " /exit - exit the program\n" + + " /help - show the list of commands"; + writer.write(protocol.encode(new AnswerMessage(message, AnswerMessage.Value.SUCCESS))); + } + + public String toString() { + return "/help"; + } +} diff --git a/src/main/java/arhangel/dim/core/commands/LoginCommand.java b/src/main/java/arhangel/dim/core/commands/LoginCommand.java new file mode 100644 index 0000000..b713d80 --- /dev/null +++ b/src/main/java/arhangel/dim/core/commands/LoginCommand.java @@ -0,0 +1,30 @@ +package arhangel.dim.core.commands; + +import arhangel.dim.core.authorization.Authorize; +import arhangel.dim.core.message.AnswerMessage; +import arhangel.dim.core.message.Protocol; +import arhangel.dim.core.message.SerializationProtocol; +import arhangel.dim.core.session.Session; + +import java.io.DataOutputStream; + +public class LoginCommand implements Command { + /** + * args 0 - название команды, 1 - логин, 2 - пароль + */ + @Override + public void run(String[] args, Session session) throws Exception { + DataOutputStream writer = session.getWriter(); + Authorize service = session.getAuthorize(); + if (args.length == 3) { + service.authorizeUser(args[1], args[2], session); + } else { + Protocol protocol = new SerializationProtocol<>(); + writer.write(protocol.encode(new AnswerMessage("", AnswerMessage.Value.NUM_ARGS))); + } + } + + public String toString() { + return "/login"; + } +} diff --git a/src/main/java/arhangel/dim/core/commands/RegisterCommand.java b/src/main/java/arhangel/dim/core/commands/RegisterCommand.java new file mode 100644 index 0000000..4a1eb64 --- /dev/null +++ b/src/main/java/arhangel/dim/core/commands/RegisterCommand.java @@ -0,0 +1,32 @@ +package arhangel.dim.core.commands; + +import arhangel.dim.core.authorization.Authorize; +import arhangel.dim.core.message.AnswerMessage; +import arhangel.dim.core.message.Protocol; +import arhangel.dim.core.message.SerializationProtocol; +import arhangel.dim.core.session.Session; + +import java.io.DataOutputStream; + +public class RegisterCommand implements Command { + /** + * args 0 - название команды, 1 - логин, 2 - пароль + */ + @Override + public void run(String[] args, Session session) throws Exception { + Protocol protocol = new SerializationProtocol<>(); + AnswerMessage.Value success; + if (args.length == 3) { + Authorize service = session.getAuthorize(); + service.registerUser(args[1], args[2], session); + } else { + DataOutputStream writer = session.getWriter(); + success = AnswerMessage.Value.NUM_ARGS; + writer.write(protocol.encode(new AnswerMessage("", success))); + } + } + + public String toString() { + return "/register"; + } +} diff --git a/src/main/java/arhangel/dim/core/commands/TextCommand.java b/src/main/java/arhangel/dim/core/commands/TextCommand.java new file mode 100644 index 0000000..0452b11 --- /dev/null +++ b/src/main/java/arhangel/dim/core/commands/TextCommand.java @@ -0,0 +1,75 @@ +package arhangel.dim.core.commands; + +import arhangel.dim.core.message.AnswerMessage; +import arhangel.dim.core.message.Chat; +import arhangel.dim.core.message.Protocol; +import arhangel.dim.core.message.SerializationProtocol; +import arhangel.dim.core.store.ChatStore; +import arhangel.dim.core.store.DataStore; +import arhangel.dim.core.session.Session; +import arhangel.dim.core.session.SessionManager; + +import java.io.DataOutputStream; +import java.util.List; + +public class TextCommand implements Command { + /** + * args 0 - название команды, 1 - идентификатор чата, 2,3,4... - сообщение + */ + @Override + public void run(String[] args, Session session) throws Exception { + DataOutputStream writer = session.getWriter(); + Protocol protocol = new SerializationProtocol<>(); + String message = ""; + AnswerMessage.Value success; + DataStore dataStore = session.getDataStore(); + int authorId = session.getCurrentUserId(); + String authorName = session.getCurrentUserName(); + if (authorId == -1) { + success = AnswerMessage.Value.LOGIN; + writer.write(protocol.encode(new AnswerMessage(message, success))); + } else { + if (args.length < 3) { + success = AnswerMessage.Value.NUM_ARGS; + writer.write(protocol.encode(new AnswerMessage(message, success))); + return; + } + int chatId = Integer.parseInt(args[1]); + StringBuilder builder = new StringBuilder(); + for (int i = 2; i < args.length; ++i) { + builder.append(args[i] + " "); + } + String messageFromUser = builder.toString(); + ChatStore chatStore = dataStore.getChatStore(); + Chat chat = chatStore.getChat(chatId); + if (chat == null) { + message = "Chat not found"; + success = AnswerMessage.Value.ERROR; + writer.write(protocol.encode(new AnswerMessage(message, success))); + return; + } + List participants = chat.getParticipantIds(); + if (!participants.contains(authorId)) { + message = "You are not allowed to write in this chat"; + success = AnswerMessage.Value.ERROR; + writer.write(protocol.encode(new AnswerMessage(message, success))); + return; + } + chat.addMessage(authorId, authorName, messageFromUser); + SessionManager manager = session.getSessionManager(); + for (Integer id : participants) { + success = AnswerMessage.Value.CHAT; + Session destinationSession = manager.getSessionById(id); + AnswerMessage answer = new AnswerMessage(messageFromUser, success); + answer.setMessage(String.format("Chat %d, from %d: %s", chatId, authorId, messageFromUser)); + answer.setId(authorId); + DataOutputStream destinationWriter = destinationSession.getWriter(); + destinationWriter.write(protocol.encode(answer)); + } + } + } + + public String toString() { + return "/text"; + } +} diff --git a/src/main/java/arhangel/dim/core/commands/UserInfoCommand.java b/src/main/java/arhangel/dim/core/commands/UserInfoCommand.java new file mode 100644 index 0000000..4f67566 --- /dev/null +++ b/src/main/java/arhangel/dim/core/commands/UserInfoCommand.java @@ -0,0 +1,59 @@ +package arhangel.dim.core.commands; + +import arhangel.dim.core.authorization.Authorize; +import arhangel.dim.core.authorization.User; +import arhangel.dim.core.message.AnswerMessage; +import arhangel.dim.core.message.Protocol; +import arhangel.dim.core.message.SerializationProtocol; +import arhangel.dim.core.session.Session; + +import java.io.DataOutputStream; + +public class UserInfoCommand implements Command { + /** + * args 0 - название команды, 1 - имя пользователя. Если аргумент 1 отсутствует, то выводятся + * данные о текущем пользователе + */ + @Override + public void run(String[] args, Session session) throws Exception { + DataOutputStream writer = session.getWriter(); + Protocol protocol = new SerializationProtocol<>(); + String message = ""; + AnswerMessage.Value success; + if (args.length == 1) { + int currentUserId = session.getCurrentUserId(); + if (currentUserId == -1) { + success = AnswerMessage.Value.NUM_ARGS; + } else { + Authorize service = session.getAuthorize(); + User user = service.getUserInfo(currentUserId); + if (user == null) { + message = "Can't find you. Don't worry."; + success = AnswerMessage.Value.ERROR; + } else { + message = String.format("Username: %s," + + " nickname: %s, Id: %d", user.getName(), user.getNick(), user.getId()); + success = AnswerMessage.Value.SUCCESS; + } + } + } else if (args.length == 2) { + Authorize service = session.getAuthorize(); + User user = service.getUserInfo(Integer.parseInt(args[1])); + if (user == null) { + message = "Can't find user: " + args[1]; + success = AnswerMessage.Value.ERROR; + } else { + message = String.format("Username: %s," + + " nickname: %s, Id: %d", user.getName(), user.getNick(), user.getId()); + success = AnswerMessage.Value.SUCCESS; + } + } else { + success = AnswerMessage.Value.NUM_ARGS; + } + writer.write(protocol.encode(new AnswerMessage(message, success))); + } + + public String toString() { + return "/info"; + } +} diff --git a/src/main/java/arhangel/dim/core/jdbc/DataBaseOrganizer.java b/src/main/java/arhangel/dim/core/jdbc/DataBaseOrganizer.java new file mode 100644 index 0000000..f45d680 --- /dev/null +++ b/src/main/java/arhangel/dim/core/jdbc/DataBaseOrganizer.java @@ -0,0 +1,53 @@ +package arhangel.dim.core.jdbc; + +import java.sql.Connection; +import java.sql.DriverManager; +import java.sql.Statement; + +/** + * Организация базы данных перед запуском(Создание таблиц). + */ +public class DataBaseOrganizer { + public static void reorganizeDataBase(String[] args) throws Exception { + Class.forName("org.postgresql.Driver"); + Connection conn = DriverManager.getConnection("jdbc:postgresql://178.62.140.149:5432/Kud8", + "trackuser", "trackuser"); + Statement stmt; + String sql; + + stmt = conn.createStatement(); + sql = "CREATE TABLE IF NOT EXISTS users " + + "(ID SERIAL PRIMARY KEY," + + " LOGIN TEXT NOT NULL," + + " PASSWORD TEXT NOT NULL," + + " NICK TEXT NOT NULL)"; + stmt.executeUpdate(sql); + stmt.close(); + + stmt = conn.createStatement(); + sql = "CREATE TABLE IF NOT EXISTS chats " + + "(ID SERIAL PRIMARY KEY," + + " TEMP TEXT NOT NULL)"; + stmt.executeUpdate(sql); + stmt.close(); + + stmt = conn.createStatement(); + sql = "CREATE TABLE IF NOT EXISTS message " + + "(ID SERIAL PRIMARY KEY," + + " AUTHOR_ID INT NOT NULL," + + " VALUE TEXT NOT NULL," + + " CHAT_ID INT NOT NULL)"; + stmt.executeUpdate(sql); + stmt.close(); + + stmt = conn.createStatement(); + sql = "CREATE TABLE IF NOT EXISTS userschat " + + "(ID SERIAL PRIMARY KEY," + + " USER_ID INT NOT NULL," + + " CHAT_ID INT NOT NULL)"; + stmt.executeUpdate(sql); + stmt.close(); + + conn.close(); + } +} diff --git a/src/main/java/arhangel/dim/core/jdbc/QueryExecutor.java b/src/main/java/arhangel/dim/core/jdbc/QueryExecutor.java new file mode 100644 index 0000000..fdea10b --- /dev/null +++ b/src/main/java/arhangel/dim/core/jdbc/QueryExecutor.java @@ -0,0 +1,102 @@ +package arhangel.dim.core.jdbc; + +import java.sql.Connection; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.sql.Statement; +import java.util.HashMap; +import java.util.Map; + +/** + * Класс для отправки запросов в БД + */ +public class QueryExecutor { + /** + * Словарь подготовленных запросов + */ + private Map preparedStatementMap; + + /** + * Словарь подготовленных запросов, с Generated Keys + */ + private Map preparedStatementMapGenKey; + + public QueryExecutor() { + preparedStatementMap = new HashMap<>(); + preparedStatementMapGenKey = new HashMap<>(); + } + + public void prepareStatement(Connection connection, String query) throws SQLException { + if (preparedStatementMap.get(query) == null) { + preparedStatementMap.put(query, connection.prepareStatement(query)); + } + } + + public void prepareStatementGeneratedKeys(Connection connection, String query) throws SQLException { + if (preparedStatementMapGenKey.get(query) == null) { + preparedStatementMapGenKey.put(query, connection.prepareStatement(query, + PreparedStatement.RETURN_GENERATED_KEYS)); + } + } + + public T execQuery(Connection connection, String query, ResultHandler handler) throws SQLException { + Statement stmt = connection.createStatement(); + stmt.execute(query); + ResultSet result = stmt.getResultSet(); + T value = handler.handle(result); + result.close(); + stmt.close(); + + return value; + } + + public T execQuery(String sql, Map args, ResultHandler handler) throws SQLException { + PreparedStatement pstmt = preparedStatementMap.get(sql); + if (pstmt == null) { + throw new SQLException(String.format("Statement \"%s\" wasn't prepared", sql)); + } + for (Map.Entry entry : args.entrySet()) { + pstmt.setObject(entry.getKey(), entry.getValue()); + } + ResultSet rs = pstmt.executeQuery(); + T value = handler.handle(rs); + rs.close(); + return value; + } + + public void execUpdate(String sql, Map args) throws SQLException { + PreparedStatement pstmt = preparedStatementMap.get(sql); + if (pstmt == null) { + throw new SQLException(String.format("Statement \"%s\" wasn't prepared", sql)); + } + for (Map.Entry entry : args.entrySet()) { + pstmt.setObject(entry.getKey(), entry.getValue()); + } + pstmt.executeUpdate(); + } + + public T execUpdate(String sql, Map args, ResultHandler handler) throws SQLException { + PreparedStatement pstmt = preparedStatementMapGenKey.get(sql); + if (pstmt == null) { + throw new SQLException(String.format("Statement \"%s\" wasn't prepared", sql)); + } + for (Map.Entry entry : args.entrySet()) { + pstmt.setObject(entry.getKey(), entry.getValue()); + } + pstmt.executeUpdate(); + ResultSet rs = pstmt.getGeneratedKeys(); + T value = handler.handle(rs); + rs.close(); + return value; + } + + public void close() throws SQLException { + for (Map.Entry pair : preparedStatementMap.entrySet()) { + pair.getValue().close(); + } + for (Map.Entry pair : preparedStatementMapGenKey.entrySet()) { + pair.getValue().close(); + } + } +} diff --git a/src/main/java/arhangel/dim/lections/jdbc/ResultHandler.java b/src/main/java/arhangel/dim/core/jdbc/ResultHandler.java similarity index 53% rename from src/main/java/arhangel/dim/lections/jdbc/ResultHandler.java rename to src/main/java/arhangel/dim/core/jdbc/ResultHandler.java index 90bae13..97b2991 100644 --- a/src/main/java/arhangel/dim/lections/jdbc/ResultHandler.java +++ b/src/main/java/arhangel/dim/core/jdbc/ResultHandler.java @@ -1,12 +1,8 @@ -package arhangel.dim.lections.jdbc; +package arhangel.dim.core.jdbc; import java.sql.ResultSet; import java.sql.SQLException; -/** - * Обобщенный интерфейс обработки результата - */ - public interface ResultHandler { T handle(ResultSet resultSet) throws SQLException; -} \ No newline at end of file +} diff --git a/src/main/java/arhangel/dim/core/message/AnswerMessage.java b/src/main/java/arhangel/dim/core/message/AnswerMessage.java new file mode 100644 index 0000000..655adb2 --- /dev/null +++ b/src/main/java/arhangel/dim/core/message/AnswerMessage.java @@ -0,0 +1,59 @@ +package arhangel.dim.core.message; + +import java.io.Serializable; + +/** + * Ответ сервера на запрос клиента + */ +public class AnswerMessage implements Serializable { + + public enum Value { + SUCCESS, + ERROR, + LOGIN, + NUM_ARGS, + CHAT, + } + + private int id; + private String from; + private String message; + private Value result; + + public AnswerMessage(String message, Value result) { + this.message = message; + this.result = result; + } + + public String getMessage() { + return message; + } + + public void setMessage(String message) { + this.message = message; + } + + public Value getResult() { + return result; + } + + public void setResult(Value result) { + this.result = result; + } + + public int getId() { + return id; + } + + public void setId(int id) { + this.id = id; + } + + public String getFrom() { + return from; + } + + public void setFrom(String from) { + this.from = from; + } +} diff --git a/src/main/java/arhangel/dim/core/message/Chat.java b/src/main/java/arhangel/dim/core/message/Chat.java new file mode 100644 index 0000000..ba987de --- /dev/null +++ b/src/main/java/arhangel/dim/core/message/Chat.java @@ -0,0 +1,59 @@ +package arhangel.dim.core.message; + +import arhangel.dim.core.store.DataBaseMessageStore; +import arhangel.dim.core.store.MessageStore; + +import java.sql.Connection; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +public class Chat { + + private Integer id; + private MessageStore messageStore; + private List participantIds; + private Connection connection; + + public Chat(Integer id, Connection conn) { + this.id = id; + this.participantIds = new ArrayList<>(); + this.connection = conn; + this.messageStore = new DataBaseMessageStore(connection, this); + } + + public Chat(List participantIds, Integer id, Connection conn) { + this.id = id; + this.participantIds = participantIds; + this.connection = conn; + this.messageStore = new DataBaseMessageStore(conn, this); + } + + public boolean addParticipant(int id) { + if (participantIds.contains(id)) { + return false; + } + participantIds.add(id); + return true; + } + + public void addMessage(int authorId, String authorName, String message) throws Exception { + messageStore.addMessage(authorId, authorName, message, this); + } + + public Integer getId() { + return id; + } + + public void setId(Integer id) { + this.id = id; + } + + public List getParticipantIds() { + return participantIds; + } + + public Map getMessageMap() throws Exception { + return messageStore.getMessagesMap(); + } +} diff --git a/src/main/java/arhangel/dim/core/message/Message.java b/src/main/java/arhangel/dim/core/message/Message.java new file mode 100644 index 0000000..b852193 --- /dev/null +++ b/src/main/java/arhangel/dim/core/message/Message.java @@ -0,0 +1,65 @@ +package arhangel.dim.core.message; + +import java.io.Serializable; +import java.util.Objects; + +public class Message implements Serializable { + + protected int id; + protected int authorId; + protected String message; + + public Message() { + + } + + public int getId() { + return id; + } + + public void setId(int id) { + this.id = id; + } + + public String getMessage() { + return message; + } + + public void setMessage(String message) { + this.message = message; + } + + public int getAuthorId() { + return authorId; + } + + public void setAuthorId(int authorId) { + this.authorId = authorId; + } + + @Override + public boolean equals(Object other) { + if (this == other) { + return true; + } + if (other == null || getClass() != other.getClass()) { + return false; + } + Message message = (Message) other; + return Objects.equals(id, message.id) && + Objects.equals(authorId, message.authorId); + } + + @Override + public int hashCode() { + return Objects.hash(id, authorId); + } + + @Override + public String toString() { + return "Message{" + + "id=" + id + + ", senderId=" + authorId + + '}'; + } +} diff --git a/src/main/java/arhangel/dim/core/message/Protocol.java b/src/main/java/arhangel/dim/core/message/Protocol.java new file mode 100644 index 0000000..077bad7 --- /dev/null +++ b/src/main/java/arhangel/dim/core/message/Protocol.java @@ -0,0 +1,8 @@ +package arhangel.dim.core.message; + +public interface Protocol { + + byte[] encode(T msg) throws Exception; + + T decode(byte[] data) throws Exception; +} diff --git a/src/main/java/arhangel/dim/core/message/SerializationProtocol.java b/src/main/java/arhangel/dim/core/message/SerializationProtocol.java new file mode 100644 index 0000000..08134b8 --- /dev/null +++ b/src/main/java/arhangel/dim/core/message/SerializationProtocol.java @@ -0,0 +1,50 @@ +package arhangel.dim.core.message; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.ObjectOutput; +import java.io.ObjectOutputStream; +import java.io.ByteArrayInputStream; +import java.io.ObjectInputStream; +import java.io.ObjectInput; +import java.nio.ByteBuffer; + +public class SerializationProtocol implements Protocol { + @Override + public byte[] encode(T msg) throws Exception { + try (ByteArrayOutputStream bos = new ByteArrayOutputStream(); + ObjectOutput out = new ObjectOutputStream(bos)) { + out.writeObject(msg); + byte[] objData = bos.toByteArray(); + int size = objData.length; + + ByteBuffer buf = ByteBuffer.allocate(size + 4); + buf.putInt(size); + buf.put(objData); + return buf.array(); + } catch (IOException e) { + System.err.println("Failed to encode message " + e.toString()); + } + return new byte[0]; + } + + @Override + public T decode(byte[] data) throws Exception { + ByteBuffer buf = ByteBuffer.wrap(data); + int size = buf.getInt(); + if (size > data.length - 4) { + System.err.println("Failed to decode mesage"); + } + byte[] objData = new byte[size]; + buf.get(objData); + try (ByteArrayInputStream bis = new ByteArrayInputStream(objData); + ObjectInput in = new ObjectInputStream(bis)) { + return (T) in.readObject(); + } catch (IOException e) { + System.err.println("Failed to decode messsage " + e.toString()); + } catch (ClassNotFoundException e) { + System.err.println("Decode: no class found " + e.toString()); + } + return null; + } +} diff --git a/src/main/java/arhangel/dim/core/messages/Command.java b/src/main/java/arhangel/dim/core/messages/Command.java deleted file mode 100644 index 533a4b6..0000000 --- a/src/main/java/arhangel/dim/core/messages/Command.java +++ /dev/null @@ -1,17 +0,0 @@ -package arhangel.dim.core.messages; - -import arhangel.dim.core.net.Session; - -// TODO: на каждое сообщение завести обработчик-команду -public interface Command { - - /** - * Реализация паттерна Команда. Метод execute() вызывает соответствующую реализацию, - * для запуска команды нужна сессия, чтобы можно было сгенерить ответ клиенту и провести валидацию - * сессии. - * @param session - текущая сессия - * @param message - сообщение для обработки - * @throws CommandException - все исключения перебрасываются как CommandException - */ - void execute(Session session, Message message) throws CommandException; -} diff --git a/src/main/java/arhangel/dim/core/messages/CommandException.java b/src/main/java/arhangel/dim/core/messages/CommandException.java deleted file mode 100644 index f6eedf1..0000000 --- a/src/main/java/arhangel/dim/core/messages/CommandException.java +++ /dev/null @@ -1,14 +0,0 @@ -package arhangel.dim.core.messages; - -/** - * - */ -public class CommandException extends Exception { - public CommandException(String msg) { - super(msg); - } - - public CommandException(Throwable ex) { - super(ex); - } -} diff --git a/src/main/java/arhangel/dim/core/messages/Message.java b/src/main/java/arhangel/dim/core/messages/Message.java deleted file mode 100644 index 65486c8..0000000 --- a/src/main/java/arhangel/dim/core/messages/Message.java +++ /dev/null @@ -1,66 +0,0 @@ -package arhangel.dim.core.messages; - -import java.io.Serializable; -import java.util.Objects; - -/** - * Базовый класс для всех сообщений - */ -public abstract class Message implements Serializable { - - private Long id; - private Long senderId; - private Type type; - - public Long getId() { - return id; - } - - public void setId(Long id) { - this.id = id; - } - - public Long getSenderId() { - return senderId; - } - - public void setSenderId(Long senderId) { - this.senderId = senderId; - } - - public Type getType() { - return type; - } - - public void setType(Type type) { - this.type = type; - } - - @Override - public boolean equals(Object other) { - if (this == other) { - return true; - } - if (other == null || getClass() != other.getClass()) { - return false; - } - Message message = (Message) other; - return Objects.equals(id, message.id) && - Objects.equals(senderId, message.senderId) && - type == message.type; - } - - @Override - public int hashCode() { - return Objects.hash(id, senderId, type); - } - - @Override - public String toString() { - return "Message{" + - "id=" + id + - ", senderId=" + senderId + - ", type=" + type + - '}'; - } -} diff --git a/src/main/java/arhangel/dim/core/messages/TextMessage.java b/src/main/java/arhangel/dim/core/messages/TextMessage.java deleted file mode 100644 index 59f06b5..0000000 --- a/src/main/java/arhangel/dim/core/messages/TextMessage.java +++ /dev/null @@ -1,45 +0,0 @@ -package arhangel.dim.core.messages; - -import java.util.Objects; - -/** - * Простое текстовое сообщение - */ -public class TextMessage extends Message { - private String text; - - public String getText() { - return text; - } - - public void setText(String text) { - this.text = text; - } - - @Override - public boolean equals(Object other) { - if (this == other) { - return true; - } - if (other == null || getClass() != other.getClass()) { - return false; - } - if (!super.equals(other)) { - return false; - } - TextMessage message = (TextMessage) other; - return Objects.equals(text, message.text); - } - - @Override - public int hashCode() { - return Objects.hash(super.hashCode(), text); - } - - @Override - public String toString() { - return "TextMessage{" + - "text='" + text + '\'' + - '}'; - } -} diff --git a/src/main/java/arhangel/dim/core/messages/Type.java b/src/main/java/arhangel/dim/core/messages/Type.java deleted file mode 100644 index 2dc0280..0000000 --- a/src/main/java/arhangel/dim/core/messages/Type.java +++ /dev/null @@ -1,20 +0,0 @@ -package arhangel.dim.core.messages; - -/** - * Маркер типа сообщения - */ -public enum Type { - MSG_LOGIN, // status - MSG_TEXT, // status - MSG_INFO, // MSG_INFO_RESULT - MSG_CHAT_LIST, // MSG_CHAT_LIST_RESULT, - MSG_CHAT_CREATE, // status - MSG_CHAT_HIST, // MSG_CHAT_HIST_RESULT, - - MSG_STATUS, - MSG_CHAT_LIST_RESULT, - MSG_CHAT_HIST_RESULT, - MSG_INFO_RESULT - - -} diff --git a/src/main/java/arhangel/dim/core/net/BinaryProtocol.java b/src/main/java/arhangel/dim/core/net/BinaryProtocol.java deleted file mode 100644 index c32a6c0..0000000 --- a/src/main/java/arhangel/dim/core/net/BinaryProtocol.java +++ /dev/null @@ -1,19 +0,0 @@ -package arhangel.dim.core.net; - -import arhangel.dim.core.messages.Message; - -/** - * TODO: реализовать здесь свой протокол - */ -public class BinaryProtocol implements Protocol { - - @Override - public Message decode(byte[] bytes) throws ProtocolException { - return null; - } - - @Override - public byte[] encode(Message msg) throws ProtocolException { - return new byte[0]; - } -} diff --git a/src/main/java/arhangel/dim/core/net/ConnectionHandler.java b/src/main/java/arhangel/dim/core/net/ConnectionHandler.java deleted file mode 100644 index c5df653..0000000 --- a/src/main/java/arhangel/dim/core/net/ConnectionHandler.java +++ /dev/null @@ -1,31 +0,0 @@ -package arhangel.dim.core.net; - -import java.io.IOException; - -import arhangel.dim.core.messages.Message; - -/** - * Описывает поведение слушателя сокета - * - */ -public interface ConnectionHandler { - - /** - * Отправить сообщение. - * Требуется обработать 2 типа ошибок - * @throws ProtocolException - ошибка протокола (не получилось кодировать/декодировать) - * @throws IOException - ошибка чтения/записи данных в сеть - */ - void send(Message msg) throws ProtocolException, IOException; - - /** - * Реакция на сообщение, пришедшее из сети - */ - void onMessage(Message msg); - - /** - * Молча (без проброса ошибок) закрываем соединение и освобождаем ресурсы - */ - void close(); - -} diff --git a/src/main/java/arhangel/dim/core/net/Protocol.java b/src/main/java/arhangel/dim/core/net/Protocol.java deleted file mode 100644 index e858333..0000000 --- a/src/main/java/arhangel/dim/core/net/Protocol.java +++ /dev/null @@ -1,14 +0,0 @@ -package arhangel.dim.core.net; - -import arhangel.dim.core.messages.Message; - -/** - * - */ -public interface Protocol { - - Message decode(byte[] bytes) throws ProtocolException; - - byte[] encode(Message msg) throws ProtocolException; - -} diff --git a/src/main/java/arhangel/dim/core/net/ProtocolException.java b/src/main/java/arhangel/dim/core/net/ProtocolException.java deleted file mode 100644 index e121590..0000000 --- a/src/main/java/arhangel/dim/core/net/ProtocolException.java +++ /dev/null @@ -1,14 +0,0 @@ -package arhangel.dim.core.net; - -/** - * - */ -public class ProtocolException extends Exception { - public ProtocolException(String msg) { - super(msg); - } - - public ProtocolException(Throwable ex) { - super(ex); - } -} diff --git a/src/main/java/arhangel/dim/core/net/Session.java b/src/main/java/arhangel/dim/core/net/Session.java deleted file mode 100644 index f9a161f..0000000 --- a/src/main/java/arhangel/dim/core/net/Session.java +++ /dev/null @@ -1,47 +0,0 @@ -package arhangel.dim.core.net; - -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.net.Socket; - -import arhangel.dim.core.User; -import arhangel.dim.core.messages.Message; - -/** - * Здесь храним всю информацию, связанную с отдельным клиентом. - * - объект User - описание пользователя - * - сокеты на чтение/запись данных в канал пользователя - */ -public class Session implements ConnectionHandler { - - /** - * Пользователь сессии, пока не прошел логин, user == null - * После логина устанавливается реальный пользователь - */ - private User user; - - // сокет на клиента - private Socket socket; - - /** - * С каждым сокетом связано 2 канала in/out - */ - private InputStream in; - private OutputStream out; - - @Override - public void send(Message msg) throws ProtocolException, IOException { - // TODO: Отправить клиенту сообщение - } - - @Override - public void onMessage(Message msg) { - // TODO: Пришло некое сообщение от клиента, его нужно обработать - } - - @Override - public void close() { - // TODO: закрыть in/out каналы и сокет. Освободить другие ресурсы, если необходимо - } -} diff --git a/src/main/java/arhangel/dim/core/net/StringProtocol.java b/src/main/java/arhangel/dim/core/net/StringProtocol.java deleted file mode 100644 index d4cd40a..0000000 --- a/src/main/java/arhangel/dim/core/net/StringProtocol.java +++ /dev/null @@ -1,65 +0,0 @@ -package arhangel.dim.core.net; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import arhangel.dim.core.messages.Message; -import arhangel.dim.core.messages.TextMessage; -import arhangel.dim.core.messages.Type; - -/** - * Простейший протокол передачи данных - */ -public class StringProtocol implements Protocol { - - static Logger log = LoggerFactory.getLogger(StringProtocol.class); - - public static final String DELIMITER = ";"; - - @Override - public Message decode(byte[] bytes) throws ProtocolException { - String str = new String(bytes); - log.info("decoded: {}", str); - String[] tokens = str.split(DELIMITER); - Type type = Type.valueOf(tokens[0]); - switch (type) { - case MSG_TEXT: - TextMessage textMsg = new TextMessage(); - textMsg.setSenderId(parseLong(tokens[1])); - textMsg.setText(tokens[2]); - textMsg.setType(type); - return textMsg; - default: - throw new ProtocolException("Invalid type: " + type); - } - } - - @Override - public byte[] encode(Message msg) throws ProtocolException { - StringBuilder builder = new StringBuilder(); - Type type = msg.getType(); - builder.append(type).append(DELIMITER); - switch (type) { - case MSG_TEXT: - TextMessage sendMessage = (TextMessage) msg; - builder.append(String.valueOf(sendMessage.getSenderId())).append(DELIMITER); - builder.append(sendMessage.getText()).append(DELIMITER); - break; - default: - throw new ProtocolException("Invalid type: " + type); - - - } - log.info("encoded: {}", builder.toString()); - return builder.toString().getBytes(); - } - - private Long parseLong(String str) { - try { - return Long.parseLong(str); - } catch (Exception e) { - // who care - } - return null; - } -} diff --git a/src/main/java/arhangel/dim/core/session/Session.java b/src/main/java/arhangel/dim/core/session/Session.java new file mode 100644 index 0000000..7a457b6 --- /dev/null +++ b/src/main/java/arhangel/dim/core/session/Session.java @@ -0,0 +1,75 @@ +package arhangel.dim.core.session; + +import arhangel.dim.core.authorization.Authorize; +import arhangel.dim.core.store.DataStore; + +import java.io.DataInputStream; +import java.io.DataOutputStream; + +/** + * Хранение данных о текущей сессии с клиентом + */ +public class Session { + /** + * Потоки для общения с клиентом + */ + private DataInputStream reader; + private DataOutputStream writer; + + /** + * Сервис авторизации и регистрации клиентов + */ + private Authorize authorize; + + private DataStore dataStore; + private String currentUserName; + private int currentUserId; + + private SessionManager sessionManager; + + public Session(DataInputStream reader, DataOutputStream writer, + Authorize authService, DataStore dataStore, SessionManager manager) { + this.reader = reader; + this.writer = writer; + this.authorize = authService; + this.dataStore = dataStore; + this.sessionManager = manager; + this.currentUserId = -1; + } + + public DataInputStream getReader() { + return reader; + } + + public DataOutputStream getWriter() { + return writer; + } + + public Authorize getAuthorize() { + return authorize; + } + + public String getCurrentUserName() { + return currentUserName; + } + + public void setCurrentUserName(String currentUserName) { + this.currentUserName = currentUserName; + } + + public DataStore getDataStore() { + return dataStore; + } + + public SessionManager getSessionManager() { + return sessionManager; + } + + public int getCurrentUserId() { + return currentUserId; + } + + public void setCurrentUserId(int currentUserId) { + this.currentUserId = currentUserId; + } +} diff --git a/src/main/java/arhangel/dim/core/session/SessionManager.java b/src/main/java/arhangel/dim/core/session/SessionManager.java new file mode 100644 index 0000000..0d3c850 --- /dev/null +++ b/src/main/java/arhangel/dim/core/session/SessionManager.java @@ -0,0 +1,36 @@ +package arhangel.dim.core.session; + +import java.util.HashSet; +import java.util.Set; + +/** + * Хранение всех активных сессий + */ +public class SessionManager { + private Set sessions; + + public SessionManager() { + sessions = new HashSet<>(); + } + + public Set getSessions() { + return sessions; + } + + public void setSessions(Set sessions) { + this.sessions = sessions; + } + + public synchronized void addSession(Session session) { + sessions.add(session); + } + + public Session getSessionById(int id) { + for (Session it: sessions) { + if (it.getCurrentUserId() == id) { + return it; + } + } + return null; + } +} diff --git a/src/main/java/arhangel/dim/core/store/ChatStore.java b/src/main/java/arhangel/dim/core/store/ChatStore.java new file mode 100644 index 0000000..0530c33 --- /dev/null +++ b/src/main/java/arhangel/dim/core/store/ChatStore.java @@ -0,0 +1,18 @@ +package arhangel.dim.core.store; + +import arhangel.dim.core.message.Chat; + +import java.sql.SQLException; +import java.util.List; +import java.util.Map; + +public interface ChatStore { + + int createChat(List participants) throws Exception; + + Map getChatList() throws Exception; + + Chat getChat(Integer id) throws Exception; + + void close() throws SQLException; +} diff --git a/src/main/java/arhangel/dim/core/store/DataBaseChatStore.java b/src/main/java/arhangel/dim/core/store/DataBaseChatStore.java new file mode 100644 index 0000000..52b951c --- /dev/null +++ b/src/main/java/arhangel/dim/core/store/DataBaseChatStore.java @@ -0,0 +1,91 @@ +package arhangel.dim.core.store; + +import arhangel.dim.core.jdbc.QueryExecutor; +import arhangel.dim.core.message.Chat; + +import java.sql.Connection; +import java.sql.SQLException; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * Реализация хранилища чатов в БД PostegreSql + */ + +public class DataBaseChatStore implements ChatStore { + private Connection connection; + private QueryExecutor executor; + + public DataBaseChatStore(Connection conn) { + this.connection = conn; + this.executor = new QueryExecutor(); + } + + @Override + public synchronized int createChat(List participants) throws Exception { + int chatId = -1; + String sql = "INSERT INTO chats (temp) VALUES (?)"; + Map queryArgs = new HashMap<>(); + queryArgs.put(1, "temp"); + executor.prepareStatementGeneratedKeys(connection, sql); + chatId = executor.execUpdate(sql, queryArgs, (resSet) -> { + if (resSet.next()) { + return resSet.getInt(1); + } + return -1; + }); + sql = "INSERT INTO userschat (user_id, chat_id) VALUES (?, ?)"; + executor.prepareStatement(connection, sql); + for (Integer userId : participants) { + queryArgs.clear(); + queryArgs.put(1, userId); + queryArgs.put(2, chatId); + executor.execUpdate(sql, queryArgs); + } + return chatId; + } + + @Override + public Map getChatList() throws Exception { + String sql = "SELECT * FROM userschat"; + return executor.execQuery(connection, sql, (resSet) -> { + Map result = new HashMap<>(); + while (resSet.next()) { + int chatId = resSet.getInt("chat_id"); + int userId = resSet.getInt("user_id"); + Chat chat = result.get(chatId); + if (chat == null) { + chat = new Chat(chatId, connection); + chat.addParticipant(userId); + result.put(chatId, chat); + } else { + chat.addParticipant(userId); + } + } + return result; + }); + } + + @Override + public Chat getChat(Integer id) throws Exception { + Chat result = new Chat(id, connection); + String sql = "SELECT * FROM userschat WHERE chat_id = ?"; + Map queryArgs = new HashMap<>(); + queryArgs.put(1, id); + executor.prepareStatement(connection, sql); + executor.execQuery(sql, queryArgs, (resSet) -> { + while (resSet.next()) { + int userId = resSet.getInt("user_id"); + result.addParticipant(userId); + } + return null; + }); + return result; + } + + @Override + public void close() throws SQLException { + executor.close(); + } +} diff --git a/src/main/java/arhangel/dim/core/store/DataBaseMessageStore.java b/src/main/java/arhangel/dim/core/store/DataBaseMessageStore.java new file mode 100644 index 0000000..10e99be --- /dev/null +++ b/src/main/java/arhangel/dim/core/store/DataBaseMessageStore.java @@ -0,0 +1,71 @@ +package arhangel.dim.core.store; + +import arhangel.dim.core.jdbc.QueryExecutor; +import arhangel.dim.core.message.Chat; +import arhangel.dim.core.message.Message; + +import java.sql.Connection; +import java.sql.SQLException; +import java.util.HashMap; +import java.util.Map; + +/** + * Реализация хранилища сообщений на БД PostegreSQL + */ +public class DataBaseMessageStore implements MessageStore { + private Connection connection; + private int chatId; + private QueryExecutor executor; + + public DataBaseMessageStore(Connection conn, Chat chat) { + this.connection = conn; + this.chatId = chat.getId(); + this.executor = new QueryExecutor(); + } + + @Override + public synchronized void addMessage(int authorId, String authorName, String value, Chat chat) throws Exception { + try { + if (value.contains("\'")) { + value = value.replace('\'', ' '); + } + String sql = "INSERT INTO message (author_id, value, chat_id) VALUES (? ,? ,?)"; + Map queryArgs = new HashMap<>(); + queryArgs.put(1, authorId); + queryArgs.put(2, value); + queryArgs.put(3, chat.getId()); + executor.prepareStatement(connection, sql); + executor.execUpdate(sql, queryArgs); + } catch (Exception e) { + System.err.println("MessageStore: failed to write data " + e.getMessage()); + } + } + + @Override + public synchronized Map getMessagesMap() throws Exception { + Map messageMap = new HashMap<>(); + String sql = "SELECT * FROM message WHERE chat_id = ? LIMIT 10000"; + Map queryArgs = new HashMap<>(); + queryArgs.put(1, chatId); + executor.prepareStatement(connection, sql); + executor.execQuery(sql, queryArgs, (r) -> { + while (r.next()) { + int authorId = r.getInt("author_id"); + String value = r.getString("value"); + int messageId = r.getInt("id"); + Message message = new Message(); + message.setAuthorId(authorId); + message.setMessage(value); + message.setId(messageId); + messageMap.put(messageId, message); + } + return null; + }); + return messageMap; + } + + @Override + public void close() throws SQLException { + executor.close(); + } +} diff --git a/src/main/java/arhangel/dim/core/store/DataBaseUserStore.java b/src/main/java/arhangel/dim/core/store/DataBaseUserStore.java new file mode 100644 index 0000000..5bff869 --- /dev/null +++ b/src/main/java/arhangel/dim/core/store/DataBaseUserStore.java @@ -0,0 +1,106 @@ +package arhangel.dim.core.store; + +import arhangel.dim.core.authorization.User; +import arhangel.dim.core.jdbc.QueryExecutor; + +import java.sql.Connection; +import java.sql.SQLException; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * Хранилище пользователей, реализованное на базе данных PostegreSql. + */ +public class DataBaseUserStore implements UserStore { + /** + * Соединение с БД + */ + private Connection connection; + + /** + * Исполнитель SQL-запросов + */ + private QueryExecutor executor; + + public DataBaseUserStore(Connection conn) { + this.connection = conn; + this.executor = new QueryExecutor(); + } + + @Override + public synchronized List getUserByName(String name) throws Exception { + if (name == null) { + return null; + } + Map queryArgs = new HashMap<>(); + queryArgs.put(1, name); + String sql = "SELECT * FROM USERS where LOGIN = ?"; + executor.prepareStatement(connection, sql); + return executor.execQuery(sql, queryArgs, (resSet) -> { + List data = new ArrayList<>(); + while (resSet.next()) { + User user = new User(resSet.getString("login"), + resSet.getString("password"), + resSet.getString("nick")); + + int id = resSet.getInt("id"); + user.setId(id); + data.add(user); + } + return data; + }); + } + + @Override + public synchronized User getUser(int id) throws Exception { + if (id < 0) { + return null; + } + Map queryArgs = new HashMap<>(); + queryArgs.put(1, id); + String sql = "SELECT * FROM USERS where ID = ?"; + executor.prepareStatement(connection, sql); + return executor.execQuery(sql, queryArgs, (resSet) -> { + User result = new User(); + while (resSet.next()) { + result = new User(resSet.getString("login"), resSet.getString("password"), resSet.getString("nick")); + result.setId(id); + } + return result; + }); + } + + @Override + public synchronized int addUser(User user) throws Exception { + if (user == null) { + System.out.println("Can't add user"); + return -1; + } + int result = -1; + try { + Map queryArgs = new HashMap<>(); + queryArgs.put(1, user.getName()); + queryArgs.put(2, Integer.toString(user.getPassword().hashCode())); + queryArgs.put(3, user.getName()); + String sql = "INSERT INTO USERS (LOGIN, PASSWORD, NICK) VALUES (?, ?, ? )"; + executor.prepareStatementGeneratedKeys(connection, sql); + result = executor.execUpdate(sql, queryArgs, (resSet) -> { + if (resSet.next()) { + return resSet.getInt(1); + } + return -1; + }); + } catch (Exception e) { + System.err.println("UserStore: failed to write data " + e.getMessage()); + throw e; + } + return result; + } + + @Override + public void close() throws SQLException { + executor.close(); + } +} diff --git a/src/main/java/arhangel/dim/core/store/DataStore.java b/src/main/java/arhangel/dim/core/store/DataStore.java new file mode 100644 index 0000000..e338272 --- /dev/null +++ b/src/main/java/arhangel/dim/core/store/DataStore.java @@ -0,0 +1,61 @@ +package arhangel.dim.core.store; + + +import arhangel.dim.core.commands.Command; +import arhangel.dim.core.commands.LoginCommand; +import arhangel.dim.core.commands.RegisterCommand; +import arhangel.dim.core.commands.UserInfoCommand; +import arhangel.dim.core.commands.TextCommand; +import arhangel.dim.core.commands.ChatCreateCommand; +import arhangel.dim.core.commands.ChatHistoryCommand; +import arhangel.dim.core.commands.ChatListCommand; +import arhangel.dim.core.commands.HelpCommand; + +import java.sql.Connection; +import java.util.HashMap; +import java.util.Map; + +/** + * Объединение всех хранилищ + */ +public class DataStore { + private UserStore userStore; + private Map commandsStore; + private ChatStore chatStore; + private Connection connection; + + public DataStore(UserStore fileUserStore, ChatStore chatStore, Connection conn) { + this.userStore = fileUserStore; + this.chatStore = chatStore; + this.connection = conn; + commandsStore = new HashMap<>(); + commandsStore.put("/register", new RegisterCommand()); + commandsStore.put("/login", new LoginCommand()); + commandsStore.put("/info", new UserInfoCommand()); + commandsStore.put("/chat_list", new ChatListCommand()); + commandsStore.put("/chat_create", new ChatCreateCommand()); + commandsStore.put("/chat_history", new ChatHistoryCommand()); + commandsStore.put("/text", new TextCommand()); + commandsStore.put("/help", new HelpCommand()); + + } + + public UserStore getUserStore() { + return userStore; + } + + public ChatStore getChatStore() { + return chatStore; + } + + public Map getCommandsStore() { + return commandsStore; + } + + public Connection getConnection() { + return connection; + } + + public void close() throws Exception { + } +} diff --git a/src/main/java/arhangel/dim/core/store/MessageStore.java b/src/main/java/arhangel/dim/core/store/MessageStore.java index e16bed8..807e27b 100644 --- a/src/main/java/arhangel/dim/core/store/MessageStore.java +++ b/src/main/java/arhangel/dim/core/store/MessageStore.java @@ -1,44 +1,19 @@ package arhangel.dim.core.store; -import java.util.List; +import java.sql.SQLException; +import java.util.Map; -import arhangel.dim.core.Chat; -import arhangel.dim.core.messages.Message; +import arhangel.dim.core.message.Chat; +import arhangel.dim.core.message.Message; /** * Хранилище информации о сообщениях */ public interface MessageStore { - /** - * получаем список ид пользователей заданного чата - */ - List getChatsByUserId(Long userId); - - /** - * получить информацию о чате - */ - Chat getChatById(Long chatId); - - /** - * Список сообщений из чата - */ - List getMessagesFromChat(Long chatId); - - /** - * Получить информацию о сообщении - */ - Message getMessageById(Long messageId); - - /** - * Добавить сообщение в чат - */ - void addMessage(Long chatId, Message message); - - /** - * Добавить пользователя к чату - */ - void addUserToChat(Long userId, Long chatId); + void addMessage(int authorId, String from, String message, Chat chat) throws Exception; + Map getMessagesMap() throws Exception; + void close() throws SQLException; } diff --git a/src/main/java/arhangel/dim/core/store/UserStore.java b/src/main/java/arhangel/dim/core/store/UserStore.java index d13ce6f..524f562 100644 --- a/src/main/java/arhangel/dim/core/store/UserStore.java +++ b/src/main/java/arhangel/dim/core/store/UserStore.java @@ -1,34 +1,20 @@ package arhangel.dim.core.store; -import arhangel.dim.core.User; +import arhangel.dim.core.authorization.User; + +import java.sql.SQLException; +import java.util.List; + /** - * Хранилище информации о пользователе + * Хранилище пользователей */ public interface UserStore { + User getUser(int id) throws Exception; - /** - * Добавить пользователя в хранилище - * Вернуть его же - */ - User addUser(User user); - - /** - * Обновить информацию о пользователе - */ - User updateUser(User user); + List getUserByName(String name) throws Exception; - /** - * - * Получить пользователя по логину/паролю - * return null if user not found - */ - User getUser(String login, String pass); + int addUser(User user) throws Exception; - /** - * - * Получить пользователя по id, например запрос информации/профиля - * return null if user not found - */ - User getUserById(Long id); + void close() throws SQLException; } diff --git a/src/main/java/arhangel/dim/lections/classez/IntWrapper.java b/src/main/java/arhangel/dim/lections/classez/IntWrapper.java deleted file mode 100644 index 7359449..0000000 --- a/src/main/java/arhangel/dim/lections/classez/IntWrapper.java +++ /dev/null @@ -1,35 +0,0 @@ -package arhangel.dim.lections.classez; - -/** - * Created by Rustam on 29.03.2016. - */ -public class IntWrapper { - - Monad operation; - Monad num; - - public IntWrapper setOperation(Monad operation) { - this.operation = operation; - return this; - } - - public IntWrapper setNum(Monad num) { - this.num = num; - return this; - } - - public int calculate(int num2) { - int result = 0; - operation.apply("asd"); - num.apply(12); -// switch (operation) { -// case "+": result = num + num2; break; -// case "-": result = num - num2; break; -// } - return result; - } - - interface Monad { - T apply(T arg); - } -} diff --git a/src/main/java/arhangel/dim/lections/classez/Main.java b/src/main/java/arhangel/dim/lections/classez/Main.java deleted file mode 100644 index f5ed91f..0000000 --- a/src/main/java/arhangel/dim/lections/classez/Main.java +++ /dev/null @@ -1,34 +0,0 @@ -package arhangel.dim.lections.classez; - -/** - * Created by r.kildiev on 29.03.2016. - */ - -//Lecture Slides https://drive.google.com/open?id=0Bz3AMLjdKktjdDl6MXhQTFBIU2M -public class Main { - public static void main(String[] args) { - Outer outer = new Outer(); - outer.anonymous(); -// Outer.Inner innerClass = outer.inner; -// System.out.println(innerClass.localInt); -// Outer.Inner inner2 = new Outer.Inner(); - - IntWrapper intWrapper = new IntWrapper(); - intWrapper.setOperation(new IntWrapper.Monad() { - @Override - public String apply(String arg) { - System.out.println("apply String"); - return "++".substring(1); - } - }) - .setNum(new IntWrapper.Monad() { - @Override - public Integer apply(Integer arg) { - System.out.println("apply Integer"); - return arg + 1; - } - }) - .calculate(3) - ; - } -} diff --git a/src/main/java/arhangel/dim/lections/classez/Outer.java b/src/main/java/arhangel/dim/lections/classez/Outer.java deleted file mode 100644 index 45fa04f..0000000 --- a/src/main/java/arhangel/dim/lections/classez/Outer.java +++ /dev/null @@ -1,49 +0,0 @@ -package arhangel.dim.lections.classez; - -/** - * Created by r.kildiev on 29.03.2016. - */ -class Outer { - Inner inner = new Inner(); - - void anonymous() { - - HelloWorld greeting = /*class $1 implements*/new HelloWorld() { - public String greet() { - System.out.println("Hello World"); - return null; - } - }; - String result = greeting.greet().substring(3); - } - - interface HelloWorld { - public String greet(); - } - - class Inner { - int innerField = 0; - int localInt = 1; - - String local = new String(); - - public Inner() { - - } - - void localMethod() { - /*private*/ - class Local { - int outerLocalInt; - int localInt = 2; - - // static String field = ""; - public Local() { - } - } -// int localInt = local.localInt; - //blah blah code - } - } - -} diff --git a/src/main/java/arhangel/dim/lections/collections/BoundGenerics.java b/src/main/java/arhangel/dim/lections/collections/BoundGenerics.java deleted file mode 100644 index 2f982b0..0000000 --- a/src/main/java/arhangel/dim/lections/collections/BoundGenerics.java +++ /dev/null @@ -1,102 +0,0 @@ -package arhangel.dim.lections.collections; - -import java.util.ArrayList; -import java.util.List; - -/** - * - */ -public class BoundGenerics { - - static class Animal { - void feed() { - System.out.println("Animal feed()"); - } - } - - static class Pet extends Animal { - void call() { - System.out.println("Pet call()"); - } - } - - static class Cat extends Pet { - void mew() { - System.out.println("Cat mew()"); - } - } - - static class Dog extends Pet { - void bark() { - System.out.println("Dog bark()"); - } - } - - - static void fillPets(List pets) { - pets.add(new Dog()); - pets.add(new Cat()); - } - - static void copy(List dest, List src) { - - for (T e : src) { - dest.add(e); - } - - // src.stream().forEach(dest::add); - } - - public static void main(String[] args) { - List cats = new ArrayList<>(); - cats.add(new Cat()); - cats.add(new Cat()); - - - List pets = cats; - - - List dogs = new ArrayList<>(); - dogs.add(new Dog()); - dogs.add(new Dog()); - - callPets(cats); // Incompatible types (compile time) -// callPets(dogs); - - - List animals = new ArrayList<>(); - // Incompatible types -// fillPets(animals); - - } - -// static void callPets(List list) { -// // Позовем домашних питомцев -// for (Pet pet : list) { -// pet.call(); -// } -// } - - // Коллекция pets - поставщик данных (producer) -// static void callPets(List pets) { -// for (T item : pets) { -// item.call(); -// } -// -// //pets.stream().forEach(Pet::call); -// } - - - static void callPets(List pets) { - pets.stream().forEach(Pet::call); - } - - - // Коллекция pets - потребитель данных (consumer) -// static void fillPets(List pets) { -// pets.add(new Dog()); -// pets.add(new Cat()); -// } - - -} diff --git a/src/main/java/arhangel/dim/lections/collections/Box.java b/src/main/java/arhangel/dim/lections/collections/Box.java deleted file mode 100644 index 468d37c..0000000 --- a/src/main/java/arhangel/dim/lections/collections/Box.java +++ /dev/null @@ -1,28 +0,0 @@ -package arhangel.dim.lections.collections; - -/** - * - */ -public class Box { - private T item; - - public Box(T item) { - this.item = item; - } - - public T getItem() { - return item; - } - - public void setItem(T item) { - this.item = item; - // Object - nothing more - } - - @Override - public String toString() { - return "Box{" + - "item=" + item + - '}'; - } -} diff --git a/src/main/java/arhangel/dim/lections/collections/Demo.java b/src/main/java/arhangel/dim/lections/collections/Demo.java deleted file mode 100644 index d862eae..0000000 --- a/src/main/java/arhangel/dim/lections/collections/Demo.java +++ /dev/null @@ -1,60 +0,0 @@ -package arhangel.dim.lections.collections; - -import java.util.Arrays; -import java.util.List; -import java.util.function.Consumer; -import java.util.function.Predicate; - -/** - * 7 - */ -public class Demo { - - // SAM - Single Abstract Method - static class MyPredicate implements Predicate { - @Override - public boolean test(Integer integer) { - return integer % 2 != 0; - } - } - - static class MyConsumer implements Consumer { - @Override - public void accept(T item) { - System.out.println("# " + item); - } - } - - public static void main(String[] args) { - List numbers = Arrays.asList(1, 2, 3, 4, 5, 6, 7); - - // Filter with predicate - final int skip = 3; - // skip = 4; - numbers.stream().filter(new MyPredicate()).forEach(new MyConsumer<>()); - - numbers - .stream() - .filter((val) -> val != skip) - .forEach(System.out::println); - - - // Map - - int sum = numbers.stream() - .map((val) -> val * val) - .reduce(0, (val1, val2) -> val1 + val2); - System.out.println("sum: " + sum); - - - List myList = - Arrays.asList("a1", "a2", "b1", "c2", "c1"); - - myList.stream() - .filter(s -> s.startsWith("c")) - .map(String::toUpperCase) - .sorted() - .forEach(System.out::println); - - } -} diff --git a/src/main/java/arhangel/dim/lections/collections/FunctionalProgramming.java b/src/main/java/arhangel/dim/lections/collections/FunctionalProgramming.java deleted file mode 100644 index 53a84da..0000000 --- a/src/main/java/arhangel/dim/lections/collections/FunctionalProgramming.java +++ /dev/null @@ -1,75 +0,0 @@ -package arhangel.dim.lections.collections; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collection; -import java.util.Collections; -import java.util.List; - - -public class FunctionalProgramming { - - // Принимает одно значение, возвращает одно значение - interface Function { - R apply(T val); - } - - // Принимает элемент и проверяет его на условие - interface Predicate { - boolean test(T val); - } - - // Принимает 2 аргумента, проводит опреацию и возвращает результат - interface BiFunction { - R apply(U val1, V val2); - } - - // 2 аргумента одного типа - interface BiOperator extends BiFunction { - T apply(T val1, T val2); - } - - static class Square implements Function { - public Integer apply(Integer val) { - return val * val; - } - } - - /* - Применить к каждому элементу коллекции заданную операцию - */ - static List map(Collection collection, Function functor) { - return Collections.emptyList(); - } - - /* - Проверить элементы коллекции на заданное условие. - Вернуть коллекцию элементов, прошедших фильтр - */ - static List filter(List list, Predicate predicate) { - return Collections.emptyList(); - } - - /* - Последовательно применить операцию ко всем элементам коллекции - Вернуть одно значение - */ - static T reduce(List list, T init, BiOperator op) { - return null; - } - - public static void main(String[] args) { - List numbers = Arrays.asList(1, 2, 3, 4); - - // Returned 1, 4, 9, 16 - System.out.println("map [^2]: " + numbers + " -> " + map(numbers, new Square())); - - System.out.println("filter [%3]: " + numbers + " -> " + filter(numbers, new Predicate() { - @Override - public boolean test(Integer val) { - return val % 3 != 0; - } - })); - - } -} diff --git a/src/main/java/arhangel/dim/lections/collections/Stack.java b/src/main/java/arhangel/dim/lections/collections/Stack.java deleted file mode 100644 index a04f604..0000000 --- a/src/main/java/arhangel/dim/lections/collections/Stack.java +++ /dev/null @@ -1,26 +0,0 @@ -package arhangel.dim.lections.collections; - -import java.util.Collection; - -/** - * - */ -public interface Stack extends Iterable { - - void push(E element) throws StackException; - - E pop() throws StackException; - - E peek(); - - int getSize(); - - boolean isEmpty(); - - boolean isFull(); - - // A little bit wrong =( Could you fix it? - void pushAll(Collection src) throws StackException; - - void popAll(Collection dst) throws StackException; -} diff --git a/src/main/java/arhangel/dim/lections/collections/StackException.java b/src/main/java/arhangel/dim/lections/collections/StackException.java deleted file mode 100644 index afdd057..0000000 --- a/src/main/java/arhangel/dim/lections/collections/StackException.java +++ /dev/null @@ -1,10 +0,0 @@ -package arhangel.dim.lections.collections; - -/** - * - */ -public class StackException extends Exception { - public StackException(String msg) { - super(msg); - } -} diff --git a/src/main/java/arhangel/dim/lections/exception/ExceptionDemo.java b/src/main/java/arhangel/dim/lections/exception/ExceptionDemo.java deleted file mode 100644 index 35295fa..0000000 --- a/src/main/java/arhangel/dim/lections/exception/ExceptionDemo.java +++ /dev/null @@ -1,86 +0,0 @@ -package arhangel.dim.lections.exception; - - -import java.io.IOException; -import java.sql.Connection; - -/** - * - */ -public class ExceptionDemo { - - public static void convertString(String str) { - if (str == null) { - throw new IllegalArgumentException("Arg str must be non-null"); - } - } - - public static void m1() throws Exception { - throw new ArithmeticException("Amth"); - } - - public static void m2() throws Exception { - try { - m1(); - } catch (Exception e) { - throw new Exception(e); - } - } - - public static void main(String[] args) throws Exception { - - try { - m2(); - } catch (IllegalArgumentException e) { - e.printStackTrace(); - } - - //convertString(null); - -// System.out.println("str == null -> " + getSize(null)); -// System.out.println("str != null -> " + getSize("test")); - - //exceptionLost(); - - } - - public static int getSize(String str) { - Connection conn = null; - try { - return str.length(); - } catch (Exception e) { - System.out.println("in catch block"); - //System.exit(0); - return -1; - } finally { - if (conn != null) { - try { - conn.close(); - } catch (Exception e) { - // do nothing - } - } - return 0; - } - } - - public static void exceptionLost() throws Exception { - try { - try { - throw new Exception("a"); - } catch (Exception e) { - System.out.println("In catch"); - throw e; // a - } finally { - System.out.println("In finally block"); - -// if (true) { -// throw new IOException("b"); -// } - System.err.println("c"); - } - } catch (IOException e) { - System.err.println(e.getMessage()); - } - } -} diff --git a/src/main/java/arhangel/dim/lections/jdbc/JdbcExample.java b/src/main/java/arhangel/dim/lections/jdbc/JdbcExample.java deleted file mode 100644 index 268dee2..0000000 --- a/src/main/java/arhangel/dim/lections/jdbc/JdbcExample.java +++ /dev/null @@ -1,179 +0,0 @@ -package arhangel.dim.lections.jdbc; - -/** - * Created by r.kildiev on 02.11.2015. - */ - -import java.sql.Connection; -import java.sql.DriverManager; -import java.sql.ResultSet; -import java.sql.SQLException; -import java.sql.Statement; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -import arhangel.dim.core.User; - -public class JdbcExample { - - public static void main(String[] argv) throws SQLException, ClassNotFoundException { - - Class.forName("org.postgresql.Driver"); - - Connection connection = DriverManager.getConnection("jdbc:postgresql://178.62.140.149:5432/main", - "trackuser", "trackuser"); - - Statement stmt; - String sql; - - stmt = connection.createStatement(); - sql = "CREATE TABLE IF NOT EXISTS company" + - "(ID INT PRIMARY KEY NOT NULL," + - " NAME TEXT NOT NULL, " + - " AGE INT NOT NULL, " + - " ADDRESS CHAR(50), " + - " SALARY REAL)"; - stmt.executeUpdate(sql); - stmt.close(); -// c.close(); - - connection.setAutoCommit(false); - - stmt = connection.createStatement(); - sql = "INSERT INTO COMPANY (ID,NAME,AGE,ADDRESS,SALARY) VALUES (1, 'Paul', 32, 'California', 20000.00 );"; - stmt.executeUpdate(sql); - - sql = "INSERT INTO COMPANY (ID,NAME,AGE,ADDRESS,SALARY) VALUES (2, 'Allen', 25, 'Texas', 15000.00 );"; - stmt.executeUpdate(sql); - - sql = "INSERT INTO COMPANY (ID,NAME,AGE,ADDRESS,SALARY) VALUES (3, 'Teddy', 23, 'Norway', 20000.00 );"; - stmt.executeUpdate(sql); - - sql = "INSERT INTO COMPANY (ID,NAME,AGE,ADDRESS,SALARY) VALUES (4, 'Mark', 25, 'Rich-Mond ', 65000.00 );"; - stmt.executeUpdate(sql); - - stmt.close(); - connection.commit(); -// c.close(); - - stmt = connection.createStatement(); - ResultSet rs = stmt.executeQuery("SELECT * FROM COMPANY;"); - while (rs.next()) { - int id = rs.getInt("id"); - String name = rs.getString("name"); - int age = rs.getInt("age"); - String address = rs.getString("address"); - float salary = rs.getFloat("salary"); - System.out.println("ID = " + id); - System.out.println("NAME = " + name); - System.out.println("AGE = " + age); - System.out.println("ADDRESS = " + address); - System.out.println("SALARY = " + salary); - System.out.println(); - } - rs.close(); - stmt.close(); -// c.close(); - - stmt = connection.createStatement(); - sql = "UPDATE COMPANY SET SALARY = 25000.00 WHERE ID=1;"; - stmt.executeUpdate(sql); - connection.commit(); - - rs = stmt.executeQuery("SELECT * FROM COMPANY;"); - while (rs.next()) { - int id = rs.getInt("id"); - String name = rs.getString("name"); - int age = rs.getInt("age"); - String address = rs.getString("address"); - float salary = rs.getFloat("salary"); - System.out.println("ID = " + id); - System.out.println("NAME = " + name); - System.out.println("AGE = " + age); - System.out.println("ADDRESS = " + address); - System.out.println("SALARY = " + salary); - System.out.println(); - } - rs.close(); - stmt.close(); -// c.close(); - - stmt = connection.createStatement(); - sql = "DELETE FROM COMPANY WHERE ID=2;"; - stmt.executeUpdate(sql); - connection.commit(); - - rs = stmt.executeQuery("SELECT * FROM COMPANY;"); - while (rs.next()) { - int id = rs.getInt("id"); - String name = rs.getString("name"); - int age = rs.getInt("age"); - String address = rs.getString("address"); - float salary = rs.getFloat("salary"); - System.out.println("ID = " + id); - System.out.println("NAME = " + name); - System.out.println("AGE = " + age); - System.out.println("ADDRESS = " + address); - System.out.println("SALARY = " + salary); - System.out.println(); - } - rs.close(); - stmt.close(); - connection.close(); - -// PreparedStatement prepStmnt = c.prepareStatement("INSERT INTO COMPANY (ID,NAME,AGE,ADDRESS,SALARY) " -// + "VALUES (2, 'Allen', 25, 'Texas', 15000.00 );"); -// int parameterIndex = 234; -// prepStmnt.setString(parameterIndex, "asd"); -// rs = prepStmnt.executeQuery(); - - - - /** - * Использование executor для запроса в базу - */ - QueryExecutor exec = new QueryExecutor(); - List users = exec.execQuery(connection, "SELECT * FROM users;", (rset) -> { - System.out.println("handle:"); - List data = new ArrayList<>(); - while (rset.next()) { - User user = new User(); - user.setName(rset.getString(2)); - data.add(user); - } - return data; - }); - - System.out.println(users.toString()); - - - /** - * Использование prepared executor для запроса в базу - */ - Map prepared = new HashMap<>(); - prepared.put(1, "John"); - - users = exec.execQuery(connection, "SELECT * FROM users WHERE name = ?;", prepared, (rset) -> { - System.out.println("handle:"); - List data = new ArrayList<>(); - while (rset.next()) { - User user = new User(); - user.setName(rset.getString(2)); - data.add(user); - } - return data; - }); - - System.out.println(users.toString()); - - - - - - } - - - -} diff --git a/src/main/java/arhangel/dim/lections/jdbc/QueryExecutor.java b/src/main/java/arhangel/dim/lections/jdbc/QueryExecutor.java deleted file mode 100644 index 6e5e512..0000000 --- a/src/main/java/arhangel/dim/lections/jdbc/QueryExecutor.java +++ /dev/null @@ -1,42 +0,0 @@ -package arhangel.dim.lections.jdbc; - -import java.sql.Connection; -import java.sql.PreparedStatement; -import java.sql.ResultSet; -import java.sql.SQLException; -import java.sql.Statement; -import java.util.Map; - -/** - * - */ -public class QueryExecutor { - - // Простой запрос - public T execQuery(Connection connection, String query, ResultHandler handler) throws SQLException { - Statement stmt = connection.createStatement(); - stmt.execute(query); - ResultSet result = stmt.getResultSet(); - T value = handler.handle(result); - result.close(); - stmt.close(); - - return value; - } - - // Подготовленный запрос - public T execQuery(Connection connection, String query, Map args, ResultHandler handler) throws SQLException { - PreparedStatement stmt = connection.prepareStatement(query); - for (Map.Entry entry : args.entrySet()) { - stmt.setObject(entry.getKey(), entry.getValue()); - } - ResultSet rs = stmt.executeQuery(); - T value = handler.handle(rs); - rs.close(); - stmt.close(); - return value; - } - - // Также нужно реализовать Update запросы - -} diff --git a/src/main/java/arhangel/dim/lections/objects/AServer.java b/src/main/java/arhangel/dim/lections/objects/AServer.java deleted file mode 100644 index 7e53ad2..0000000 --- a/src/main/java/arhangel/dim/lections/objects/AServer.java +++ /dev/null @@ -1,29 +0,0 @@ -package arhangel.dim.lections.objects; - -/** - * - */ -public abstract class AServer { - - protected abstract boolean validate(String[] params); - - protected abstract void processContent(); - - protected String onError() { - return "Failed to parse request"; - } - - public void doGet(String request) { - String[] parameters = parseParameters(request); - if (validate(parameters)) { - processContent(); - } else { - onError(); - } - } - - private String[] parseParameters(String request) { - // разбираем строку параметров - return null; - } -} diff --git a/src/main/java/arhangel/dim/lections/objects/AbstractExample.java b/src/main/java/arhangel/dim/lections/objects/AbstractExample.java deleted file mode 100644 index ac55544..0000000 --- a/src/main/java/arhangel/dim/lections/objects/AbstractExample.java +++ /dev/null @@ -1,34 +0,0 @@ -package arhangel.dim.lections.objects; - -/** - * - */ -public class AbstractExample { - - public static void main(String[] args) { - - // Создаем класс-потомок - AServer imageServer = new ImageServer(); - imageServer.processContent(); - - // Нельзя создать инстанс абстрактного класса - // AServer aserver = new AServer(); - - - // Можно создать анонимный класс - AServer server = new AServer() { - @Override - protected boolean validate(String[] params) { - return false; - } - - @Override - protected void processContent() { - - } - }; - } - -} - - diff --git a/src/main/java/arhangel/dim/lections/objects/Button.java b/src/main/java/arhangel/dim/lections/objects/Button.java deleted file mode 100644 index c202d3c..0000000 --- a/src/main/java/arhangel/dim/lections/objects/Button.java +++ /dev/null @@ -1,36 +0,0 @@ -package arhangel.dim.lections.objects; - -import java.util.ArrayList; -import java.util.List; - -/** - * - */ -public class Button { - private ClickListener[] listeners = new ClickListener[10]; - private int count = 0; - - // закоментирован вариант с List - //private List listenerList = new ArrayList<>(); - - // Добавляем себе подписчиков - public void addListener(ClickListener listener) { - listeners[count++] = listener; - - //listenerList.add(listener); - } - - // На кнопку кто-то нажал и теперь все об этом узнают - public void click() { - for (int i = 0; i < count; i++) { - listeners[i].onClick(); - } - -// for (ClickListener listener : listenerList) { -// listener.onClick(); -// } - } - - - -} diff --git a/src/main/java/arhangel/dim/lections/objects/ClickListener.java b/src/main/java/arhangel/dim/lections/objects/ClickListener.java deleted file mode 100644 index 3d4bc7b..0000000 --- a/src/main/java/arhangel/dim/lections/objects/ClickListener.java +++ /dev/null @@ -1,10 +0,0 @@ -package arhangel.dim.lections.objects; - -/** - * - */ -public interface ClickListener { - - // do smth on click - void onClick(); -} diff --git a/src/main/java/arhangel/dim/lections/objects/ImageServer.java b/src/main/java/arhangel/dim/lections/objects/ImageServer.java deleted file mode 100644 index 8c8c4bb..0000000 --- a/src/main/java/arhangel/dim/lections/objects/ImageServer.java +++ /dev/null @@ -1,22 +0,0 @@ -package arhangel.dim.lections.objects; - -/** - * - */ -public class ImageServer extends AServer { - @Override - protected boolean validate(String[] params) { - return params.length > 0 && params[0].equals("imageId"); - } - - @Override - protected void processContent() { - // Загрузим картинку и отдадим ее пользователю - } - - @Override - protected String onError() { - return "Failed to parse ImageId"; - } -} - diff --git a/src/main/java/arhangel/dim/lections/objects/LinkageTest.java b/src/main/java/arhangel/dim/lections/objects/LinkageTest.java deleted file mode 100644 index 0dba290..0000000 --- a/src/main/java/arhangel/dim/lections/objects/LinkageTest.java +++ /dev/null @@ -1,37 +0,0 @@ -package arhangel.dim.lections.objects; - -/** - * - */ -public class LinkageTest { - - static class Parent { - void test() { - System.out.println("parent::test()"); - } - } - - static class Child extends Parent { - @Override - void test() { - System.out.println("child::test()"); - } - } - - static void use(Parent item) { - System.out.println("use::parent"); - item.test(); - } - - static void use(Child item) { - System.out.println("use::child"); - item.test(); - } - - public static void main(String[] args) { - Parent item = new Child(); - use(item); - - } - -} diff --git a/src/main/java/arhangel/dim/lections/objects/ListenerDemo.java b/src/main/java/arhangel/dim/lections/objects/ListenerDemo.java deleted file mode 100644 index 264e055..0000000 --- a/src/main/java/arhangel/dim/lections/objects/ListenerDemo.java +++ /dev/null @@ -1,54 +0,0 @@ -package arhangel.dim.lections.objects; - -/** - * - */ -public class ListenerDemo { - - public static void main(String[] args) { - - Canvas canvas = new Canvas(); - Pentagon pentagon = new Pentagon(); - - Button redButton = new Button(); - redButton.addListener(canvas); - redButton.addListener(pentagon); - redButton.addListener(new Ussr()); - - redButton.click(); - } - - static class Canvas implements ClickListener { - - // Много методов про отрисовку экрана - - @Override - public void onClick() { - System.out.println("CANVAS: Button was pressed"); - } - } - - static class Pentagon implements ClickListener { - - public void alarm() { - System.out.println("ALARM!"); - } - - @Override - public void onClick() { - alarm(); - } - } - - static class Ussr implements ClickListener { - private void launchRocket() { - System.out.println("Ракеты запущены, командир!"); - } - - @Override - public void onClick() { - launchRocket(); - } - } - -} diff --git a/src/main/java/arhangel/dim/lections/objects/LoaderDemo.java b/src/main/java/arhangel/dim/lections/objects/LoaderDemo.java deleted file mode 100644 index 3d0a6d0..0000000 --- a/src/main/java/arhangel/dim/lections/objects/LoaderDemo.java +++ /dev/null @@ -1,40 +0,0 @@ -package arhangel.dim.lections.objects; - -import java.net.URI; - -/** - * - */ -public class LoaderDemo { - - public static void main(String[] args) throws Exception { - //Loader loader = new XmlLoader(); - Loader loader = new NetLoader(); - Resource resource = loader.load(new URI("test-path")); - } -} - -class Resource { - // класс с настройками -} - -interface Loader { - Resource load(URI uri); -} - -class XmlLoader implements Loader { - @Override - public Resource load(URI uri) { - // read XML and parse - return new Resource(); - } -} - -class NetLoader implements Loader { - @Override - public Resource load(URI uri) { - // read Resources from internet - return new Resource(); - } -} - diff --git a/src/main/java/arhangel/dim/lections/objects/Polimorf.java b/src/main/java/arhangel/dim/lections/objects/Polimorf.java deleted file mode 100644 index 405ed1b..0000000 --- a/src/main/java/arhangel/dim/lections/objects/Polimorf.java +++ /dev/null @@ -1,71 +0,0 @@ -package arhangel.dim.lections.objects; - -import java.util.ArrayList; -import java.util.List; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * - */ -public class Polimorf { - - private static Logger log = LoggerFactory.getLogger(Polimorf.class); - - static class Parent { - void test() { - System.out.println("parent::test()"); - } - - void testParent() { - System.out.println("parent::testParent()"); - } - } - - static class Child extends Parent { - @Override - void test() { - System.out.println("child::test()"); - } - - void testChild() { - System.out.println("child::testParent()"); - } - } - - public static void main(String[] args) { - Parent item = new Child(); - - System.out.println("===Parent -> Child==="); - // Late binding - invoke Child impl - item.test(); - item.testParent(); - // No such method in Parent - //item.testChild(); - - System.out.println("===Child -> Child==="); - Child other = new Child(); - other.test(); - other.testChild(); - other.testParent(); - - System.out.println("===Collection==="); - List list = new ArrayList<>(); - list.add(new Child()); - list.add(new Parent()); - - // Using for loop (old!) - for (Parent p : list) { - p.test(); - } - - // Using stream - //list.stream().forEach(p -> p.test()); - - // Using method references - // list.stream().forEach(Parent::test); - - - } -} diff --git a/src/main/java/arhangel/dim/lections/objects/StaticDemo.java b/src/main/java/arhangel/dim/lections/objects/StaticDemo.java deleted file mode 100644 index ed20f23..0000000 --- a/src/main/java/arhangel/dim/lections/objects/StaticDemo.java +++ /dev/null @@ -1,65 +0,0 @@ -package arhangel.dim.lections.objects; - - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * - */ -public class StaticDemo { - - private static Logger log = LoggerFactory.getLogger(StaticDemo.class); - - public static void main(String[] args) { - log.info("Account counter: " + Account.idCounter); - - int current = Account.idCounter; - // Запрещено, id - это поле экземпляра, его нужно создать и инициализировать - //int id = Account.id; - - for (int i = 0; i < 5; i++) { - Account acc = new Account(); - log.info(acc.toString()); - } - - Account acc = null; - - // Так делать нехорошо! - acc.idCounter = 10; - - // А так можно - Account.idCounter = 10; - - - } -} - -class Account { - - static int idCounter = 0; - int id; - - public Account() { - id = idCounter++; - } - - public static Account createAccount() { - System.out.println("Account created"); - return new Account(); - } - - @Override - public String toString() { - return "Account{" + - "id=" + id + - '}'; - } -} - -class ExtAccount extends Account { - public static Account createAccount() { - System.out.println("Ext Account created"); - return new Account(); - } -} diff --git a/src/main/java/arhangel/dim/lections/reflection/Reflect.java b/src/main/java/arhangel/dim/lections/reflection/Reflect.java deleted file mode 100644 index a23bf75..0000000 --- a/src/main/java/arhangel/dim/lections/reflection/Reflect.java +++ /dev/null @@ -1,155 +0,0 @@ -package arhangel.dim.lections.reflection; - -import java.io.Serializable; -import java.lang.annotation.Annotation; -import java.lang.reflect.Constructor; -import java.lang.reflect.Field; -import java.lang.reflect.Method; -import java.lang.reflect.Modifier; - -/** - * - */ -class Test implements Serializable, Cloneable { - private int field; - - public Test() { - - } - - public Test(Object field) { } - - @Deprecated - protected static void method(String[] params) { } - - - public void foo() { - System.out.println("FOO"); - } - - @Override - public String toString() { - return "Test{" + - "field=" + field + - '}'; - } -} - -public class Reflect { - public static void main(String[] args) throws Exception { - Class clazz = Test.class; - Test test = (Test) clazz.newInstance(); - - clazz.getConstructors(); - - // вызвать метод по имени у заданного объекта - Method method = clazz.getMethod("foo"); - System.out.println(method.toString()); - method.invoke(test); - - // установить поле по имени у заданного объекта - Field field0 = clazz.getDeclaredField("field"); - field0.setAccessible(true); - field0.set(test, 100); - System.out.println(test); - - // выводим название пакета - Package pack = clazz.getPackage(); - System.out.println("package " + pack.getName() + ";"); - - // начинаем декларацию класса с модификаторов - int modifiers = clazz.getModifiers(); - System.out.print(getModifiers(modifiers)); - // выводим название класса - System.out.print("class " + clazz.getSimpleName() + " "); - - // выводим название родительского класса - System.out.print("extends " + clazz.getSuperclass().getSimpleName() + " "); - - // выводим интерфейсы, которые реализует класс - Class[] interfaces = clazz.getInterfaces(); - for (int i = 0, size = interfaces.length; i < size; i++) { - System.out.print(i == 0 ? "implements " : ", "); - System.out.print(interfaces[i].getSimpleName()); - } - System.out.println(" {"); - - // выводим поля класса - Field[] fields = clazz.getDeclaredFields(); - for (Field field : fields) { - System.out.println("\t" + getModifiers(field.getModifiers()) + - getType(field.getType()) + " " + field.getName() + ";"); - } - - // выводим констукторы класса - Constructor[] constructors = clazz.getDeclaredConstructors(); - for (Constructor c : constructors) { - System.out.print("\t" + getModifiers(c.getModifiers()) + - clazz.getSimpleName() + "("); - System.out.print(getParameters(c.getParameterTypes())); - System.out.println(") { }"); - } - - // выводим методы класса - Method[] methods = clazz.getDeclaredMethods(); - for (Method m : methods) { - // получаем аннотации - Annotation[] annotations = m.getAnnotations(); - System.out.print("\t"); - for (Annotation a : annotations) { - System.out.print("@" + a.annotationType().getSimpleName() + " "); - } - System.out.println(); - - System.out.print("\t" + getModifiers(m.getModifiers()) + - getType(m.getReturnType()) + " " + m.getName() + "("); - System.out.print(getParameters(m.getParameterTypes())); - System.out.println(") { }"); - } - - System.out.println("}"); - - - } - - static String getModifiers(int mod) { - String modifiers = ""; - if (Modifier.isPublic(mod)) { - modifiers += "public "; - } - if (Modifier.isProtected(mod)) { - modifiers += "protected "; - } - if (Modifier.isPrivate(mod)) { - modifiers += "private "; - } - if (Modifier.isStatic(mod)) { - modifiers += "static "; - } - if (Modifier.isAbstract(mod)) { - modifiers += "abstract "; - } - - return modifiers; - } - - static String getType(Class clazz) { - String type = clazz.isArray() ? clazz.getComponentType().getSimpleName() - : clazz.getSimpleName(); - if (clazz.isArray()) { - type += "[]"; - } - return type; - } - - static String getParameters(Class[] params) { - String param = ""; - for (int i = 0, size = params.length; i < size; i++) { - if (i > 0) { - param += ", "; - } - param += getType(params[i]) + " param" + i; - } - return param; - } -} diff --git a/src/main/java/arhangel/dim/lections/socket/Client.java b/src/main/java/arhangel/dim/lections/socket/Client.java deleted file mode 100644 index 1c794a2..0000000 --- a/src/main/java/arhangel/dim/lections/socket/Client.java +++ /dev/null @@ -1,46 +0,0 @@ -package arhangel.dim.lections.socket; - -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.net.Socket; - -/** - * Клиентская часть - */ -public class Client { - - public static final int PORT = 19000; - public static final String HOST = "localhost"; - - public static void main(String[] args) { - - Socket socket = null; - try { - socket = new Socket(HOST, PORT); - - try (InputStream in = socket.getInputStream(); - OutputStream out = socket.getOutputStream()) { - - String line = "Hello!"; - out.write(line.getBytes()); - out.flush(); - - byte[] data = new byte[32 * 1024]; - int readBytes = in.read(data); - - System.out.printf("Server> %s", new String(data, 0, readBytes)); - - } - - } catch (IOException e) { - e.printStackTrace(); - // exit, failed to open socket - } finally { - IoUtil.closeQuietly(socket); - } - } - - - -} diff --git a/src/main/java/arhangel/dim/lections/socket/Server.java b/src/main/java/arhangel/dim/lections/socket/Server.java deleted file mode 100644 index 09e0fed..0000000 --- a/src/main/java/arhangel/dim/lections/socket/Server.java +++ /dev/null @@ -1,48 +0,0 @@ -package arhangel.dim.lections.socket; - -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.net.ServerSocket; -import java.net.Socket; - - -/** - * Обработка подключений - */ -public class Server { - - public static final int PORT = 19000; - - public static void main(String[] args) { - - ServerSocket serverSocket = null; - try { - serverSocket = new ServerSocket(PORT); - - System.out.println("Started, waiting for connection"); - - Socket socket = serverSocket.accept(); - - System.out.println("Accepted. " + socket.getInetAddress()); - - try (InputStream in = socket.getInputStream(); - OutputStream out = socket.getOutputStream()) { - - - byte[] buf = new byte[32 * 1024]; - int readBytes = in.read(buf); - String line = new String(buf, 0, readBytes); - System.out.printf("Client>%s", line); - - out.write(line.getBytes()); - out.flush(); - } - - } catch (IOException e) { - e.printStackTrace(); - } finally { - IoUtil.closeQuietly(serverSocket); - } - } -} diff --git a/src/main/java/arhangel/dim/lections/threads/DeadLock.java b/src/main/java/arhangel/dim/lections/threads/DeadLock.java deleted file mode 100644 index c47e347..0000000 --- a/src/main/java/arhangel/dim/lections/threads/DeadLock.java +++ /dev/null @@ -1,78 +0,0 @@ -package arhangel.dim.lections.threads; - - -import java.util.concurrent.locks.Lock; -import java.util.concurrent.locks.ReentrantLock; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * - */ -public class DeadLock { - static Logger logger = LoggerFactory.getLogger(DeadLock.class); - Lock lock = new ReentrantLock(); - - public static void main(String[] args) { - - final Account a1 = new Account(1); - a1.sum = 100; - final Account a2 = new Account(2); - a2.sum = 300; - - Thread t1 = new Thread(() -> { - Account.transact(a1, a2, 10); - }, ""); - - Thread t2 = new Thread(() -> { - Account.transact(a2, a1, 20); - }, ""); - - t1.start(); - t2.start(); - } - - static class Account { - int sum; - int id; - - public Account(int id) { - this.id = id; - } - - static void transact(final Account from, final Account to, int amount) { - Account lock1; - Account lock2; - -// lock1 = from; -// lock2 = to; - - if (from.id < to.id) { - lock1 = from; - lock2 = to; - } else { - lock1 = to; - lock2 = from; - } - - synchronized (lock1) { - logger.info("Lock1({}) was acquired by thread {}. Waiting for lock2({}), " + - "lock1.id, Thread.currentThread().getName(), lock2.id"); - try { - Thread.sleep(500); - } catch (InterruptedException e) { - e.printStackTrace(); - } - - synchronized (lock2) { - logger.info("Lock2({}) was acquired by thread {}. Waiting for lock1({}), " + - "lock2.id, Thread.currentThread().getName(), lock1.id"); - from.sum -= amount; - to.sum += amount; - } - } - } - } - -} diff --git a/src/main/java/arhangel/dim/lections/threads/Monitor.java b/src/main/java/arhangel/dim/lections/threads/Monitor.java deleted file mode 100644 index 8c985c4..0000000 --- a/src/main/java/arhangel/dim/lections/threads/Monitor.java +++ /dev/null @@ -1,45 +0,0 @@ -package arhangel.dim.lections.threads; - -/** - * - */ -public class Monitor { - - private final Object lockObject = new Object(); - - private final Object anotherLockObject = new Object(); - - int counter = 0; - - public void doChange() { - synchronized (lockObject) { - counter++; - } - } - - public void doAnotherChange() { - synchronized (anotherLockObject) { - counter++; - } - } - - public static void main(String[] args) { - Monitor monitor = new Monitor(); - - new Thread(() -> { - for (int i = 0; i < 100_000; i++) { - monitor.doChange(); - } - }).start(); - - new Thread(() -> { - for (int i = 0; i < 100_000; i++) { - monitor.doAnotherChange(); - } - }).start(); - - System.out.println(monitor.counter); - } - - -} diff --git a/src/main/java/arhangel/dim/lections/threads/MyThread.java b/src/main/java/arhangel/dim/lections/threads/MyThread.java deleted file mode 100644 index c8db1e4..0000000 --- a/src/main/java/arhangel/dim/lections/threads/MyThread.java +++ /dev/null @@ -1,26 +0,0 @@ -package arhangel.dim.lections.threads; - -import java.util.concurrent.TimeUnit; - -class MyThread extends Thread { - - private String name; - - public MyThread(String name) { - this.name = name; - } - - @Override - public void run() { - System.out.println("Thread " + name + ": started"); - try { - for (int i = 0; i < 5; i++) { - System.out.println("MyThread " + name + " : " + i); - TimeUnit.SECONDS.sleep(1); - } - } catch (InterruptedException e) { - e.printStackTrace(); - } - System.out.println("MyThread: finished"); - } -} diff --git a/src/main/java/arhangel/dim/lections/threads/Pool.java b/src/main/java/arhangel/dim/lections/threads/Pool.java deleted file mode 100644 index 325f1c4..0000000 --- a/src/main/java/arhangel/dim/lections/threads/Pool.java +++ /dev/null @@ -1,63 +0,0 @@ -package arhangel.dim.lections.threads; - -import java.util.ArrayList; -import java.util.List; -import java.util.concurrent.Callable; -import java.util.concurrent.Executor; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; -import java.util.concurrent.Future; -import java.util.concurrent.TimeUnit; - -/** - * - */ -public class Pool { - - public static void main(String[] args) throws Exception { - - int cores = Runtime.getRuntime().availableProcessors(); - System.out.println("Processors available: " + cores); - ExecutorService service = Executors.newFixedThreadPool(2); - - List futures = new ArrayList<>(); - - for (int i = 0; i < 4; i++) { -// Future future = service.submit(new MyThread("t#" + i)); - Future future = service.submit(new Task(i * 2)); - futures.add(future); - } - - System.out.println("1) ========================"); - - for (Future f : futures) { - System.out.println("result: " + f.get()); - } - - System.out.println("2) ========================"); - } - - static class Task implements Callable { - - int num; - - public Task(int num) { - this.num = num; - } - - @Override - public Integer call() throws Exception { - int acc = 0; - try { - for (int i = 0; i < num; i++) { - TimeUnit.SECONDS.sleep(1); - acc += i; - } - } catch (InterruptedException e) { - e.printStackTrace(); - } - return acc; - } - } - -} diff --git a/src/main/java/arhangel/dim/lections/threads/SimpleThread.java b/src/main/java/arhangel/dim/lections/threads/SimpleThread.java deleted file mode 100644 index 141a3d5..0000000 --- a/src/main/java/arhangel/dim/lections/threads/SimpleThread.java +++ /dev/null @@ -1,61 +0,0 @@ -package arhangel.dim.lections.threads; - -import java.util.concurrent.TimeUnit; - -/** - * - */ -public class SimpleThread { - - - - public static void main(String[] args) throws Exception { - inParallel(); -// start(); -// join(); - } - - static void inParallel() throws Exception { - Thread t1 = new MyThread("inParallel"); - - // Запуск кода в новом треде - System.out.println("Starting thread"); - t1.start(); - - for (int i = 0; i < 5; i++) { - System.out.println("Main:" + i); - TimeUnit.SECONDS.sleep(2); - } - System.out.println("Main thread finished"); - } - - - static void start() { - Thread t1 = new MyThread("simpleThread"); - - // Запуск кода в новом треде - System.out.println("Starting thread"); - t1.start(); - - // А здесь? -// System.out.println("Running"); -// t1.run(); - - System.out.println("Error:"); - // Нельзя запустить поток еще раз - // Почему? - //t1.start(); - } - - static void join() throws Exception { - Thread thread = new MyThread("joinThread"); - System.out.println("Starting thread..."); - thread.start(); - System.out.println("Joining"); - //t.join(); - System.out.println("Joined"); - - - } - -} diff --git a/src/main/java/arhangel/dim/lections/threads/StopThread.java b/src/main/java/arhangel/dim/lections/threads/StopThread.java deleted file mode 100644 index 0bc5808..0000000 --- a/src/main/java/arhangel/dim/lections/threads/StopThread.java +++ /dev/null @@ -1,93 +0,0 @@ -package arhangel.dim.lections.threads; - -import java.util.Scanner; -import java.util.concurrent.TimeUnit; - -/** - * - */ -public class StopThread { - - static class FlagThread extends Thread { - private volatile boolean pleaseStop; - - @Override - public void run() { - while (!pleaseStop) { - try { - System.out.println("Thread::sleep()"); - TimeUnit.SECONDS.sleep(100); - } catch (InterruptedException e) { - Thread.currentThread().interrupt(); - } - } - } - - public void stopThread() { - System.out.println("Stopping..."); - pleaseStop = true; - } - } - - static class InterThread extends Thread { - @Override - public void run() { - while (!Thread.currentThread().isInterrupted()) { - try { - System.out.println("Thread::sleep()"); - TimeUnit.SECONDS.sleep(1); - } catch (InterruptedException e) { - e.printStackTrace(); - Thread.currentThread().interrupt(); - } - } - } - } - - static class DummyThread extends Thread { - @Override - public void run() { - while (true) { - System.out.println("q"); -// try { -// System.out.println("Thread::sleep()"); -// TimeUnit.SECONDS.sleep(1); -// } catch (InterruptedException e) { -// } - } - } - } - - public static void flagThread() { - FlagThread flagThread = new FlagThread(); - flagThread.start(); - - Scanner scanner = new Scanner(System.in); - scanner.next(); - flagThread.stopThread(); - } - - public static void interruptThread() { - Thread thread = new InterThread(); - thread.start(); - - Scanner scanner = new Scanner(System.in); - scanner.next(); - thread.interrupt(); - } - - public static void dummyThread() { - Thread thread = new DummyThread(); - thread.start(); - - Scanner scanner = new Scanner(System.in); - scanner.next(); - thread.interrupt(); - } - - public static void main(String[] args) throws Exception { - //flagThread(); - //interruptThread(); - dummyThread(); - } -} diff --git a/src/main/java/arhangel/dim/lections/threads/counting/AtomicCounter.java b/src/main/java/arhangel/dim/lections/threads/counting/AtomicCounter.java deleted file mode 100644 index fdac6db..0000000 --- a/src/main/java/arhangel/dim/lections/threads/counting/AtomicCounter.java +++ /dev/null @@ -1,16 +0,0 @@ -package arhangel.dim.lections.threads.counting; - -import java.util.concurrent.atomic.AtomicLong; - -/** - * - */ -public class AtomicCounter implements Counter { - - private AtomicLong val = new AtomicLong(0); - - @Override - public long inc() { - return val.getAndIncrement(); - } -} diff --git a/src/main/java/arhangel/dim/lections/threads/counting/Counter.java b/src/main/java/arhangel/dim/lections/threads/counting/Counter.java deleted file mode 100644 index 95b720b..0000000 --- a/src/main/java/arhangel/dim/lections/threads/counting/Counter.java +++ /dev/null @@ -1,9 +0,0 @@ -package arhangel.dim.lections.threads.counting; - -/** - * - */ -public interface Counter { - - long inc(); -} diff --git a/src/main/java/arhangel/dim/lections/threads/counting/CounterTest.java b/src/main/java/arhangel/dim/lections/threads/counting/CounterTest.java deleted file mode 100644 index 089ba4b..0000000 --- a/src/main/java/arhangel/dim/lections/threads/counting/CounterTest.java +++ /dev/null @@ -1,87 +0,0 @@ -package arhangel.dim.lections.threads.counting; - -/** - * - */ -public class CounterTest { - - static class Sequencer extends Thread { - private Counter counter; - - public Sequencer(Counter counter) { - this.counter = counter; - } - - @Override - public void run() { - for (int i = 0; i < 100_000; i++) { - counter.inc(); - } - } - } - - static class UnsafeSequencer extends Thread { - private LockCounter counter; - - public UnsafeSequencer(LockCounter counter) { - this.counter = counter; - } - - @Override - public void run() { - for (int i = 0; i < 100_000; i++) { - counter.incUnsafe(); - } - } - } - - public static void main(String[] args) throws Exception { - //testCounter(); - testSafeUnsafe(); - } - - public static void testCounter() throws Exception { - final int threadNum = 2; - //Counter counter = new SimpleCounter(); - Counter counter = new AtomicCounter(); - //LockCounter counter = new LockCounter(); - Thread[] threads = new Thread[threadNum]; - for (int i = 0; i < threadNum; i++) { - Thread thread = new Sequencer(counter); - threads[i] = thread; - thread.start(); - } - - for (Thread t : threads) { - t.join(); - } - - System.out.printf("Threads: %d\nCounter: %d", threadNum, counter.inc()); - } - - public static void testSafeUnsafe() throws Exception { - - final int threadNum = 2; - //Counter counter = new SimpleCounter(); - //Counter counter = new AtomicCounter(); - LockCounter counter = new LockCounter(); - Thread[] threads = new Thread[threadNum]; - for (int i = 0; i < threadNum; i++) { - Thread thread = new Sequencer(counter); - threads[i] = thread; - thread.start(); - } - Thread unsafe = new UnsafeSequencer(counter); - unsafe.start(); - - for (Thread t : threads) { - t.join(); - } - - unsafe.join(); - - System.out.printf("Threads: %d\nCounter: %d", threadNum, counter.inc()); - } - - -} diff --git a/src/main/java/arhangel/dim/lections/threads/counting/LockCounter.java b/src/main/java/arhangel/dim/lections/threads/counting/LockCounter.java deleted file mode 100644 index 608d5ec..0000000 --- a/src/main/java/arhangel/dim/lections/threads/counting/LockCounter.java +++ /dev/null @@ -1,19 +0,0 @@ -package arhangel.dim.lections.threads.counting; - -/** - * реализация счетчика через лок - */ -public class LockCounter implements Counter { - - private long counter; - - public synchronized long inc() { - return counter++; - } - - public long incUnsafe() { - return counter++; - } - - -} diff --git a/src/main/java/arhangel/dim/lections/threads/counting/SimpleCounter.java b/src/main/java/arhangel/dim/lections/threads/counting/SimpleCounter.java deleted file mode 100644 index 03c221b..0000000 --- a/src/main/java/arhangel/dim/lections/threads/counting/SimpleCounter.java +++ /dev/null @@ -1,13 +0,0 @@ -package arhangel.dim.lections.threads.counting; - -/** - * - */ -public class SimpleCounter implements Counter { - private long val; - - public long inc() { - return val++; - } - -} diff --git a/src/main/java/arhangel/dim/lections/threads/queueu/BlockingQueue.java b/src/main/java/arhangel/dim/lections/threads/queueu/BlockingQueue.java deleted file mode 100644 index 27eb325..0000000 --- a/src/main/java/arhangel/dim/lections/threads/queueu/BlockingQueue.java +++ /dev/null @@ -1,19 +0,0 @@ -package arhangel.dim.lections.threads.queueu; - -/** - * - */ -public interface BlockingQueue { - - /** - * - * @param e the element to add - */ - void put(E elem) throws InterruptedException; - - /** - * - * @return the head element - */ - E take() throws InterruptedException; -} diff --git a/src/main/java/arhangel/dim/lections/threads/queueu/ListBlockingQueue.java b/src/main/java/arhangel/dim/lections/threads/queueu/ListBlockingQueue.java deleted file mode 100644 index 6b8b083..0000000 --- a/src/main/java/arhangel/dim/lections/threads/queueu/ListBlockingQueue.java +++ /dev/null @@ -1,50 +0,0 @@ -package arhangel.dim.lections.threads.queueu; - -import java.util.LinkedList; - -/** - * - */ -public class ListBlockingQueue implements BlockingQueue { - - public static final int DEFAULT_CAPACITY = 10; - - private int capacity; - private LinkedList list = new LinkedList<>(); - - public ListBlockingQueue() { - capacity = DEFAULT_CAPACITY; - } - - public ListBlockingQueue(int capacity) { - this.capacity = capacity; - } - - @Override - public void put(E elem) throws InterruptedException { - - /* - Внутри критической секции пытаемся поместить элемент в очередь - Если очередь полная isFull==true то блокируемся на wait() пока условие не будет выполнено - */ - } - - @Override - public E take() throws InterruptedException { - - /* - Внутри критической секции пытаемся достать элемент из очереди - Если очередь пустая isEmpty == true то блокируемся на wait() пока условие не будет выполнено - */ - return null; - } - - private boolean isFull() { - return list.size() == capacity; - } - - private boolean isEmpty() { - return list.size() == 0; - } - -} diff --git a/src/main/java/arhangel/dim/lections/threads/queueu/ProducerConsumer.java b/src/main/java/arhangel/dim/lections/threads/queueu/ProducerConsumer.java deleted file mode 100644 index 1b60c9c..0000000 --- a/src/main/java/arhangel/dim/lections/threads/queueu/ProducerConsumer.java +++ /dev/null @@ -1,73 +0,0 @@ -package arhangel.dim.lections.threads.queueu; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -public class ProducerConsumer { - - static Logger log = LoggerFactory.getLogger(ProducerConsumer.class); - - static boolean isReady = false; - - static class Producer extends Thread { - private final Object lock; - - public Producer(Object lock) { - this.lock = lock; - } - - @Override - public void run() { - log.info("[PRODUCER] Preparing data..."); - try { - sleep(2000); - } catch (InterruptedException e) { - e.printStackTrace(); - } - log.info("[PRODUCER] Data prepared. Notify All!"); - - isReady = true; - synchronized (lock) { - lock.notifyAll(); - } - } - - } - - static class Consumer extends Thread { - private final Object lock; - - public Consumer(Object lock) { - this.lock = lock; - } - - @Override - public void run() { - - synchronized (lock) { - log.info("[CONSUMER] Waiting for data..."); - - // Если данные еще не готовы - while (!isReady) { - try { - // ждем - lock.wait(); - // как только пробудились, заново проверяем состояние данных - // если они не готовы (или кто-то уже их поменял), то снова ждем - } catch (InterruptedException e) { - e.printStackTrace(); - } - } - - log.info("[CONSUMER] Data received"); - } - } - - } - - public static void main(String[] args) { - Object lock = new Object(); - new Consumer(lock).start(); - new Producer(lock).start(); - } -} diff --git a/src/main/java/arhangel/dim/server/CommandHandler.java b/src/main/java/arhangel/dim/server/CommandHandler.java new file mode 100644 index 0000000..1398c29 --- /dev/null +++ b/src/main/java/arhangel/dim/server/CommandHandler.java @@ -0,0 +1,79 @@ +package arhangel.dim.server; + +import arhangel.dim.core.authorization.Authorize; +import arhangel.dim.core.commands.Command; +import arhangel.dim.core.message.AnswerMessage; +import arhangel.dim.core.message.Message; +import arhangel.dim.core.message.Protocol; +import arhangel.dim.core.message.SerializationProtocol; +import arhangel.dim.core.session.Session; +import arhangel.dim.core.session.SessionManager; +import arhangel.dim.core.store.DataStore; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.InputStream; +import java.io.OutputStream; +import java.util.Map; + +/** + * Обработчик команд, поступающих от определённого клиента + */ +public class CommandHandler implements Runnable { + /** + * Потоки для общения с клиентом + */ + private DataInputStream reader; + private DataOutputStream writer; + + /** + * Список всех баз данных, требуемых для работы + */ + private DataStore dataStore; + + /** + * Список сессий. + */ + private SessionManager sessionManager; + + public CommandHandler(InputStream reader, OutputStream writer, DataStore dataStore, SessionManager sessionManager) { + this.sessionManager = sessionManager; + this.reader = new DataInputStream(reader); + this.writer = new DataOutputStream(writer); + this.dataStore = dataStore; + } + + @Override + public void run() { + try { + Map commands = dataStore.getCommandsStore(); + Authorize service = new Authorize(dataStore.getUserStore()); + Session session = new Session(reader, writer, service, dataStore, sessionManager); + sessionManager.addSession(session); + Protocol answerProtocol = new SerializationProtocol<>(); + Protocol readProtocol = new SerializationProtocol<>(); + while (true) { + byte[] readData = new byte[1024 * 64]; + reader.read(readData); + Message received = readProtocol.decode(readData); + String command = received.getMessage(); + if (command.equals("/exit")) { + break; + } + String[] parsedCommand = command.split("\\s+"); + Command commandClass = commands.get(parsedCommand[0]); + if (commandClass == null) { + String str = "Wrong command"; + AnswerMessage answer = new AnswerMessage(str , AnswerMessage.Value.ERROR); + writer.write(answerProtocol.encode(answer)); + continue; + } + commandClass.run(parsedCommand, session); + + } + + } catch (Exception e) { + System.err.println("Exception in reading command " + e.toString()); + } + } +} diff --git a/src/main/java/arhangel/dim/server/MultiThreadServer.java b/src/main/java/arhangel/dim/server/MultiThreadServer.java new file mode 100644 index 0000000..635ea23 --- /dev/null +++ b/src/main/java/arhangel/dim/server/MultiThreadServer.java @@ -0,0 +1,112 @@ +package arhangel.dim.server; + +import arhangel.dim.container.Container; +import arhangel.dim.container.beans.WebConnection; +import arhangel.dim.core.store.DataBaseUserStore; +import arhangel.dim.core.jdbc.DataBaseOrganizer; +import arhangel.dim.core.store.DataBaseChatStore; +import arhangel.dim.core.session.SessionManager; +import arhangel.dim.core.store.DataStore; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.net.ServerSocket; +import java.net.Socket; +import java.net.SocketException; +import java.sql.Connection; +import java.sql.DriverManager; +import java.util.ArrayList; +import java.util.List; + +/** + * Многопоточный сервер + */ +public class MultiThreadServer implements Runnable, AutoCloseable { + + private int serverPort; + private ServerSocket serverSocket; + private boolean isStopped; + private Connection connection; + private int maxConnection = 16; + + /** + * Нити, для работы с отдельным клиентом + */ + private List clientThreads; + + private DataStore dataStore; + + /** + * Все сессии клиентов + */ + private SessionManager sessionManager; + + + public MultiThreadServer() { + try { + Container container = new Container("C:\\Users\\Дмитрий\\Documents\\technotrack\\java\\messenger\\config.xml"); + WebConnection portAndHost = (WebConnection)container.getByClass("arhangel.dim.container.beans.WebConnection"); + this.serverPort = portAndHost.getPort(); + isStopped = false; + clientThreads = new ArrayList<>(); + DataBaseOrganizer.reorganizeDataBase(null); + connection = DriverManager.getConnection("jdbc:postgresql://178.62.140.149:5432/Kud8", + "trackuser", "trackuser"); + dataStore = new DataStore(new DataBaseUserStore(connection), new DataBaseChatStore(connection), connection); + sessionManager = new SessionManager(); + } catch (Exception e) { + System.err.println("Server: exception caught " + e.toString()); + } + } + + @Override + public void run() { + try { + serverSocket = new ServerSocket(serverPort); + while (!isStopped()) { + if (clientThreads.size() >= maxConnection) { + System.err.println("Error: too much connections"); + return; + } + Socket clientSocket = serverSocket.accept(); + System.out.println("Client connected."); + DataInputStream in = new DataInputStream(clientSocket.getInputStream()); + DataOutputStream out = new DataOutputStream(clientSocket.getOutputStream()); + Thread thread = new Thread(new CommandHandler(in, out, dataStore, sessionManager)); + clientThreads.add(thread); + thread.start(); + } + } catch (SocketException e) { + if (!e.getMessage().equals("socket closed")) { + System.err.println("Server: exception caught: " + e.toString()); + } + } catch (Exception e) { + System.err.println("Server: exception caught: " + e.toString()); + } finally { + close(); + } + } + + public synchronized boolean isStopped() { + return isStopped; + } + + private synchronized void stop() { + isStopped = true; + } + + @Override + public void close() { + stop(); + try { + serverSocket.close(); + dataStore.close(); + connection.close(); + for (Thread it : clientThreads) { + it.join(); + } + } catch (Exception e) { + System.err.println("Server: error in closing: " + e.toString()); + } + } +} diff --git a/src/main/java/arhangel/dim/server/Server.java b/src/main/java/arhangel/dim/server/Server.java deleted file mode 100644 index 92452b8..0000000 --- a/src/main/java/arhangel/dim/server/Server.java +++ /dev/null @@ -1,21 +0,0 @@ -package arhangel.dim.server; - -import arhangel.dim.core.net.Protocol; - -/** - * Основной класс для сервера сообщений - */ -public class Server { - - public static final int DEFAULT_MAX_CONNECT = 16; - - // Засетить из конфига - private int port; - private Protocol protocol; - private int maxConnection = DEFAULT_MAX_CONNECT; - - public void stop() { - // TODO: закрыть все сетевые подключения, остановить потоки-обработчики, закрыть ресурсы, если есть. - } - -} diff --git a/src/main/java/arhangel/dim/server/ServerMain.java b/src/main/java/arhangel/dim/server/ServerMain.java new file mode 100644 index 0000000..ab1d3eb --- /dev/null +++ b/src/main/java/arhangel/dim/server/ServerMain.java @@ -0,0 +1,27 @@ +package arhangel.dim.server; + +import java.io.BufferedReader; +import java.io.InputStreamReader; + +public class ServerMain { + + public static void main(String[] args) { + try { + MultiThreadServer server = new MultiThreadServer(); + Thread serverThread = new Thread(server); + serverThread.start(); + System.out.println("Server started, type /stop to stop it"); + BufferedReader reader = new BufferedReader(new InputStreamReader(System.in)); + while (true) { + String line = reader.readLine(); + if (line.equals("/stop")) { + server.close(); + break; + } + } + serverThread.join(); + } catch (Exception e) { + System.err.println("ServerMain: exception caught: " + e.toString()); + } + } +} diff --git a/src/test/java/arhangel/dim/container/ContainerTest.java b/src/test/java/arhangel/dim/container/ContainerTest.java index 3152f67..6f696de 100644 --- a/src/test/java/arhangel/dim/container/ContainerTest.java +++ b/src/test/java/arhangel/dim/container/ContainerTest.java @@ -1,4 +1,4 @@ -package arhangel.dim.container; +/*package arhangel.dim.container; import org.junit.BeforeClass; import org.junit.Test; @@ -9,9 +9,7 @@ import arhangel.dim.container.beans.Engine; import arhangel.dim.container.beans.Gear; -/** - * - */ + public class ContainerTest { private static Container container; @@ -55,3 +53,4 @@ public void testGetByClass() throws Exception { Assert.assertEquals(expectedCar, car); } } +*/ \ No newline at end of file diff --git a/src/test/java/arhangel/dim/core/net/BinaryProtocolTest.java b/src/test/java/arhangel/dim/core/net/BinaryProtocolTest.java deleted file mode 100644 index 32d0988..0000000 --- a/src/test/java/arhangel/dim/core/net/BinaryProtocolTest.java +++ /dev/null @@ -1,30 +0,0 @@ -package arhangel.dim.core.net; - -import org.junit.Assert; -import org.junit.Test; - -import arhangel.dim.core.messages.Message; -import arhangel.dim.core.messages.TextMessage; -import arhangel.dim.core.messages.Type; - -/** - * - */ -public class BinaryProtocolTest { - - @Test - public void decode() throws Exception { - Protocol protocol = new StringProtocol(); - TextMessage message = new TextMessage(); - message.setText("Hello"); - message.setSenderId(1L); - message.setType(Type.MSG_TEXT); - - byte[] data = protocol.encode(message); - Assert.assertTrue(data != null); - - Message other = protocol.decode(data); - Assert.assertEquals(message, other); - - } -} \ No newline at end of file