mirror of
https://codeberg.org/Mercury-IM/Smack
synced 2024-11-22 14:22:05 +01:00
Merged the 3.2 Beta branch into trunk.
git-svn-id: http://svn.igniterealtime.org/svn/repos/smack/trunk@12107 b35dd754-fafc-0310-a699-88a17e54d16e
This commit is contained in:
parent
67a5e6b98d
commit
2150d07435
9 changed files with 387 additions and 38 deletions
|
@ -28,7 +28,7 @@
|
|||
<property name="version.major" value="3" />
|
||||
<property name="version.minor" value="2" />
|
||||
<property name="version.revision" value="0" />
|
||||
<property name="version.extra" value="Beta" />
|
||||
<property name="version.extra" value="Beta2" />
|
||||
|
||||
<if>
|
||||
<equals arg1="${version.extra}" arg2=""/>
|
||||
|
|
|
@ -181,6 +181,7 @@ hr {
|
|||
<li>[<a href='http://issues.igniterealtime.org/browse/SMACK-232'>SMACK-232</a>] - Better handling of Roster error</li>
|
||||
<li>[<a href='http://issues.igniterealtime.org/browse/SMACK-243'>SMACK-243</a>] - Packet with wrong date format makes Smack to disconnect</li>
|
||||
<li>[<a href='http://issues.igniterealtime.org/browse/SMACK-264'>SMACK-264</a>] - fix for NPE in SASLMechanism.java</li>
|
||||
<li>[<a href='http://issues.igniterealtime.org/browse/SMACK-269'>SMACK-269</a>] - Smack 3.1.0 creates a new chat for every incoming message</li>
|
||||
<li>[<a href='http://issues.igniterealtime.org/browse/SMACK-271'>SMACK-271</a>] - Deadlock in XMPPConnection while login and parsing stream features</li>
|
||||
<li>[<a href='http://issues.igniterealtime.org/browse/SMACK-275'>SMACK-275</a>] - Patch: Fix for broken SASL DIGEST-MD5 implementation</li>
|
||||
<li>[<a href='http://issues.igniterealtime.org/browse/SMACK-288'>SMACK-288</a>] - The parsing of the result for a LeafNode.getItems() call is incorrect. It creates a DefaultPacketExtension instead of an Item for every other item in the result.</li>
|
||||
|
@ -191,6 +192,7 @@ hr {
|
|||
<li>[<a href='http://issues.igniterealtime.org/browse/SMACK-308'>SMACK-308</a>] - Multiple errors in pubsub GetItemsRequest</li>
|
||||
<li>[<a href='http://issues.igniterealtime.org/browse/SMACK-312'>SMACK-312</a>] - Only fire RosterListener#entriesUpdated for RosterEntries that changed</li>
|
||||
<li>[<a href='http://issues.igniterealtime.org/browse/SMACK-327'>SMACK-327</a>] - getFeatures() method on DiscoverInfo is improperly set to be package protected instead of public</li>
|
||||
<li>[<a href='http://issues.igniterealtime.org/browse/SMACK-328'>SMACK-328</a>] - Number format exception while parsing dates.</li>
|
||||
</ul>
|
||||
|
||||
<h2>3.1.0 -- <span style="font-weight: normal;">November 20, 2008</span></h2>
|
||||
|
|
|
@ -82,6 +82,40 @@ newChat.sendMessage(newMessage);
|
|||
}
|
||||
</pre>
|
||||
</div>
|
||||
|
||||
<p class="subheader">
|
||||
Incoming Chat
|
||||
</p>
|
||||
|
||||
When chats are prompted by another user, the setup is slightly different since
|
||||
you are receiving a chat message first. Instead of explicitly creating a chat to send
|
||||
messages, you need to register to handle newly created Chat instances when the ChatManager
|
||||
creates them.
|
||||
</br>
|
||||
</br>
|
||||
The ChatManager will already find a matching chat (by thread id) and if none exists, then it
|
||||
will create a new one that does match. To get this new chat, you have to register to be
|
||||
notified when it happens. You can register a message listener to receive all future messages as
|
||||
part of this handler.<p>
|
||||
|
||||
<div class="code"><pre><font color="gray"><i>// Assume we've created a Connection name "connection".</i></font>
|
||||
ChatManager chatmanager = connection.getChatManager().addChatListener(
|
||||
new ChatManagerListener() {
|
||||
@Override
|
||||
public void chatCreated(Chat chat, boolean createdLocally)
|
||||
{
|
||||
if (!createdLocally)
|
||||
chat.addMessageListener(new MyNewMessageListener());;
|
||||
}
|
||||
});
|
||||
</pre>
|
||||
</div>
|
||||
In addition to thread based chat messages, there are some clients that
|
||||
do not send a thread id as part of the chat. To handle this scenario,
|
||||
Smack will attempt match the incoming messages to the best fit existing
|
||||
chat, based on the JID. It will attempt to find a chat with the same full
|
||||
JID, failing that, it will try the base JID. If no existing chat to the
|
||||
user can found, then a new one is created.
|
||||
<p>
|
||||
|
||||
<br clear="all"/><br><br>
|
||||
|
|
|
@ -20,6 +20,13 @@
|
|||
|
||||
package org.jivesoftware.smack;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.WeakHashMap;
|
||||
import java.util.concurrent.CopyOnWriteArraySet;
|
||||
|
||||
import org.jivesoftware.smack.filter.AndFilter;
|
||||
import org.jivesoftware.smack.filter.FromContainsFilter;
|
||||
import org.jivesoftware.smack.filter.PacketFilter;
|
||||
|
@ -29,9 +36,6 @@ import org.jivesoftware.smack.packet.Packet;
|
|||
import org.jivesoftware.smack.util.StringUtils;
|
||||
import org.jivesoftware.smack.util.collections.ReferenceMap;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.concurrent.CopyOnWriteArraySet;
|
||||
|
||||
/**
|
||||
* The chat manager keeps track of references to all current chats. It will not hold any references
|
||||
* in memory on its own so it is neccesary to keep a reference to the chat object itself. To be
|
||||
|
@ -65,14 +69,20 @@ public class ChatManager {
|
|||
/**
|
||||
* Maps thread ID to chat.
|
||||
*/
|
||||
private Map<String, Chat> threadChats = new ReferenceMap<String, Chat>(ReferenceMap.HARD,
|
||||
ReferenceMap.WEAK);
|
||||
private Map<String, Chat> threadChats = Collections.synchronizedMap(new ReferenceMap<String, Chat>(ReferenceMap.HARD,
|
||||
ReferenceMap.WEAK));
|
||||
|
||||
/**
|
||||
* Maps jids to chats
|
||||
*/
|
||||
private Map<String, Chat> jidChats = new ReferenceMap<String, Chat>(ReferenceMap.HARD,
|
||||
ReferenceMap.WEAK);
|
||||
private Map<String, Chat> jidChats = Collections.synchronizedMap(new ReferenceMap<String, Chat>(ReferenceMap.HARD,
|
||||
ReferenceMap.WEAK));
|
||||
|
||||
/**
|
||||
* Maps base jids to chats
|
||||
*/
|
||||
private Map<String, Chat> baseJidChats = Collections.synchronizedMap(new ReferenceMap<String, Chat>(ReferenceMap.HARD,
|
||||
ReferenceMap.WEAK));
|
||||
|
||||
private Set<ChatManagerListener> chatManagerListeners
|
||||
= new CopyOnWriteArraySet<ChatManagerListener>();
|
||||
|
@ -161,6 +171,7 @@ public class ChatManager {
|
|||
Chat chat = new Chat(this, userJID, threadID);
|
||||
threadChats.put(threadID, chat);
|
||||
jidChats.put(userJID, chat);
|
||||
baseJidChats.put(StringUtils.parseBareAddress(userJID), chat);
|
||||
|
||||
for(ChatManagerListener listener : chatManagerListeners) {
|
||||
listener.chatCreated(chat, createdLocally);
|
||||
|
@ -179,8 +190,21 @@ public class ChatManager {
|
|||
return createChat(userJID, threadID, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Try to get a matching chat for the given user JID. Try the full
|
||||
* JID map first, the try to match on the base JID if no match is
|
||||
* found.
|
||||
*
|
||||
* @param userJID
|
||||
* @return
|
||||
*/
|
||||
private Chat getUserChat(String userJID) {
|
||||
return jidChats.get(userJID);
|
||||
Chat match = jidChats.get(userJID);
|
||||
|
||||
if (match == null) {
|
||||
match = baseJidChats.get(StringUtils.parseBareAddress(userJID));
|
||||
}
|
||||
return match;
|
||||
}
|
||||
|
||||
public Chat getThreadChat(String thread) {
|
||||
|
|
|
@ -46,8 +46,9 @@ public class QueueDetails implements PacketExtension {
|
|||
*/
|
||||
public static final String NAMESPACE = "http://jabber.org/protocol/workgroup";
|
||||
|
||||
private static final SimpleDateFormat DATE_FORMATTER = new SimpleDateFormat("yyyyMMdd'T'HH:mm:ss");
|
||||
private static final String DATE_FORMAT = "yyyyMMdd'T'HH:mm:ss";
|
||||
|
||||
private SimpleDateFormat dateFormat = new SimpleDateFormat(DATE_FORMAT);
|
||||
/**
|
||||
* The list of users in the queue.
|
||||
*/
|
||||
|
@ -124,7 +125,7 @@ public class QueueDetails implements PacketExtension {
|
|||
|
||||
if (timestamp != null) {
|
||||
buf.append("<join-time>");
|
||||
buf.append(DATE_FORMATTER.format(timestamp));
|
||||
buf.append(dateFormat.format(timestamp));
|
||||
buf.append("</join-time>");
|
||||
}
|
||||
|
||||
|
@ -141,6 +142,8 @@ public class QueueDetails implements PacketExtension {
|
|||
public static class Provider implements PacketExtensionProvider {
|
||||
|
||||
public PacketExtension parseExtension(XmlPullParser parser) throws Exception {
|
||||
|
||||
SimpleDateFormat dateFormat = new SimpleDateFormat(DATE_FORMAT);
|
||||
QueueDetails queueDetails = new QueueDetails();
|
||||
|
||||
int eventType = parser.getEventType();
|
||||
|
@ -171,15 +174,13 @@ public class QueueDetails implements PacketExtension {
|
|||
time = Integer.parseInt(parser.nextText());
|
||||
}
|
||||
else if ("join-time".equals(parser.getName())) {
|
||||
joinTime = DATE_FORMATTER.parse(parser.nextText());
|
||||
joinTime = dateFormat.parse(parser.nextText());
|
||||
}
|
||||
else if( parser.getName().equals( "waitTime" ) ) {
|
||||
Date wait = DATE_FORMATTER.parse( parser.nextText() );
|
||||
Date wait = dateFormat.parse(parser.nextText());
|
||||
System.out.println( wait );
|
||||
}
|
||||
|
||||
|
||||
|
||||
eventType = parser.next();
|
||||
|
||||
if (eventType != XmlPullParser.END_TAG) {
|
||||
|
@ -187,8 +188,6 @@ public class QueueDetails implements PacketExtension {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
queueDetails.addUser(new QueueUser(uid, position, time, joinTime));
|
||||
|
||||
eventType = parser.next();
|
||||
|
|
|
@ -39,7 +39,8 @@ public class QueueOverview implements PacketExtension {
|
|||
*/
|
||||
public static String NAMESPACE = "http://jabber.org/protocol/workgroup";
|
||||
|
||||
private static final SimpleDateFormat DATE_FORMATTER = new SimpleDateFormat("yyyyMMdd'T'HH:mm:ss");
|
||||
private static final String DATE_FORMAT = "yyyyMMdd'T'HH:mm:ss";
|
||||
private SimpleDateFormat dateFormat = new SimpleDateFormat(DATE_FORMAT);
|
||||
|
||||
private int averageWaitTime;
|
||||
private Date oldestEntry;
|
||||
|
@ -101,7 +102,7 @@ public class QueueOverview implements PacketExtension {
|
|||
buf.append("<count>").append(userCount).append("</count>");
|
||||
}
|
||||
if (oldestEntry != null) {
|
||||
buf.append("<oldest>").append(DATE_FORMATTER.format(oldestEntry)).append("</oldest>");
|
||||
buf.append("<oldest>").append(dateFormat.format(oldestEntry)).append("</oldest>");
|
||||
}
|
||||
if (averageWaitTime != -1) {
|
||||
buf.append("<time>").append(averageWaitTime).append("</time>");
|
||||
|
@ -119,6 +120,7 @@ public class QueueOverview implements PacketExtension {
|
|||
public PacketExtension parseExtension (XmlPullParser parser) throws Exception {
|
||||
int eventType = parser.getEventType();
|
||||
QueueOverview queueOverview = new QueueOverview();
|
||||
SimpleDateFormat dateFormat = new SimpleDateFormat(DATE_FORMAT);
|
||||
|
||||
if (eventType != XmlPullParser.START_TAG) {
|
||||
// throw exception
|
||||
|
@ -135,7 +137,7 @@ public class QueueOverview implements PacketExtension {
|
|||
queueOverview.setAverageWaitTime(Integer.parseInt(parser.nextText()));
|
||||
}
|
||||
else if ("oldest".equals(parser.getName())) {
|
||||
queueOverview.setOldestEntry((DATE_FORMATTER.parse(parser.nextText())));
|
||||
queueOverview.setOldestEntry((dateFormat.parse(parser.nextText())));
|
||||
}
|
||||
else if ("status".equals(parser.getName())) {
|
||||
queueOverview.setStatus(WorkgroupQueue.Status.fromString(parser.nextText()));
|
||||
|
|
288
test-unit/org/jivesoftware/smack/ChatConnectionTest.java
Normal file
288
test-unit/org/jivesoftware/smack/ChatConnectionTest.java
Normal file
|
@ -0,0 +1,288 @@
|
|||
/**
|
||||
* $RCSfile$
|
||||
* $Revision: 11640 $
|
||||
* $Date: 2010-02-18 08:38:57 -0500 (Thu, 18 Feb 2010) $
|
||||
*
|
||||
* Copyright 2010 Jive Software.
|
||||
*
|
||||
* All rights reserved. Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.jivesoftware.smack;
|
||||
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.junit.Assert.fail;
|
||||
|
||||
import org.jivesoftware.smack.packet.Message;
|
||||
import org.jivesoftware.smack.packet.Packet;
|
||||
import org.jivesoftware.smack.packet.PacketExtension;
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Ignore;
|
||||
import org.junit.Test;
|
||||
|
||||
/**
|
||||
* Tests that verifies the correct behavior of the {@see Roster} implementation.
|
||||
*
|
||||
* @see Roster
|
||||
* @see <a href="http://xmpp.org/rfcs/rfc3921.html#roster">Roster Management</a>
|
||||
* @author Guenther Niess
|
||||
*/
|
||||
public class ChatConnectionTest {
|
||||
|
||||
private DummyConnection connection;
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
// Uncomment this to enable debug output
|
||||
//Connection.DEBUG_ENABLED = true;
|
||||
|
||||
connection = new DummyConnection();
|
||||
connection.connect();
|
||||
connection.login("me", "secret");
|
||||
}
|
||||
|
||||
@After
|
||||
public void tearDown() throws Exception {
|
||||
if (connection != null)
|
||||
connection.disconnect();
|
||||
}
|
||||
|
||||
/**
|
||||
* Confirm that a new chat is created when a chat message is received but
|
||||
* there is no thread id for a user with only a base jid.
|
||||
*/
|
||||
@Test
|
||||
public void chatCreatedWithIncomingChatNoThreadBaseJid()
|
||||
{
|
||||
TestChatManagerListener listener = new TestChatManagerListener();
|
||||
connection.getChatManager().addChatListener(listener);
|
||||
|
||||
Packet incomingChat = createChatPacket(null, false);
|
||||
processServerMessage(incomingChat);
|
||||
|
||||
Chat newChat = listener.getNewChat();
|
||||
assertNotNull(newChat);
|
||||
}
|
||||
|
||||
/**
|
||||
* Confirm that a new chat is created when a chat message is received but
|
||||
* there is no thread id for a user with a full jid.
|
||||
*/
|
||||
@Test
|
||||
public void chatCreatedWhenIncomingChatNoThreadFullJid()
|
||||
{
|
||||
TestChatManagerListener listener = new TestChatManagerListener();
|
||||
connection.getChatManager().addChatListener(listener);
|
||||
|
||||
Packet incomingChat = createChatPacket(null, true);
|
||||
processServerMessage(incomingChat);
|
||||
|
||||
Chat newChat = listener.getNewChat();
|
||||
assertNotNull(newChat);
|
||||
}
|
||||
|
||||
/**
|
||||
* Confirm that an existing chat created with a base jid is matched to an
|
||||
* incoming chat message that has no thread id and the user is a full jid.
|
||||
*/
|
||||
@Test
|
||||
public void chatFoundWhenNoThreadFullJid()
|
||||
{
|
||||
TestChatManagerListener listener = new TestChatManagerListener();
|
||||
connection.getChatManager().addChatListener(listener);
|
||||
Chat outgoing = connection.getChatManager().createChat("you@testserver", null);
|
||||
|
||||
Packet incomingChat = createChatPacket(null, true);
|
||||
processServerMessage(incomingChat);
|
||||
|
||||
Chat newChat = listener.getNewChat();
|
||||
assertNotNull(newChat);
|
||||
assertTrue(newChat == outgoing);
|
||||
}
|
||||
|
||||
/**
|
||||
* Confirm that an existing chat created with a base jid is matched to an
|
||||
* incoming chat message that has no thread id and the user is a base jid.
|
||||
*/
|
||||
@Test
|
||||
public void chatFoundWhenNoThreadBaseJid()
|
||||
{
|
||||
TestChatManagerListener listener = new TestChatManagerListener();
|
||||
connection.getChatManager().addChatListener(listener);
|
||||
Chat outgoing = connection.getChatManager().createChat("you@testserver", null);
|
||||
|
||||
Packet incomingChat = createChatPacket(null, false);
|
||||
processServerMessage(incomingChat);
|
||||
|
||||
Chat newChat = listener.getNewChat();
|
||||
assertNotNull(newChat);
|
||||
assertTrue(newChat == outgoing);
|
||||
}
|
||||
|
||||
/**
|
||||
* Confirm that an existing chat created with a base jid is matched to an
|
||||
* incoming chat message that has the same id and the user is a full jid.
|
||||
*/
|
||||
@Test
|
||||
public void chatFoundWithSameThreadFullJid()
|
||||
{
|
||||
TestChatManagerListener listener = new TestChatManagerListener();
|
||||
connection.getChatManager().addChatListener(listener);
|
||||
Chat outgoing = connection.getChatManager().createChat("you@testserver", null);
|
||||
|
||||
Packet incomingChat = createChatPacket(outgoing.getThreadID(), true);
|
||||
processServerMessage(incomingChat);
|
||||
|
||||
Chat newChat = listener.getNewChat();
|
||||
assertNotNull(newChat);
|
||||
assertTrue(newChat == outgoing);
|
||||
}
|
||||
|
||||
/**
|
||||
* Confirm that an existing chat created with a base jid is matched to an
|
||||
* incoming chat message that has the same id and the user is a base jid.
|
||||
*/
|
||||
@Test
|
||||
public void chatFoundWithSameThreadBaseJid()
|
||||
{
|
||||
TestChatManagerListener listener = new TestChatManagerListener();
|
||||
connection.getChatManager().addChatListener(listener);
|
||||
Chat outgoing = connection.getChatManager().createChat("you@testserver", null);
|
||||
|
||||
Packet incomingChat = createChatPacket(outgoing.getThreadID(), false);
|
||||
processServerMessage(incomingChat);
|
||||
|
||||
Chat newChat = listener.getNewChat();
|
||||
assertNotNull(newChat);
|
||||
assertTrue(newChat == outgoing);
|
||||
}
|
||||
|
||||
/**
|
||||
* Confirm that an existing chat created with a base jid is not matched to
|
||||
* an incoming chat message that has a different id and the same user as a
|
||||
* base jid.
|
||||
*/
|
||||
@Ignore
|
||||
@Test
|
||||
public void chatNotFoundWithDiffThreadBaseJid()
|
||||
{
|
||||
TestChatManagerListener listener = new TestChatManagerListener();
|
||||
connection.getChatManager().addChatListener(listener);
|
||||
Chat outgoing = connection.getChatManager().createChat("you@testserver", null);
|
||||
|
||||
Packet incomingChat = createChatPacket(outgoing.getThreadID() + "ff", false);
|
||||
processServerMessage(incomingChat);
|
||||
|
||||
Chat newChat = listener.getNewChat();
|
||||
assertNotNull(newChat);
|
||||
assertFalse(newChat == outgoing);
|
||||
}
|
||||
|
||||
/**
|
||||
* Confirm that an existing chat created with a base jid is not matched to
|
||||
* an incoming chat message that has a different id and the same base jid.
|
||||
*/
|
||||
@Ignore
|
||||
@Test
|
||||
public void chatNotFoundWithDiffThreadFullJid()
|
||||
{
|
||||
TestChatManagerListener listener = new TestChatManagerListener();
|
||||
connection.getChatManager().addChatListener(listener);
|
||||
Chat outgoing = connection.getChatManager().createChat("you@testserver", null);
|
||||
|
||||
Packet incomingChat = createChatPacket(outgoing.getThreadID() + "ff", true);
|
||||
processServerMessage(incomingChat);
|
||||
|
||||
Chat newChat = listener.getNewChat();
|
||||
assertNotNull(newChat);
|
||||
assertFalse(newChat == outgoing);
|
||||
}
|
||||
|
||||
private Packet createChatPacket(final String threadId, final boolean isFullJid)
|
||||
{
|
||||
Message chatMsg = new Message("me@testserver", Message.Type.chat);
|
||||
chatMsg.setBody("the body message");
|
||||
chatMsg.setFrom("you@testserver" + (isFullJid ? "/resource" : ""));
|
||||
|
||||
if (threadId != null)
|
||||
chatMsg.addExtension(new PacketExtension()
|
||||
{
|
||||
@Override
|
||||
public String toXML()
|
||||
{
|
||||
return "<thread>" + threadId + "</thread>";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getNamespace()
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getElementName()
|
||||
{
|
||||
return "thread";
|
||||
}
|
||||
});
|
||||
return chatMsg;
|
||||
}
|
||||
|
||||
private void processServerMessage(Packet incomingChat)
|
||||
{
|
||||
TestChatServer chatServer = new TestChatServer(incomingChat);
|
||||
chatServer.start();
|
||||
try
|
||||
{
|
||||
chatServer.join();
|
||||
} catch (InterruptedException e)
|
||||
{
|
||||
fail();
|
||||
}
|
||||
}
|
||||
|
||||
class TestChatManagerListener implements ChatManagerListener
|
||||
{
|
||||
private Chat newChat;
|
||||
|
||||
@Override
|
||||
public void chatCreated(Chat chat, boolean createdLocally)
|
||||
{
|
||||
newChat = chat;
|
||||
}
|
||||
|
||||
public Chat getNewChat()
|
||||
{
|
||||
return newChat;
|
||||
}
|
||||
}
|
||||
|
||||
private class TestChatServer extends Thread
|
||||
{
|
||||
private Packet chatPacket;
|
||||
|
||||
TestChatServer(Packet chatMsg)
|
||||
{
|
||||
chatPacket = chatMsg;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run()
|
||||
{
|
||||
connection.processPacket(chatPacket);
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue