summaryrefslogtreecommitdiffstats
path: root/src/jrummikub
diff options
context:
space:
mode:
Diffstat (limited to 'src/jrummikub')
-rw-r--r--src/jrummikub/control/network/ConnectionControl.java233
-rw-r--r--src/jrummikub/control/network/NetworkControl.java37
-rw-r--r--src/jrummikub/view/impl/GameListPanel.java15
3 files changed, 254 insertions, 31 deletions
diff --git a/src/jrummikub/control/network/ConnectionControl.java b/src/jrummikub/control/network/ConnectionControl.java
index 9777853..171c15d 100644
--- a/src/jrummikub/control/network/ConnectionControl.java
+++ b/src/jrummikub/control/network/ConnectionControl.java
@@ -1,19 +1,36 @@
package jrummikub.control.network;
+import java.util.UUID;
+
import javax.swing.SwingUtilities;
import jrummikub.util.Event;
+import jrummikub.util.Event1;
import jrummikub.util.IEvent;
+import jrummikub.util.IEvent1;
import jrummikub.util.LoginData;
+import jrummikub.view.IGameListPanel.GameData;
import org.jivesoftware.smack.Connection;
+import org.jivesoftware.smack.PacketListener;
import org.jivesoftware.smack.XMPPConnection;
import org.jivesoftware.smack.XMPPException;
+import org.jivesoftware.smack.filter.AndFilter;
+import org.jivesoftware.smack.filter.PacketExtensionFilter;
+import org.jivesoftware.smack.filter.PacketTypeFilter;
+import org.jivesoftware.smack.packet.DefaultPacketExtension;
+import org.jivesoftware.smack.packet.Message;
+import org.jivesoftware.smack.packet.Packet;
+import org.jivesoftware.smack.packet.PacketExtension;
import org.jivesoftware.smack.packet.XMPPError;
import org.jivesoftware.smack.packet.XMPPError.Type;
+import org.jivesoftware.smackx.muc.DiscussionHistory;
import org.jivesoftware.smackx.muc.MultiUserChat;
class ConnectionControl {
+ private final static String ELEMENT_NAME = "rummikub";
+ private final static String NAMESPACE = "http://home.universe-factory.net/rummikub/";
+
private final LoginData loginData;
private volatile Connection connection;
private volatile MultiUserChat muc;
@@ -21,6 +38,11 @@ class ConnectionControl {
private Event connectedEvent = new Event();
private Event connectionFailedEvent = new Event();
+ private Event1<GameData> gameOfferEvent = new Event1<GameData>();
+ private Event1<UUID> gameWithdrawalEvent = new Event1<UUID>();
+
+ private volatile GameData offeredGame;
+
ConnectionControl(LoginData loginData) {
this.loginData = loginData;
}
@@ -44,6 +66,30 @@ class ConnectionControl {
return connectionFailedEvent;
}
+ IEvent1<GameData> getGameOfferEvent() {
+ return gameOfferEvent;
+ }
+
+ IEvent1<UUID> getGameWithdrawalEvent() {
+ return gameWithdrawalEvent;
+ }
+
+ void offerGame(GameData data) {
+ offeredGame = data;
+
+ sendGameOffer();
+ }
+
+ void withdrawGame(UUID uuid) {
+ offeredGame = null;
+
+ new Thread(new SendGameWithdrawRunner(uuid)).start();
+ }
+
+ private void sendGameOffer() {
+ new Thread(new SendGameOfferRunner(offeredGame)).start();
+ }
+
private static void emitLater(final Event event) {
SwingUtilities.invokeLater(new Runnable() {
@Override
@@ -53,40 +99,97 @@ class ConnectionControl {
});
}
+ private Message createMessage(PacketExtension extension) {
+ Message message = muc.createMessage();
+ message.addExtension(extension);
+ return message;
+ }
+
+ private static DefaultPacketExtension createJRummikubExtension() {
+ return new DefaultPacketExtension(ELEMENT_NAME, NAMESPACE);
+ }
+
+ private void processPacket(Packet packet) {
+ DefaultPacketExtension extension = (DefaultPacketExtension) packet
+ .getExtension(ELEMENT_NAME, NAMESPACE);
+
+ String messageType = extension.getValue("messageType");
+
+ if (messageType.equals("game_offer")) {
+ String host = packet.getFrom();
+ host = host.substring(host.indexOf('/') + 1);
+
+ UUID uuid = UUID.fromString(extension.getValue("uuid"));
+ int currentPlayerCount = Integer.parseInt(extension
+ .getValue("currentPlayerCount"));
+ int maxPlayerCount = Integer.parseInt(extension
+ .getValue("maxPlayerCount"));
+
+ GameData gameData = new GameData(uuid, host);
+ gameData.setCurrentPlayerCount(currentPlayerCount);
+ gameData.setMaxPlayerCount(maxPlayerCount);
+ gameOfferEvent.emit(gameData);
+ } else if (messageType.equals("game_withdrawal")) {
+ gameWithdrawalEvent.emit(UUID.fromString(extension.getValue("uuid")));
+ } else if (messageType.equals("game_request")) {
+ if (offeredGame != null) {
+ sendGameOffer();
+ }
+ }
+ }
+
+ private Message createGameOfferMessage(GameData data) {
+ DefaultPacketExtension extension = createJRummikubExtension();
+
+ extension.setValue("messageType", "game_offer");
+ extension.setValue("uuid", data.getGameID().toString());
+ extension.setValue("currentPlayerCount",
+ Integer.toString(data.getCurrentPlayerCount()));
+ extension.setValue("maxPlayerCount",
+ Integer.toString(data.getMaxPlayerCount()));
+
+ return createMessage(extension);
+ }
+
+ private Message createGameWithdrawMessage(UUID uuid) {
+ DefaultPacketExtension extension = createJRummikubExtension();
+
+ extension.setValue("messageType", "game_withdrawal");
+ extension.setValue("uuid", uuid.toString());
+
+ return createMessage(extension);
+ }
+
+ private Message createGameRequestMessage() {
+ DefaultPacketExtension extension = createJRummikubExtension();
+
+ extension.setValue("messageType", "game_request");
+
+ return createMessage(extension);
+ }
+
private class ConnectRunner implements Runnable {
@Override
public void run() {
synchronized (ConnectionControl.this) {
connection = new XMPPConnection(loginData.getServerName());
- try {
- connection.connect();
- connection.login(loginData.getUserName(),
- loginData.getPassword(), "JRummikub");
- muc = new MultiUserChat(connection,
- loginData.getChannelName());
-
- String nickname = loginData.getUserName();
- // Loop until a unused nickname is found
- while (true) {
- try {
- muc.join(nickname);
- break; // Join was successful, break the loop
- } catch (XMPPException e) {
- XMPPError error = e.getXMPPError();
- if (error.getType() == Type.CANCEL
- && error.getCode() == 409) {
- // There was a conflict, try again with another
- // nickname
- nickname += "_";
- continue;
- } else {
- // An unknown error has occurred, cancel connect
- throw e;
+
+ connection.addPacketListener(new PacketListener() {
+ @Override
+ public void processPacket(final Packet packet) {
+ SwingUtilities.invokeLater(new Runnable() {
+ @Override
+ public void run() {
+ ConnectionControl.this.processPacket(packet);
}
- }
+ });
+
}
+ }, new AndFilter(new PacketTypeFilter(Message.class),
+ new PacketExtensionFilter(ELEMENT_NAME, NAMESPACE)));
- emitLater(connectedEvent);
+ try {
+ doConnect();
} catch (XMPPException e) {
connection.disconnect();
connection = null;
@@ -98,6 +201,84 @@ class ConnectionControl {
}
}
}
+
+ private void doConnect() throws XMPPException {
+ connection.connect();
+ connection.login(loginData.getUserName(), loginData.getPassword(),
+ "JRummikub");
+ muc = new MultiUserChat(connection, loginData.getChannelName());
+ DiscussionHistory history = new DiscussionHistory();
+ history.setMaxStanzas(0);
+
+ String nickname = loginData.getUserName();
+ // Loop until a unused nickname is found
+ while (true) {
+ try {
+ muc.join(nickname, null, history, 10000);
+ break; // Join was successful, break the loop
+ } catch (XMPPException e) {
+ XMPPError error = e.getXMPPError();
+ if (error.getType() == Type.CANCEL && error.getCode() == 409) {
+ // There was a conflict, try again with another
+ // nickname
+ nickname += "_";
+ continue;
+ } else {
+ // An unknown error has occurred, cancel connect
+ throw e;
+ }
+ }
+ }
+
+ emitLater(connectedEvent);
+
+ new Thread(new SendGameRequestRunner()).start();
+ }
+ }
+
+ private class SendGameOfferRunner implements Runnable {
+ private GameData data;
+
+ public SendGameOfferRunner(GameData data) {
+ this.data = data;
+ }
+
+ @Override
+ public void run() {
+ synchronized (ConnectionControl.this) {
+ if (connection != null) {
+ connection.sendPacket(createGameOfferMessage(data));
+ }
+ }
+ }
+ }
+
+ private class SendGameWithdrawRunner implements Runnable {
+ private UUID uuid;
+
+ public SendGameWithdrawRunner(UUID uuid) {
+ this.uuid = uuid;
+ }
+
+ @Override
+ public void run() {
+ synchronized (ConnectionControl.this) {
+ if (connection != null) {
+ connection.sendPacket(createGameWithdrawMessage(uuid));
+ }
+ }
+ }
+ }
+
+ private class SendGameRequestRunner implements Runnable {
+ @Override
+ public void run() {
+ synchronized (ConnectionControl.this) {
+ if (connection != null) {
+ connection.sendPacket(createGameRequestMessage());
+ }
+ }
+ }
}
private class DisconnectRunner implements Runnable {
diff --git a/src/jrummikub/control/network/NetworkControl.java b/src/jrummikub/control/network/NetworkControl.java
index ce7714b..013c866 100644
--- a/src/jrummikub/control/network/NetworkControl.java
+++ b/src/jrummikub/control/network/NetworkControl.java
@@ -1,7 +1,9 @@
package jrummikub.control.network;
import java.util.ArrayList;
+import java.util.HashMap;
import java.util.List;
+import java.util.Map;
import java.util.UUID;
import jrummikub.util.Connection;
@@ -20,6 +22,8 @@ public class NetworkControl {
private List<Connection> connections = new ArrayList<Connection>();
private Event stopNetworkEvent = new Event();
+ private Map<UUID, GameData> gameMap = new HashMap<UUID, GameData>();
+
public NetworkControl(final LoginData loginData, final IView view) {
this.view = view;
connectionControl = new ConnectionControl(loginData);
@@ -33,7 +37,8 @@ public class NetworkControl {
GameData testData = new GameData(UUID.randomUUID(), "NeoRaider");
testData.setCurrentPlayerCount(2);
testData.setMaxPlayerCount(4);
- view.getGameListPanel().addGame(testData);
+
+ connectionControl.offerGame(testData);
}
}));
@@ -46,6 +51,36 @@ public class NetworkControl {
}
}));
+ connections.add(connectionControl.getGameOfferEvent().add(
+ new IListener1<IGameListPanel.GameData>() {
+ @Override
+ public void handle(GameData value) {
+ GameData game = gameMap.get(value.getGameID());
+
+ if (game == null) {
+ game = value;
+ gameMap.put(value.getGameID(), value);
+ } else {
+ game.setCurrentPlayerCount(value.getCurrentPlayerCount());
+ game.setMaxPlayerCount(value.getMaxPlayerCount());
+ }
+
+ view.getGameListPanel().addGame(game);
+ }
+ }));
+ connections.add(connectionControl.getGameWithdrawalEvent().add(
+ new IListener1<UUID>() {
+ @Override
+ public void handle(UUID value) {
+ GameData game = gameMap.get(value);
+
+ if (game != null) {
+ view.getGameListPanel().removeGame(game);
+ gameMap.remove(value);
+ }
+ }
+ }));
+
connections.add(view.getGameListPanel().getJoinEvent()
.add(new IListener1<IGameListPanel.GameData>() {
@Override
diff --git a/src/jrummikub/view/impl/GameListPanel.java b/src/jrummikub/view/impl/GameListPanel.java
index eae424a..dae0f27 100644
--- a/src/jrummikub/view/impl/GameListPanel.java
+++ b/src/jrummikub/view/impl/GameListPanel.java
@@ -4,7 +4,6 @@ import java.awt.Color;
import java.awt.Component;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
-import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;
@@ -163,16 +162,24 @@ class GameListPanel extends JPanel implements IGameListPanel {
JLabel hostLabel, playerCountLabel;
GameDataCellRenderer() {
- setLayout(new GridLayout(1, 2));
+ setLayout(new GridBagLayout());
+ GridBagConstraints c = new GridBagConstraints();
+ c.fill = GridBagConstraints.BOTH;
+ c.gridwidth = 1;
+ c.weightx = 1;
+ c.weighty = 1;
+
hostLabel = new JLabel();
hostLabel.setOpaque(true);
hostLabel.setHorizontalAlignment(JLabel.LEFT);
- add(hostLabel);
+ add(hostLabel, c);
playerCountLabel = new JLabel();
playerCountLabel.setOpaque(true);
playerCountLabel.setHorizontalAlignment(JLabel.RIGHT);
- add(playerCountLabel);
+
+ c.gridwidth = GridBagConstraints.REMAINDER;
+ add(playerCountLabel, c);
}
@Override