From 95fa5a3c3fe9bfde4da58f95114b4b814b61f05e Mon Sep 17 00:00:00 2001 From: "marcins78@gmail.com" Date: Mon, 12 Sep 2011 15:18:45 +0000 Subject: [PATCH] Adding chat to the server. --- .../java/com/gempukku/lotro/GameEvent.java | 25 ++++--- .../lotro/GatheringChatRoomListener.java | 22 ++++++ ...heringParticipantCommunicationChannel.java | 4 + .../com/gempukku/lotro/chat/ChatMessage.java | 27 +++++++ .../com/gempukku/lotro/chat/ChatRoom.java | 37 +++++++++ .../gempukku/lotro/chat/ChatRoomListener.java | 5 ++ .../gempukku/lotro/chat/ChatRoomMediator.java | 36 +++++++++ .../com/gempukku/lotro/chat/ChatServer.java | 61 +++++++++++++++ .../gempukku/lotro/server/ServerResource.java | 75 +++++++++++++++++++ 9 files changed, 280 insertions(+), 12 deletions(-) create mode 100644 gemp-lotr/gemp-lotr-server/src/main/java/com/gempukku/lotro/GatheringChatRoomListener.java create mode 100644 gemp-lotr/gemp-lotr-server/src/main/java/com/gempukku/lotro/chat/ChatMessage.java create mode 100644 gemp-lotr/gemp-lotr-server/src/main/java/com/gempukku/lotro/chat/ChatRoom.java create mode 100644 gemp-lotr/gemp-lotr-server/src/main/java/com/gempukku/lotro/chat/ChatRoomListener.java create mode 100644 gemp-lotr/gemp-lotr-server/src/main/java/com/gempukku/lotro/chat/ChatRoomMediator.java create mode 100644 gemp-lotr/gemp-lotr-server/src/main/java/com/gempukku/lotro/chat/ChatServer.java diff --git a/gemp-lotr/gemp-lotr-server/src/main/java/com/gempukku/lotro/GameEvent.java b/gemp-lotr/gemp-lotr-server/src/main/java/com/gempukku/lotro/GameEvent.java index 2e8713737..963b243ff 100644 --- a/gemp-lotr/gemp-lotr-server/src/main/java/com/gempukku/lotro/GameEvent.java +++ b/gemp-lotr/gemp-lotr-server/src/main/java/com/gempukku/lotro/GameEvent.java @@ -11,13 +11,14 @@ import java.util.List; public class GameEvent { public enum Type { PARTICIPANT, GAME_PHASE_CHANGE, TURN_CHANGE, PLAYER_POSITION, TWILIGHT_POOL, - PUT_CARD_IN_PLAY, MOVE_CARD_IN_PLAY, REMOVE_CARD_FROM_PLAY, ATTACH_CARD, + PUT_CARD_IN_PLAY, MOVE_CARD_IN_PLAY, REMOVE_CARD_FROM_PLAY, ADD_ASSIGNMENT, REMOVE_ASSIGNMENT, START_SKIRMISH, END_SKIRMISH, - ADD_TOKENS, REMOVE_TOKENS + ADD_TOKENS, REMOVE_TOKENS, + MESSAGE } - private String _warning; + private String _message; private Type _type; private Zone _zone; private String _participantId; @@ -66,6 +67,15 @@ public class GameEvent { return this; } + public String getMessage() { + return _message; + } + + public GameEvent message(String message) { + _message = message; + return this; + } + public Integer getCount() { return _count; } @@ -84,15 +94,6 @@ public class GameEvent { return this; } - public String getWarning() { - return _warning; - } - - public GameEvent warning(String warning) { - _warning = warning; - return this; - } - public String getParticipantId() { return _participantId; } diff --git a/gemp-lotr/gemp-lotr-server/src/main/java/com/gempukku/lotro/GatheringChatRoomListener.java b/gemp-lotr/gemp-lotr-server/src/main/java/com/gempukku/lotro/GatheringChatRoomListener.java new file mode 100644 index 000000000..44f969e1d --- /dev/null +++ b/gemp-lotr/gemp-lotr-server/src/main/java/com/gempukku/lotro/GatheringChatRoomListener.java @@ -0,0 +1,22 @@ +package com.gempukku.lotro; + +import com.gempukku.lotro.chat.ChatMessage; +import com.gempukku.lotro.chat.ChatRoomListener; + +import java.util.LinkedList; +import java.util.List; + +public class GatheringChatRoomListener implements ChatRoomListener { + private List _messages = new LinkedList(); + + @Override + public void messageReceived(ChatMessage message) { + _messages.add(message); + } + + public List consumeMessages() { + List messages = _messages; + _messages = new LinkedList(); + return messages; + } +} diff --git a/gemp-lotr/gemp-lotr-server/src/main/java/com/gempukku/lotro/GatheringParticipantCommunicationChannel.java b/gemp-lotr/gemp-lotr-server/src/main/java/com/gempukku/lotro/GatheringParticipantCommunicationChannel.java index ec2e78c13..53dae07ad 100644 --- a/gemp-lotr/gemp-lotr-server/src/main/java/com/gempukku/lotro/GatheringParticipantCommunicationChannel.java +++ b/gemp-lotr/gemp-lotr-server/src/main/java/com/gempukku/lotro/GatheringParticipantCommunicationChannel.java @@ -98,6 +98,10 @@ public class GatheringParticipantCommunicationChannel implements GameStateListen _events.add(new GameEvent(REMOVE_TOKENS).card(card).token(token).count(count)); } + public void sendMessage(String message) { + _events.add(new GameEvent(MESSAGE).message(message)); + } + public List consumeGameEvents() { List result = _events; _events = new LinkedList(); diff --git a/gemp-lotr/gemp-lotr-server/src/main/java/com/gempukku/lotro/chat/ChatMessage.java b/gemp-lotr/gemp-lotr-server/src/main/java/com/gempukku/lotro/chat/ChatMessage.java new file mode 100644 index 000000000..e45f21b5e --- /dev/null +++ b/gemp-lotr/gemp-lotr-server/src/main/java/com/gempukku/lotro/chat/ChatMessage.java @@ -0,0 +1,27 @@ +package com.gempukku.lotro.chat; + +import java.util.Date; + +public class ChatMessage { + private Date _when; + private String _from; + private String _message; + + public ChatMessage(Date when, String from, String message) { + _when = when; + _from = from; + _message = message; + } + + public String getFrom() { + return _from; + } + + public String getMessage() { + return _message; + } + + public Date getWhen() { + return _when; + } +} diff --git a/gemp-lotr/gemp-lotr-server/src/main/java/com/gempukku/lotro/chat/ChatRoom.java b/gemp-lotr/gemp-lotr-server/src/main/java/com/gempukku/lotro/chat/ChatRoom.java new file mode 100644 index 000000000..ce026a4da --- /dev/null +++ b/gemp-lotr/gemp-lotr-server/src/main/java/com/gempukku/lotro/chat/ChatRoom.java @@ -0,0 +1,37 @@ +package com.gempukku.lotro.chat; + +import java.util.Date; +import java.util.HashMap; +import java.util.LinkedList; +import java.util.Map; + +public class ChatRoom { + private int _maxMessageCount = 10; + private LinkedList _lastMessages = new LinkedList(); + private Map _chatRoomListeners = new HashMap(); + + public void postMessage(String from, String message) { + ChatMessage chatMessage = new ChatMessage(new Date(), from, message); + _lastMessages.add(chatMessage); + shrinkLastMessages(); + for (Map.Entry listeners : _chatRoomListeners.entrySet()) + if (!listeners.getKey().equals(from)) + listeners.getValue().messageReceived(chatMessage); + } + + public void joinChatRoom(String playerId, ChatRoomListener listener) { + _chatRoomListeners.put(playerId, listener); + for (ChatMessage lastMessage : _lastMessages) + listener.messageReceived(lastMessage); + } + + public void partChatRoom(String playerId) { + _chatRoomListeners.remove(playerId); + } + + private void shrinkLastMessages() { + while (_lastMessages.size() > _maxMessageCount) { + _lastMessages.removeFirst(); + } + } +} diff --git a/gemp-lotr/gemp-lotr-server/src/main/java/com/gempukku/lotro/chat/ChatRoomListener.java b/gemp-lotr/gemp-lotr-server/src/main/java/com/gempukku/lotro/chat/ChatRoomListener.java new file mode 100644 index 000000000..e6e0ccd8f --- /dev/null +++ b/gemp-lotr/gemp-lotr-server/src/main/java/com/gempukku/lotro/chat/ChatRoomListener.java @@ -0,0 +1,5 @@ +package com.gempukku.lotro.chat; + +public interface ChatRoomListener { + public void messageReceived(ChatMessage message); +} diff --git a/gemp-lotr/gemp-lotr-server/src/main/java/com/gempukku/lotro/chat/ChatRoomMediator.java b/gemp-lotr/gemp-lotr-server/src/main/java/com/gempukku/lotro/chat/ChatRoomMediator.java new file mode 100644 index 000000000..f06278e35 --- /dev/null +++ b/gemp-lotr/gemp-lotr-server/src/main/java/com/gempukku/lotro/chat/ChatRoomMediator.java @@ -0,0 +1,36 @@ +package com.gempukku.lotro.chat; + +import com.gempukku.lotro.GatheringChatRoomListener; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +public class ChatRoomMediator { + private ChatRoom _chatRoom = new ChatRoom(); + + private Map _listeners = new HashMap(); + + public synchronized List joinUser(String playerId) { + GatheringChatRoomListener value = new GatheringChatRoomListener(); + _listeners.put(playerId, value); + _chatRoom.joinChatRoom(playerId, value); + return value.consumeMessages(); + } + + public synchronized List getPendingMessages(String playerId) { + GatheringChatRoomListener gatheringChatRoomListener = _listeners.get(playerId); + if (gatheringChatRoomListener == null) + return null; + return gatheringChatRoomListener.consumeMessages(); + } + + public synchronized void partUser(String playerId) { + _chatRoom.partChatRoom(playerId); + _listeners.remove(playerId); + } + + public synchronized void sendMessage(String playerId, String message) { + _chatRoom.postMessage(playerId, message); + } +} diff --git a/gemp-lotr/gemp-lotr-server/src/main/java/com/gempukku/lotro/chat/ChatServer.java b/gemp-lotr/gemp-lotr-server/src/main/java/com/gempukku/lotro/chat/ChatServer.java new file mode 100644 index 000000000..094e6b4b0 --- /dev/null +++ b/gemp-lotr/gemp-lotr-server/src/main/java/com/gempukku/lotro/chat/ChatServer.java @@ -0,0 +1,61 @@ +package com.gempukku.lotro.chat; + +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +public class ChatServer { + private Map _chatRooms = new ConcurrentHashMap(); + + private boolean _started; + private CleaningTask _cleaningTask; + + public void createChatRoom(String name) { + _chatRooms.put(name, new ChatRoomMediator()); + } + + public ChatRoomMediator getChatRoom(String name) { + return _chatRooms.get(name); + } + + public void destroyChatRoom(String name) { + _chatRooms.remove(name); + } + + public synchronized void startServer() { + if (!_started) { + _cleaningTask = new CleaningTask(); + new Thread(_cleaningTask).start(); + _started = true; + } + } + + public synchronized void stopServer() { + if (_started) { + _cleaningTask.stop(); + _started = false; + } + } + + private void cleanup() { + // TODO cleanup server + } + + private class CleaningTask implements Runnable { + private boolean _running = true; + + public void run() { + while (_running) { + cleanup(); + try { + Thread.sleep(100); + } catch (InterruptedException e) { + // Ignore + } + } + } + + public void stop() { + _running = false; + } + } +} diff --git a/gemp-lotr/gemp-lotr-web/src/main/java/com/gempukku/lotro/server/ServerResource.java b/gemp-lotr/gemp-lotr-web/src/main/java/com/gempukku/lotro/server/ServerResource.java index f3c7ff4ea..a9d3bc05c 100644 --- a/gemp-lotr/gemp-lotr-web/src/main/java/com/gempukku/lotro/server/ServerResource.java +++ b/gemp-lotr/gemp-lotr-web/src/main/java/com/gempukku/lotro/server/ServerResource.java @@ -4,6 +4,9 @@ import com.gempukku.lotro.GameEvent; import com.gempukku.lotro.LotroGameMediator; import com.gempukku.lotro.LotroGameParticipant; import com.gempukku.lotro.LotroServer; +import com.gempukku.lotro.chat.ChatMessage; +import com.gempukku.lotro.chat.ChatRoomMediator; +import com.gempukku.lotro.chat.ChatServer; import com.gempukku.lotro.db.DeckDAO; import com.gempukku.lotro.db.PlayerDAO; import com.gempukku.lotro.db.vo.Deck; @@ -27,6 +30,7 @@ import javax.ws.rs.core.Response; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.parsers.ParserConfigurationException; +import java.util.List; import java.util.Map; @Singleton @@ -35,6 +39,7 @@ public class ServerResource { private static final Logger _logger = Logger.getLogger(ServerResource.class); private LotroServer _lotroServer; + private ChatServer _chatServer; public ServerResource() { _logger.debug("starting resource"); @@ -42,6 +47,10 @@ public class ServerResource { try { _lotroServer = new LotroServer(); _lotroServer.startServer(); + + _chatServer = new ChatServer(); + _chatServer.startServer(); + _chatServer.createChatRoom("default"); } catch (RuntimeException exp) { _logger.error("Error while creating resource", exp); exp.printStackTrace(); @@ -316,6 +325,72 @@ public class ServerResource { return doc; } + @Path("/chat/{room}") + @GET + @Produces(MediaType.APPLICATION_XML) + public Document getMessages( + @PathParam("room") String room, + @QueryParam("participantId") String participantId) throws ParserConfigurationException { + ChatRoomMediator chatRoom = _chatServer.getChatRoom(room); + if (chatRoom == null) + sendError(Response.Status.NOT_FOUND); + + List chatMessages = chatRoom.joinUser(participantId); + + DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance(); + DocumentBuilder documentBuilder = documentBuilderFactory.newDocumentBuilder(); + + Document doc = documentBuilder.newDocument(); + + Element chatElem = doc.createElement("chat"); + chatElem.setAttribute("roomName", room); + doc.appendChild(chatElem); + + for (ChatMessage chatMessage : chatMessages) { + Element message = doc.createElement("message"); + message.setAttribute("from", chatMessage.getFrom()); + message.setAttribute("date", String.valueOf(chatMessage.getWhen().getTime())); + message.appendChild(doc.createTextNode(chatMessage.getMessage())); + chatElem.appendChild(message); + } + + return doc; + } + + @Path("/chat/{room}") + @POST + @Produces(MediaType.APPLICATION_XML) + public Document postMessage( + @PathParam("room") String room, + @FormParam("participantId") String participantId, + @FormParam("message") String message) throws ParserConfigurationException { + ChatRoomMediator chatRoom = _chatServer.getChatRoom(room); + if (chatRoom == null) + sendError(Response.Status.NOT_FOUND); + + chatRoom.sendMessage(participantId, message); + List chatMessages = chatRoom.getPendingMessages(participantId); + + DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance(); + DocumentBuilder documentBuilder = documentBuilderFactory.newDocumentBuilder(); + + Document doc = documentBuilder.newDocument(); + + Element chatElem = doc.createElement("chat"); + chatElem.setAttribute("roomName", room); + doc.appendChild(chatElem); + + for (ChatMessage chatMessage : chatMessages) { + Element messageElem = doc.createElement("message"); + messageElem.setAttribute("from", chatMessage.getFrom()); + messageElem.setAttribute("date", String.valueOf(chatMessage.getWhen().getTime())); + messageElem.appendChild(doc.createTextNode(chatMessage.getMessage())); + chatElem.appendChild(messageElem); + } + + return doc; + } + private class SerializationVisitor implements ParticipantCommunicationVisitor { private Document _doc; private Element _element;