Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion client.xml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
<bean id="protocol" class="arhangel.dim.core.net.StringProtocol"/>

<bean id="client" class="arhangel.dim.client.Client">
<property name="port" val="19000"/>
<property name="port" val="8000"/>
<property name="host" val="localhost"/>
<property name="protocol" ref="protocol"/>
</bean>
Expand Down
5 changes: 5 additions & 0 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,11 @@
<artifactId>postgresql</artifactId>
<version>9.4-1204-jdbc42</version>
</dependency>
<dependency>
<groupId>org.postgresql</groupId>
<artifactId>postgresql</artifactId>
<version>9.4-1204-jdbc42</version>
</dependency>
</dependencies>


Expand Down
112 changes: 97 additions & 15 deletions src/main/java/arhangel/dim/client/Client.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,26 @@
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Scanner;
import java.util.stream.Collectors;

import arhangel.dim.core.messages.CreateChatMessage;
import arhangel.dim.core.messages.InfoMessage;
import arhangel.dim.core.messages.ListChatMessage;
import arhangel.dim.core.messages.ListChatResultMessage;
import arhangel.dim.core.messages.LoginMessage;
import arhangel.dim.core.messages.StatusMessage;
import arhangel.dim.server.Server;
import com.sun.org.apache.xpath.internal.SourceTree;
import com.sun.scenario.effect.impl.sw.sse.SSEBlend_SRC_OUTPeer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import arhangel.dim.container.Container;
import arhangel.dim.container.InvalidConfigurationException;
import arhangel.dim.container.exceptions.InvalidConfigurationException;
import arhangel.dim.core.messages.Message;
import arhangel.dim.core.messages.TextMessage;
import arhangel.dim.core.messages.Type;
Expand All @@ -26,13 +38,12 @@ public class Client implements ConnectionHandler {

/**
* Механизм логирования позволяет более гибко управлять записью данных в лог (консоль, файл и тд)
* */
*/
static Logger log = LoggerFactory.getLogger(Client.class);

/**
* Протокол, хост и порт инициализируются из конфига
*
* */
*/
private Protocol protocol;
private int port;
private String host;
Expand All @@ -41,13 +52,15 @@ public class Client implements ConnectionHandler {
* Тред "слушает" сокет на наличие входящих сообщений от сервера
*/
private Thread socketThread;

private Socket socket;
/**
* С каждым сокетом связано 2 канала in/out
*/
private InputStream in;
private OutputStream out;

private Long userId;

public Protocol getProtocol() {
return protocol;
}
Expand All @@ -73,6 +86,8 @@ public void setHost(String host) {
}

public void initSocket() throws IOException {
System.out.println(host);
System.out.println(port);
Socket socket = new Socket(host, port);
in = socket.getInputStream();
out = socket.getOutputStream();
Expand All @@ -91,6 +106,7 @@ public void initSocket() throws IOException {

// По сети передается поток байт, его нужно раскодировать с помощью протокола
Message msg = protocol.decode(Arrays.copyOf(buf, read));
log.info("Decoded message:" + msg);
onMessage(msg);
}
} catch (Exception e) {
Expand All @@ -110,6 +126,37 @@ public void initSocket() throws IOException {
@Override
public void onMessage(Message msg) {
log.info("Message received: {}", msg);

switch (msg.getType()) {
case MSG_STATUS:
StatusMessage msgStatus = (StatusMessage) msg;
System.out.println(msgStatus.getStatus());
break;
case MSG_CHAT_LIST_RESULT:
ListChatResultMessage msgChatListResult = (ListChatResultMessage) msg;
if (msgChatListResult.getChatIds().size() == 0) {
System.out.println("You have no chats yet.");
} else {
System.out.println("Your chats: " + String.join(",", msgChatListResult.getChatIds().stream()
.map(Object::toString)
.collect(Collectors.toList())));
}
break;
case MSG_INFO:
InfoMessage infoMessage = (InfoMessage) msg;
StringBuilder sb = new StringBuilder();
sb.append("Info. User: ").append(infoMessage.getUserId())
.append(".");
System.out.println(sb.toString());
break;
case MSG_TEXT:
TextMessage textMessage = (TextMessage) msg;
System.out.println(msg);
break;
default:
log.error("unsupported type of message");
break;
}
}

/**
Expand All @@ -122,19 +169,48 @@ public void processInput(String line) throws IOException, ProtocolException {
String cmdType = tokens[0];
switch (cmdType) {
case "/login":
// TODO: реализация
if (tokens.length != 3) {
log.error("Invalid args number");
break;
}
LoginMessage loginMessage = new LoginMessage();
loginMessage.setLogin(tokens[1]);
loginMessage.setPassword(tokens[2]);
send(loginMessage);
break;
case "/help":
// TODO: реализация
break;
case "/text":
// FIXME: пример реализации для простого текстового сообщения
if (tokens.length != 3) {
log.error("Invalid args number");
break;
}
TextMessage sendMessage = new TextMessage();
sendMessage.setType(Type.MSG_TEXT);
sendMessage.setText(tokens[1]);
sendMessage.setChatId(Long.parseLong(tokens[1]));
sendMessage.setText(tokens[2]);
send(sendMessage);
break;
// TODO: implement another types from wiki
case "/info":
InfoMessage infoMessage = new InfoMessage();
if (tokens.length == 1) {
infoMessage.setArg(false);
} else {
infoMessage.setArg(true);
infoMessage.setUserId(Long.parseLong(tokens[1]));
}
send(infoMessage);
break;
case "/chat_create":
CreateChatMessage createChatMessage = new CreateChatMessage();
String[] userIdsStr = tokens[1].split(",");
List<Long> userIds = new ArrayList<Long>();
for (int i = 0; i < userIdsStr.length; ++i) {
userIds.add(Long.parseLong(userIdsStr[i]));
}
createChatMessage.setUsersIds(userIds);
send(createChatMessage);
break;

default:
log.error("Invalid input: " + line);
Expand All @@ -146,14 +222,20 @@ public void processInput(String line) throws IOException, ProtocolException {
*/
@Override
public void send(Message msg) throws IOException, ProtocolException {
log.info(msg.toString());
log.info("send to server: " + msg.toString());
out.write(protocol.encode(msg));
out.flush(); // принудительно проталкиваем буфер с данными
out.flush();
}

@Override
public void close() {
// TODO: написать реализацию. Закройте ресурсы и остановите поток-слушатель
public void close() throws IOException {
log.error("Closing socket...");
if (!socketThread.isInterrupted()) {
socketThread.interrupt();
}
if (!socket.isClosed()) {
socket.close();
}
}

public static void main(String[] args) throws Exception {
Expand All @@ -175,7 +257,7 @@ public static void main(String[] args) throws Exception {
System.out.println("$");
while (true) {
String input = scanner.nextLine();
if ("q".equals(input)) {
if ("exit".equals(input)) {
return;
}
try {
Expand Down
98 changes: 93 additions & 5 deletions src/main/java/arhangel/dim/container/BeanGraph.java
Original file line number Diff line number Diff line change
@@ -1,22 +1,33 @@
package arhangel.dim.container;

import java.util.HashMap;
import arhangel.dim.container.exceptions.CycleReferenceException;

import java.util.List;
import java.util.ArrayList;
import java.util.Map;
import java.util.HashMap;

import static java.util.Collections.reverse;

/**
*
*/
public class BeanGraph {
// Граф представлен в виде списка связности для каждой вершины
private Map<BeanVertex, List<BeanVertex>> vertices = new HashMap<>();
private Map<String, BeanVertex> vertexByName = new HashMap<>();

/**
* Добавить вершину в граф
* @param value - объект, привязанный к вершине
*/
public BeanVertex addVertex(Bean value) {
return null;
BeanVertex newVertex = new BeanVertex(value);

vertices.put(newVertex, new ArrayList<BeanVertex>());
vertexByName.put(value.getName(), newVertex);

return newVertex;
}

/**
Expand All @@ -25,26 +36,103 @@ public BeanVertex addVertex(Bean value) {
* @param to в какую вершину
*/
public void addEdge(BeanVertex from ,BeanVertex to) {
List<BeanVertex> incidentVertices = vertices.get(from);
incidentVertices.add(to);
}

public BeanGraph() {}

public BeanGraph(List<Bean> beans) {
// adding all the vertices
for (Bean bean : beans) {
addVertex(bean);
}

// adding edges between vertices
for (Bean bean : beans) {
BeanVertex from = vertexByName.get(bean.getName());

HashMap<String, Property> properties = (HashMap<String, Property>) bean.getProperties();
for (Property property : properties.values()) {

if (property.getType() == ValueType.VAL) {
continue;
}

BeanVertex to = vertexByName.get(property.getName());
addEdge(from, to);
}
}
}

/**
* Проверяем, связаны ли вершины
*/
public boolean isConnected(BeanVertex v1, BeanVertex v2) {
return false;
List<BeanVertex> incidentVertices = vertices.get(v1);
return incidentVertices.contains(v2);
}

/**
* Получить список вершин, с которыми связана vertex
*/
public List<BeanVertex> getLinked(BeanVertex vertex) {
return null;
return vertices.get(vertex);
}

/**
* Количество вершин в графе
*/
public int size() {
return 0;
return vertices.size();
}

private enum VertexType {
NOT_PROCESSED, // dfs в вершину еще не заходил
STARTED_PROCESSING, // dfs зашел в вершину
FINISHED_PROCESSING // dfs вышел из вершины
}

/**
* Проверить граф на наличие циклов
*/
private boolean isCircle(BeanVertex vertex, List<BeanVertex> sortedVertices,
Map<BeanVertex, VertexType> usedVertices) {
usedVertices.put(vertex, VertexType.STARTED_PROCESSING);

for (BeanVertex incidentVertex : vertices.get(vertex)) {
if (usedVertices.get(incidentVertex).equals(VertexType.NOT_PROCESSED)) {
isCircle(incidentVertex, sortedVertices, usedVertices);
} else if (usedVertices.get(incidentVertex).equals(VertexType.STARTED_PROCESSING)) {
return true;
}
}
sortedVertices.add(vertex);
usedVertices.put(vertex, VertexType.FINISHED_PROCESSING);
return false;
}

/**
* Отсортировать вершины графа в топологическом порядке
*/
public List<BeanVertex> sortTopologically() throws CycleReferenceException {
Map<BeanVertex, VertexType> usedVertices = new HashMap<>();
for (BeanVertex vertex : vertices.keySet()) {
usedVertices.put(vertex, VertexType.NOT_PROCESSED);
}
List<BeanVertex> sortedVertices = new ArrayList<>();

for (BeanVertex vertex : vertices.keySet()) {
if (!usedVertices.get(vertex).equals(0)) {
continue;
}

boolean foundCircle = isCircle(vertex, sortedVertices, usedVertices);
if (foundCircle) {
throw new CycleReferenceException("circle reference found");
}

}
return sortedVertices;
}
}
Loading